Skip to content

Commit

Permalink
init token card component w/ calculator and data render
Browse files Browse the repository at this point in the history
  • Loading branch information
salmad3 committed Oct 31, 2024
1 parent 54b13c9 commit 0763642
Show file tree
Hide file tree
Showing 8 changed files with 569 additions and 270 deletions.
149 changes: 149 additions & 0 deletions components/TokenCard/TokenCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import React, { useState } from 'react';
import { Card, Text, Tooltip, TextInput, Accordion, Divider, Group, Button } from '@mantine/core';
import { IconInfoCircle, IconClipboardCheck } from '@tabler/icons-react';
import { TokenCardProps } from './types';
import ibcInfo from './data/ibc_info.json';

const cardStyle = {
backgroundColor: '#2c2f33',
padding: '1.5rem',
borderRadius: '12px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
transition: 'box-shadow 0.3s ease-in-out',
};

const textColor = { color: '#f0f0f0' };
const subTextColor = { color: '#b0b0b0' };

export const TokenCard: React.FC<TokenCardProps> = ({ title, description, tooltip, details }) => {
const [conversionInput, setConversionInput] = useState<number | ''>('');
const [copied, setCopied] = useState<number | null>(null);

const handleConversionInput = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
setConversionInput(value === '' ? '' : parseFloat(value));
};

const handleCopy = async (channelData: object, idx: number) => {
const jsonData = JSON.stringify(channelData, null, 2);
await navigator.clipboard.writeText(jsonData);
setCopied(idx);
setTimeout(() => setCopied(null), 1500);
};

const EVM_CONVERSION_FACTOR = 1e18;
const COSMOS_CONVERSION_FACTOR = { asei: 1e18, nsei: 1e9, usei: 1e6 };

return (
<Card
style={cardStyle}
shadow="sm"
padding="lg"
withBorder
onMouseEnter={(e) => e.currentTarget.style.boxShadow = '0 8px 20px rgba(0, 0, 0, 0.5)'}
onMouseLeave={(e) => e.currentTarget.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.3)'}
>
<Group align="center" mb="xs">
<Text size="lg" style={{ ...textColor, fontWeight: 'bold' }}>{title}</Text>
{tooltip && (
<Tooltip label={tooltip} position="right" withArrow>
<IconInfoCircle size={18} color="#4a90e2" style={{ cursor: 'pointer' }} />
</Tooltip>
)}
</Group>

{description && (
<Text size="sm" style={{ ...subTextColor, marginBottom: '16px' }}>{description}</Text>
)}

<Divider my="sm" variant="dashed" />

{details.map((detail, index) => (
<div key={index} style={{ marginBottom: '12px' }}>
{detail.label.includes("Conversion") ? (
<>
<Text size="sm" style={textColor}>{detail.label}</Text>
<TextInput
placeholder="Enter amount in Sei"
type="number"
value={conversionInput}
onChange={handleConversionInput}
styles={{ input: { backgroundColor: '#4a4d52', color: '#ffffff', marginTop: '8px' } }}
/>
{conversionInput !== '' && detail.label === "EVM Conversion" && (
<Text size="sm" style={{ ...textColor, marginTop: '8px' }}>
{conversionInput} Sei = {conversionInput * EVM_CONVERSION_FACTOR} wei
</Text>
)}
{conversionInput !== '' && detail.label === "Cosmos Conversion" && (
<div style={{ marginTop: '8px' }}>
<Text size="sm" style={textColor}>
{conversionInput} Sei = {conversionInput * COSMOS_CONVERSION_FACTOR.asei} asei
</Text>
<Text size="sm" style={textColor}>
{conversionInput} Sei = {conversionInput * COSMOS_CONVERSION_FACTOR.nsei} nsei
</Text>
<Text size="sm" style={textColor}>
{conversionInput} Sei = {conversionInput * COSMOS_CONVERSION_FACTOR.usei} usei
</Text>
</div>
)}
</>
) : (
<Text size="sm" style={textColor}>
<b>{detail.label}:</b> {detail.content}
</Text>
)}
</div>
))}

{title === "IBC Tokens" && (
<Accordion variant="contained" mt="md" styles={{
item: { backgroundColor: '#3b3e42', color: '#f0f0f0', borderRadius: '8px', marginBottom: '8px' },
control: { color: '#f0f0f0', fontWeight: 500 },
panel: { color: '#e0e0e0', padding: '12px 16px', fontSize: '14px' }
}}>
{Object.entries(ibcInfo).map(([network, channels]) => (
<Accordion.Item key={network} value={network}>
<Accordion.Control>{network.toUpperCase()}</Accordion.Control>
<Accordion.Panel>
{channels.map((channel, idx) => (
<div key={idx} style={{ marginBottom: '12px' }}>
<Group position="apart">
<Text size="sm" style={{ color: '#e0e0e0' }}>
<b>Counterparty Chain:</b> {channel.counterparty_chain_name}
</Text>
<Tooltip label={copied === idx ? "Copied!" : "Copy JSON"} withArrow>
<Button
size="xs"
variant="subtle"
onClick={() => handleCopy(channel, idx)}
style={{ color: '#4a90e2', cursor: 'pointer' }}
>
<IconClipboardCheck size={16} />
</Button>
</Tooltip>
</Group>
<Text size="sm" style={subTextColor}>
<b>Destination Channel:</b> {channel.dst_channel}
</Text>
<Text size="sm" style={subTextColor}>
<b>Source Channel:</b> {channel.src_channel}
</Text>
<Text size="sm" style={subTextColor}>
<b>Port ID:</b> {channel.port_id}
</Text>
<Text size="sm" style={subTextColor}>
<b>Client ID:</b> {channel.client_id}
</Text>
{idx < channels.length - 1 && <hr style={{ borderColor: '#4a4d52', margin: '8px 0' }} />}
</div>
))}
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
)}
</Card>
);
};
92 changes: 92 additions & 0 deletions components/TokenCard/data/ibc_info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"pacific-1": [
{
"counterparty_chain_name": "osmosis-1",
"dst_channel": "channel-782",
"src_channel": "channel-0",
"port_id": "transfer",
"client_id": "07-tendermint-2"
},
{
"counterparty_chain_name": "cosmoshub-4",
"dst_channel": "channel-584",
"src_channel": "channel-1",
"port_id": "transfer",
"client_id": "07-tendermint-3"
},
{
"counterparty_chain_name": "axelar-dojo-1",
"dst_channel": "channel-103",
"src_channel": "channel-2",
"port_id": "transfer",
"client_id": "07-tendermint-8"
},
{
"counterparty_chain_name": "phoenix-1",
"dst_channel": "channel-158",
"src_channel": "channel-3",
"port_id": "transfer",
"client_id": " 07-tendermint-10"
},
{
"counterparty_chain_name": "wormchain",
"dst_channel": "channel-0",
"src_channel": "channel-4",
"port_id": "wasm.sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn",
"client_id": "07-tendermint-12"
},
{
"counterparty_chain_name": "kava_2222-10",
"dst_channel": "channel-132",
"src_channel": "channel-18",
"port_id": "transfer",
"client_id": "07-tendermint-146"
},
{
"counterparty_chain_name": "noble-1",
"dst_channel": "channel-39",
"src_channel": "channel-45",
"port_id": "transfer",
"client_id": "07-tendermint-45"
},
{
"counterparty_chain_name": "injective-1",
"dst_channel": "channel-180",
"src_channel": "channel-54",
"port_id": "transfer",
"client_id": "07-tendermint-64"
}
],
"atlantic-2": [
{
"counterparty_chain_name": "osmo-test-5",
"dst_channel": "channel-1650",
"src_channel": "channel-67",
"port_id": "transfer",
"client_id": "07-tendermint-116"
},
{
"counterparty_chain_name": "axelar-testnet-lisbon-3",
"dst_channel": "channel-257",
"src_channel": "channel-44",
"port_id": "transfer",
"client_id": "07-tendermint-80"
},
{
"counterparty_chain_name": "wormchain-testnet-0",
"dst_channel": "channel-8",
"src_channel": "channel-69",
"port_id": "wasm.sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s",
"client_id": "07-tendermint-117"
}
],
"arctic-1": [
{
"counterparty_chain_name": "axelar-testnet-lisbon-3",
"dst_channel": "channel-467",
"src_channel": "channel-0",
"port_id": "transfer",
"client_id": "07-tendermint-0"
}
]
}
1 change: 1 addition & 0 deletions components/TokenCard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TokenCard } from './TokenCard';
9 changes: 9 additions & 0 deletions components/TokenCard/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface TokenCardProps {
title: string;
description: string;
details: Array<{
label: string;
content: string;
}>;
}

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
"license": "MIT",
"dependencies": {
"@mantine/code-highlight": "^7.12.2",
"@mantine/core": "^7.10.1",
"@mantine/core": "^7.13.4",
"@mantine/hooks": "^7.10.1",
"@rainbow-me/rainbowkit": "^1.3.3",
"@sei-js/registry": "^1.0.1",
"@tabler/icons-react": "^3.21.0",
"lucide-react": "^0.314.0",
"next": "13.0.6",
"next-seo": "^6.5.0",
Expand All @@ -24,6 +25,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"styled-components": "^6.1.11",
"tabler-icons-react": "^1.56.0",
"tailwind-merge": "^2.2.1",
"underscore": "^1.13.6",
"viem": "^1.21.4",
Expand Down
78 changes: 78 additions & 0 deletions pages/learn/dev-token-standards.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { TokenCard } from '../../components/TokenCard';
import { Tabs, Blockquote, Title } from '@mantine/core';

# Token Standards

This section provides an overview of the token standards supported on Sei, each serving unique functions within the blockchain ecosystem.

---

## **Sei Token**

<TokenCard
title="Sei Token"
tooltip="Native token used on Sei for transaction fees and governance."
details={[
{ label: 'Primary Use', content: 'Used to pay transaction fees and participate in governance decisions.' },
{ label: 'EVM Conversion', content: 'Enter an amount to convert Sei to wei.' },
{ label: 'Cosmos Conversion', content: 'Enter an amount to convert Sei to Cosmos units.' },
]}
/>

## **Fungible Tokens**

<TokenCard
title="Fungible Tokens"
tooltip="Interchangeable digital assets supporting ERC20 and CW20 standards."
details={[
{ label: 'TokenFactory', content: 'Natively integrated with Cosmos modules for efficient queries and high performance.' },
{ label: 'ERC20 Standard', content: 'Defines transferable, interchangeable tokens for EVM-based dApps.' },
{ label: 'CW20 Standard', content: 'Cosmos equivalent of ERC20, providing compatibility with Cosmos-based dApps.' },
{ label: 'Cross-Chain Compatibility', content: 'Supports pointer contracts for seamless cross-chain interaction.' },
]}
/>

---

<Blockquote mt="lg">
<Title order={4} mb="sm">Interoperability Note</Title>
Both TokenFactory and CW20/ERC20 tokens support pointer contracts, enabling cross-VM interoperability.
See [Pointer Contracts Documentation](/dev-tutorials/pointer-contracts) for further details.
</Blockquote>

## **Smart Contract Tokens**

<TokenCard
title="Smart Contract Tokens"
tooltip="Tokens managed by smart contracts, compatible with ERC20 and CW20 standards."
details={[
{ label: 'ERC20 Standard', content: 'Fungible token standard for EVM-based chains, supporting token functions.' },
{ label: 'CW20 Standard', content: 'Cosmos counterpart to ERC20, ensuring compatibility with Cosmos dApps.' },
{ label: 'Pointer Contracts', content: 'Enable interaction between CW20 and ERC20 tokens across Cosmos and EVM environments.' },
]}
/>

## **NFTs**

<TokenCard
title="NFTs"
tooltip="Unique digital assets following ERC721 and CW721 standards, with optional royalty features."
details={[
{ label: 'ERC721 Standard', content: 'Defines unique, non-interchangeable tokens for EVM-based chains.' },
{ label: 'CW721 Standard', content: 'Cosmos equivalent of ERC721, compatible with Cosmos-based dApps.' },
{ label: 'Royalty Standards', content: 'Supports ERC2981 and CW2981, allowing creators to set royalties.' },
{ label: 'Cross-Chain Compatibility', content: 'Pointer contracts facilitate cross-standard interactions for NFTs.' },
]}
/>

## **IBC Tokens**

<TokenCard
title="IBC Tokens"
tooltip="Tokens bridged from other Cosmos chains via the IBC protocol."
details={[
{ label: 'IBC Protocol', content: 'Facilitates token transfers between Cosmos chains.' },
{ label: 'Channel Configuration', content: 'Detailed channel information for each network is displayed below.' }
]}
/>

Loading

0 comments on commit 0763642

Please sign in to comment.