From f57c915ea9aaef1f637c19dbd46eba3fb7856477 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Tue, 21 Jan 2025 19:44:48 -0500 Subject: [PATCH] feat: move TransactionDetails and child components to elements + use Circle SDK types --- .../app/components/ChainIcon/ChainIcon.tsx | 36 - .../app/components/ChainLabel/ChainLabel.tsx | 35 - .../components/ChainSelect/ChainSelect.tsx | 18 +- .../SendTransactionForm.stories.ts | 2 +- .../SendTransactionForm.tsx | 5 +- .../TestChainSelect/TestChainSelect.tsx | 18 +- .../TransactionStateText.stories.ts | 21 - .../TransactionStateText.tsx | 57 -- .../TransactionTableRow.stories.ts | 4 +- .../TransactionTableRow.tsx | 4 +- .../WalletDetails/WalletDetails.tsx | 2 +- .../WalletReceive/WalletReceive.stories.ts | 1 - .../WalletReceive/WalletReceive.tsx | 4 +- packages/circle-demo-webapp/app/lib/format.ts | 10 +- .../circle-demo-webapp/app/lib/memcache.ts | 4 +- packages/circle-demo-webapp/app/lib/types.ts | 731 +----------------- .../app/routes/api.createWallet.tsx | 10 +- .../TransactionTableRow.tsx | 6 +- .../routes/transactions.$walletId/route.tsx | 2 +- .../components/EditWalletDialog.tsx | 2 +- .../wallet.$id/components/EditWalletForm.tsx | 2 +- .../wallet.$id/components/FaucetButton.tsx | 2 +- .../components/WalletReceiveDialog.tsx | 2 +- .../components/WalletSendDialog.tsx | 2 +- .../app/routes/wallet.$id/route.tsx | 8 +- .../app/routes/wallets.$id/route.tsx | 6 +- .../components/ChainIcon/ChainIcon.stories.ts | 32 +- .../src/components/ChainIcon/ChainIcon.tsx | 32 + .../src}/components/ChainIcon/index.ts | 0 .../ChainLabel/ChainLabel.stories.ts | 32 +- .../src/components/ChainLabel/ChainLabel.tsx | 37 + .../src}/components/ChainLabel/index.ts | 0 .../FormErrorText/FormErrorText.tsx | 15 + .../src/components/FormErrorText/index.ts | 1 + .../components/TokenItem/TokenItem.stories.ts | 19 +- .../src}/components/TokenItem/TokenItem.tsx | 5 +- .../src}/components/TokenItem/index.ts | 0 .../TransactionDetails.stories.ts | 18 +- .../TransactionDetails/TransactionDetails.tsx | 30 +- .../components/TransactionDetails/index.ts | 0 .../TransactionStateText.stories.ts | 63 ++ .../TransactionStateText.tsx | 45 ++ .../components/TransactionStatusText/index.ts | 0 .../src/components/ui/badge.tsx | 33 + packages/circle-react-elements/src/index.tsx | 5 + .../circle-react-elements/src/lib/format.ts | 15 + .../circle-react-elements/src/lib/types.ts | 6 + 47 files changed, 407 insertions(+), 975 deletions(-) delete mode 100644 packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.tsx delete mode 100644 packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.tsx delete mode 100644 packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.stories.ts delete mode 100644 packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.tsx rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/ChainIcon/ChainIcon.stories.ts (66%) create mode 100644 packages/circle-react-elements/src/components/ChainIcon/ChainIcon.tsx rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/ChainIcon/index.ts (100%) rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/ChainLabel/ChainLabel.stories.ts (66%) create mode 100644 packages/circle-react-elements/src/components/ChainLabel/ChainLabel.tsx rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/ChainLabel/index.ts (100%) create mode 100644 packages/circle-react-elements/src/components/FormErrorText/FormErrorText.tsx create mode 100644 packages/circle-react-elements/src/components/FormErrorText/index.ts rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TokenItem/TokenItem.stories.ts (67%) rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TokenItem/TokenItem.tsx (79%) rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TokenItem/index.ts (100%) rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TransactionDetails/TransactionDetails.stories.ts (78%) rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TransactionDetails/TransactionDetails.tsx (63%) rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TransactionDetails/index.ts (100%) create mode 100644 packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.stories.ts create mode 100644 packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.tsx rename packages/{circle-demo-webapp/app => circle-react-elements/src}/components/TransactionStatusText/index.ts (100%) create mode 100644 packages/circle-react-elements/src/components/ui/badge.tsx create mode 100644 packages/circle-react-elements/src/lib/format.ts diff --git a/packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.tsx b/packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.tsx deleted file mode 100644 index 55ac33e..0000000 --- a/packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { NetworkIcon } from '@web3icons/react'; - -import { Blockchain } from '~/lib/constants'; - -export interface ChainIconProps { - /** The blockchain network */ - blockchain: string; -} - -const BLOCKCHAIN_TO_ICON_MAP: Record = { - [Blockchain.ArbSepolia]: 'arbitrum', - [Blockchain.Arb]: 'arbitrum', - [Blockchain.AvaxFuji]: 'avalanche', - [Blockchain.Avax]: 'avalanche', - [Blockchain.EthSepolia]: 'ethereum', - [Blockchain.Eth]: 'ethereum', - [Blockchain.EvmTestnet]: '', - [Blockchain.Evm]: '', - [Blockchain.MaticAmoy]: 'polygon', - [Blockchain.Matic]: 'polygon', - [Blockchain.NearTestnet]: 'near-protocol', - [Blockchain.Near]: 'near-protocol', - [Blockchain.SolDevnet]: 'solana', - [Blockchain.Sol]: 'solana', -}; - -/** A label with an icon and text to identify a blockchain network */ -export function ChainIcon({ blockchain }: ChainIconProps) { - return ( - - ); -} diff --git a/packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.tsx b/packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.tsx deleted file mode 100644 index abe0626..0000000 --- a/packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ChainIcon } from '~/components/ChainIcon'; -import { Blockchain } from '~/lib/constants'; - -export interface ChainSelectProps { - /** The blockchain network */ - blockchain: string; -} - -const BLOCKCHAIN_LABELS: Record = { - [Blockchain.ArbSepolia]: 'Arbitrum Sepolia', - [Blockchain.Arb]: 'Arbitrum', - [Blockchain.AvaxFuji]: 'Avalanche Fuji', - [Blockchain.Avax]: 'Avalanche', - [Blockchain.EthSepolia]: 'Ethereum Sepolia', - [Blockchain.Eth]: 'Ethereum', - [Blockchain.EvmTestnet]: '', - [Blockchain.Evm]: '', - [Blockchain.MaticAmoy]: 'Polygon Amoy', - [Blockchain.Matic]: 'Polygon', - [Blockchain.NearTestnet]: 'NEAR Testnet', - [Blockchain.Near]: 'NEAR', - [Blockchain.SolDevnet]: 'Solana Devnet', - [Blockchain.Sol]: 'Solana', -}; - -/** A label with an icon and text to identify a blockchain network */ -export function ChainLabel({ blockchain }: ChainSelectProps) { - return ( -

- - - {BLOCKCHAIN_LABELS[blockchain]} -

- ); -} diff --git a/packages/circle-demo-webapp/app/components/ChainSelect/ChainSelect.tsx b/packages/circle-demo-webapp/app/components/ChainSelect/ChainSelect.tsx index 782036a..f36051c 100644 --- a/packages/circle-demo-webapp/app/components/ChainSelect/ChainSelect.tsx +++ b/packages/circle-demo-webapp/app/components/ChainSelect/ChainSelect.tsx @@ -1,6 +1,7 @@ +import { Blockchain } from '@circle-fin/developer-controlled-wallets'; +import { ChainIcon } from '@circle-libs/circle-react-elements'; import { SelectProps } from '@radix-ui/react-select'; -import { ChainIcon } from '~/components/ChainIcon'; import { Select, SelectContent, @@ -8,15 +9,14 @@ import { SelectTrigger, SelectValue, } from '~/components/ui/select'; -import { Blockchain } from '~/lib/constants'; const BLOCKCHAIN_LABELS: Record = { - [Blockchain.Arb]: 'Arbitrum', - [Blockchain.Avax]: 'Avalanche', - [Blockchain.Eth]: 'Ethereum', - [Blockchain.Matic]: 'Polygon', - [Blockchain.Near]: 'NEAR', - [Blockchain.Sol]: 'Solana', + ARB: 'Arbitrum', + AVAX: 'Avalanche', + ETH: 'Ethereum', + MATIC: 'Polygon', + NEAR: 'NEAR', + SOL: 'Solana', }; export type ChainSelectProps = Omit & { placeholder?: string }; @@ -33,7 +33,7 @@ export function ChainSelect({ ...props }: ChainSelectProps) { {Object.keys(BLOCKCHAIN_LABELS).map((blockchain) => (
- + {BLOCKCHAIN_LABELS[blockchain]}
diff --git a/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.stories.ts b/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.stories.ts index 4db7da7..abc26f4 100644 --- a/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.stories.ts +++ b/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.stories.ts @@ -1,8 +1,8 @@ import type { CreateTransactionInput } from '@circle-fin/developer-controlled-wallets'; +import { Transaction } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import type { Meta, StoryObj } from '@storybook/react'; import { Blockchain } from '~/lib/constants'; -import { Transaction } from '~/lib/types'; import { SendTransactionForm } from './SendTransactionForm'; diff --git a/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.tsx b/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.tsx index d57236e..752eb9b 100644 --- a/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.tsx +++ b/packages/circle-demo-webapp/app/components/SendTransactionForm/SendTransactionForm.tsx @@ -2,6 +2,10 @@ import { Balance, CreateTransactionInput, } from '@circle-fin/developer-controlled-wallets'; +import { + Transaction, + Wallet, +} from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { TokenSelect } from '@circle-libs/circle-react-elements'; import { zodResolver } from '@hookform/resolvers/zod'; import { LoaderCircle } from 'lucide-react'; @@ -16,7 +20,6 @@ import { Input } from '~/components/ui/input'; import { Textarea } from '~/components/ui/textarea'; import { FeeLevel } from '~/lib/constants'; import { CircleError, ErrorResponse } from '~/lib/responses'; -import { Transaction, Wallet } from '~/lib/types'; import { isAddress, isNumber } from '~/lib/utils'; export interface ScreenAddressResult { diff --git a/packages/circle-demo-webapp/app/components/TestChainSelect/TestChainSelect.tsx b/packages/circle-demo-webapp/app/components/TestChainSelect/TestChainSelect.tsx index 9af8ce2..7fae45b 100644 --- a/packages/circle-demo-webapp/app/components/TestChainSelect/TestChainSelect.tsx +++ b/packages/circle-demo-webapp/app/components/TestChainSelect/TestChainSelect.tsx @@ -1,6 +1,7 @@ +import { Blockchain } from '@circle-fin/developer-controlled-wallets'; +import { ChainIcon } from '@circle-libs/circle-react-elements'; import { SelectProps } from '@radix-ui/react-select'; -import { ChainIcon } from '~/components/ChainIcon'; import { Select, SelectContent, @@ -8,15 +9,14 @@ import { SelectTrigger, SelectValue, } from '~/components/ui/select'; -import { Blockchain } from '~/lib/constants'; const BLOCKCHAIN_LABELS: Record = { - [Blockchain.ArbSepolia]: 'Arbitrum Sepolia', - [Blockchain.AvaxFuji]: 'Avalanche Fuji', - [Blockchain.EthSepolia]: 'Ethereum Sepolia', - [Blockchain.MaticAmoy]: 'Polygon Amoy', - [Blockchain.NearTestnet]: 'NEAR Testnet', - [Blockchain.SolDevnet]: 'Solana Devnet', + 'ARB-SEPOLIA': 'Arbitrum Sepolia', + 'AVAX-FUJI': 'Avalanche Fuji', + 'ETH-SEPOLIA': 'Ethereum Sepolia', + 'MATIC-AMOY': 'Polygon Amoy', + 'NEAR-TESTNET': 'NEAR Testnet', + 'SOL-DEVNET': 'Solana Devnet', }; export type TestChainSelectProps = Omit; @@ -32,7 +32,7 @@ export function TestChainSelect({ ...props }: TestChainSelectProps) { {Object.keys(BLOCKCHAIN_LABELS).map((blockchain) => (
- + {BLOCKCHAIN_LABELS[blockchain]}
diff --git a/packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.stories.ts b/packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.stories.ts deleted file mode 100644 index 5556900..0000000 --- a/packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.stories.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react'; - -import { TransactionState } from '~/lib/constants'; - -import { TransactionStateText } from './TransactionStateText'; - -const meta = { - title: 'TransactionStateText', - component: TransactionStateText, - tags: ['autodocs'], -} satisfies Meta; - -export default meta; - -type Story = StoryObj; - -export const Default: Story = { - args: { - state: TransactionState.Complete, - }, -}; diff --git a/packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.tsx b/packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.tsx deleted file mode 100644 index 3c05f01..0000000 --- a/packages/circle-demo-webapp/app/components/TransactionStatusText/TransactionStateText.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useEffect } from 'react'; - -import { Badge } from '~/components/ui/badge'; -import { TransactionState } from '~/lib/constants'; - -export interface TransactionStateTextProps { - state: (typeof TransactionState)[keyof typeof TransactionState]; - getTransaction?: () => Promise; -} - -const greenStates = [TransactionState.Complete, TransactionState.Confirmed]; -const yellowStates = [ - TransactionState.Sent, - TransactionState.Initiated, - TransactionState.Queued, - TransactionState.PendingRiskScreening, -]; - -const capitalize = (str: string) => - str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); - -export function TransactionStateText({ - state, - getTransaction, -}: TransactionStateTextProps) { - useEffect(() => { - if (!greenStates.includes(state) && typeof getTransaction === 'function') { - const interval = setInterval(() => { - getTransaction().catch(console.error); - }, 1000); - return () => clearInterval(interval); - } - }, [state, getTransaction]); - - return greenStates.includes(state) ? ( - - {capitalize(state)} ✓ - - ) : yellowStates.includes(state) ? ( - - {capitalize(state)} - - ) : ( - - {capitalize(state)} ✘ - - ); -} diff --git a/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.stories.ts b/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.stories.ts index 8b1e976..29e24af 100644 --- a/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.stories.ts +++ b/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.stories.ts @@ -28,14 +28,14 @@ export const Default: Story = { state: 'COMPLETE', transactionScreeningEvaluation: { screeningDate: '2024-12-10T13:52:57Z' }, amounts: ['30'], - nfts: null, + nfts: undefined, txHash: '0x1aac3dd232d02797fb6c340cbda7d118fce0561aa7f78049f32ba167b0eaf225', blockHash: '0x3bd9054deae68d0d5087da188f119eab2160c12c8a255668e6190c60ffed9ff6', blockHeight: 15439404, networkFee: '0.005164650002582325', firstConfirmDate: '2024-12-10T13:52:57Z', operation: 'TRANSFER', - abiParameters: null, + abiParameters: undefined, createDate: '2024-12-10T13:52:57Z', updateDate: '2024-12-10T13:54:43Z', }, diff --git a/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.tsx b/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.tsx index 2dfb7e1..8c6aa0c 100644 --- a/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.tsx +++ b/packages/circle-demo-webapp/app/components/TransactionTableRow/TransactionTableRow.tsx @@ -1,5 +1,5 @@ -import { TokenItem } from '~/components/TokenItem'; -import { TransactionStateText } from '~/components/TransactionStatusText'; +import { TokenItem, TransactionStateText } from '@circle-libs/circle-react-elements'; + import { TransactionType } from '~/lib/constants'; import { formatDate, shortenAddress } from '~/lib/format'; import { TransactionWithToken } from '~/lib/types'; diff --git a/packages/circle-demo-webapp/app/components/WalletDetails/WalletDetails.tsx b/packages/circle-demo-webapp/app/components/WalletDetails/WalletDetails.tsx index 31a2e53..fc5d414 100644 --- a/packages/circle-demo-webapp/app/components/WalletDetails/WalletDetails.tsx +++ b/packages/circle-demo-webapp/app/components/WalletDetails/WalletDetails.tsx @@ -1,9 +1,9 @@ import { AccountType } from '@circle-fin/developer-controlled-wallets'; +import { ChainLabel } from '@circle-libs/circle-react-elements'; import makeBlockie from 'ethereum-blockies-base64'; import { Copy } from 'lucide-react'; import { useMemo } from 'react'; -import { ChainLabel } from '~/components/ChainLabel'; import { Badge } from '~/components/ui/badge'; import { Button } from '~/components/ui/button'; import { shortenAddress } from '~/lib/format'; diff --git a/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.stories.ts b/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.stories.ts index 08a7b3b..9183e0d 100644 --- a/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.stories.ts +++ b/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.stories.ts @@ -25,7 +25,6 @@ export const Default: Story = { name: 'My Wallet', address: '0xc9758de68b17837dadf51616ac77d634bca848d5', blockchain: Blockchain.MaticAmoy, - accountType: 'EOA', updateDate: '2024-12-09T14:38:51Z', createDate: '2024-12-09T14:38:51Z', }, diff --git a/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.tsx b/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.tsx index 17bac19..a0942cb 100644 --- a/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.tsx +++ b/packages/circle-demo-webapp/app/components/WalletReceive/WalletReceive.tsx @@ -1,10 +1,10 @@ +import { Wallet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; +import { ChainLabel } from '@circle-libs/circle-react-elements'; import { Copy } from 'lucide-react'; import { QRCodeCanvas } from 'qrcode.react'; import { useState } from 'react'; -import { ChainLabel } from '~/components/ChainLabel'; import { Button } from '~/components/ui/button'; -import { Wallet } from '~/lib/types'; export interface WalletReceiveProps { /** The wallet */ diff --git a/packages/circle-demo-webapp/app/lib/format.ts b/packages/circle-demo-webapp/app/lib/format.ts index 045c7e9..0461d48 100644 --- a/packages/circle-demo-webapp/app/lib/format.ts +++ b/packages/circle-demo-webapp/app/lib/format.ts @@ -1,8 +1,14 @@ -export function shortenAddress(address: string): string { +export function shortenAddress(address: string | undefined): string { + if (typeof address !== 'string') { + return ''; + } return `${address.slice(0, 6)}...${address.slice(-4)}`; } -export function shortenHash(hash: string): string { +export function shortenHash(hash: string | undefined): string { + if (typeof hash !== 'string') { + return ''; + } return `${hash.slice(0, 10)}...${hash.slice(-10)}`; } diff --git a/packages/circle-demo-webapp/app/lib/memcache.ts b/packages/circle-demo-webapp/app/lib/memcache.ts index 8bc79ba..1e78e4a 100644 --- a/packages/circle-demo-webapp/app/lib/memcache.ts +++ b/packages/circle-demo-webapp/app/lib/memcache.ts @@ -1,5 +1,7 @@ +import { Token } from '@circle-fin/developer-controlled-wallets'; + import { sdk } from '~/lib/sdk'; -import { Token, WalletSet } from '~/lib/types'; +import { WalletSet } from '~/lib/types'; class MemCache { private map: Map; diff --git a/packages/circle-demo-webapp/app/lib/types.ts b/packages/circle-demo-webapp/app/lib/types.ts index 0053b19..2cd0b6f 100644 --- a/packages/circle-demo-webapp/app/lib/types.ts +++ b/packages/circle-demo-webapp/app/lib/types.ts @@ -1,734 +1,33 @@ /** * Request types */ -import { - FeeLevel, - TransactionState, - WalletState, +import type { + Blockchain, + Token, + TransactionType, } from '@circle-fin/developer-controlled-wallets'; +import type { + Transaction, + Wallet as SdkWallet, + WalletSet as SdkWalletSet, +} from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; -// this is possible now with latest version of the Circle SDK -// import { WalletSet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; - -import { Blockchain, TestnetBlockchain, TransactionType } from '~/lib/constants'; +import { TestnetBlockchain } from '~/lib/constants'; export type TypeBlockchain = (typeof Blockchain)[keyof typeof Blockchain]; export type TypeTestnetBlockchain = (typeof TestnetBlockchain)[keyof typeof TestnetBlockchain]; export type TypeTransactionType = (typeof TransactionType)[keyof typeof TransactionType]; -export enum TransferState { - CANCELLED = 'CANCELLED', - CONFIRMED = 'CONFIRMED', - COMPLETE = 'COMPLETE', - DENIED = 'DENIED', - FAILED = 'FAILED', - INITIATED = 'INITIATED', - PENDING_RISK_SCREENING = 'PENDING_RISK_SCREENING', - QUEUED = 'QUEUED', - SENT = 'SENT', -} - -/** - * A developer controlled wallet set - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-wallet-set - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/update-wallet-set - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/get-wallet-sets - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/get-wallet-set - */ -export interface WalletSet { - /** System-generated unique identifier of the resource. */ - id: string; - /** Date and time the resource was created, in ISO-8601 UTC format. */ - createDate: string; - /** Date and time the resource was last updated, in ISO-8601 UTC format. */ - updateDate: string; - custodyType: string; - /** Name or description associated with the wallet or walletSet. */ - name?: string; -} - -/** - * NFTs for a wallet - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/list-wallet-nfts - */ -export interface WalletNft { - /** - * Amount of NFTs on a wallet. For non-fungible token standards, like ERC721, NonFungible, NonFungibleEdition, - * ProgrammableNonFungible, ProgrammableNonFungibleEdition, amount will always be “1”; - * for semi-fungible token standards like ERC1155, amount will correspond to the number of tokens; - * for FungibleAsset, amount can be greater than "1". - */ - amount: string; - /** The metadata of the NFT. */ - metadata: string; - /** The NFT token ID. */ - nftTokenId: string; - token: { - /** System-generated unique identifier of the resource. */ - id: string; - /** Blockchain name of the specified token. */ - name: string; - standard: string; - /** The blockchain network that the resource is to be created on or is currently on. */ - blockchain: TypeBlockchain; - /** Number of decimal places shown in the token amount. */ - decimals: number; - /** Defines if the token is a native token of the specified blockchain. If TRUE, the token is a native token. */ - isNative: boolean; - /** Blockchain symbol of the specified token. */ - symbol: string; - /** - * Blockchain generated unique identifier, associated with wallet (account), - * smart contract or other blockchain objects. - */ - tokenAddress: string; - /** Date and time the resource was last updated, in ISO-8601 UTC format. */ - updateDate: string; - /** Date and time the resource was created, in ISO-8601 UTC format. */ - createDate: string; - }; - /** Date and time the resource was last updated, in ISO-8601 UTC format. */ - updateDate: string; -} - -/** - * A wallet - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-wallet - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/get-wallet - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/get-wallets - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/update-wallet - */ -export interface Wallet { - /** System-generated unique identifier of the resource. */ - id: string; - /** - * Blockchain generated unique identifier, associated with wallet (account), - * smart contract or other blockchain objects. - */ - address: string; - /** - * The blockchain network that the resource is to be created on or is currently on. - */ - blockchain: TypeBlockchain; - /** - * Date and time the resource was created, in ISO-8601 UTC format. - */ - createDate: string; // You can also use Date if you prefer to parse it - /** - * Date and time the resource was last updated, in ISO-8601 UTC format. - */ - updateDate: string; // Same here - /** - * Describes who controls the digital assets in a wallet: either the end-user or the developer. - */ - custodyType: string; // Use specific value if it’s always this, or allow other potential types - /** - * Name or description associated with the wallet or walletSet. - */ - name: string; - /** - * Reference or description used to identify the object. - */ - refId: string; - /** - * This enum describes the current state of the wallet. - */ - state: WalletState; // If the state can only have specific values, you can use string literals like 'LIVE' | 'INACTIVE' - /** - * Unique system generated identifier for the user. - */ - userId?: string; - /** - * System-generated unique identifier of the resource. - */ - walletSetId: string; - /** - * For NEAR blockchains only, the originally assigned public key of a wallet at the time of its creation. - */ - initialPublicKey?: string; - /** - * An account can be a Smart Contract Account (SCA) or an Externally Owned Account (EOA). - * To learn more, see the account types guide (https://developers.circle.com/w3s/programmable-wallets-account-types). - * If an account type is not specified during the creation of a wallet, - * it defaults to EOA (Externally Owned Account). - * Note that Solana doesn't support Smart Contract Account (SCA). - */ - accountType: string; // Use string literal if there are multiple fixed types -} - -/** - * A signed transaction - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/sign-transaction - */ -export interface SignedTransaction { - /** The signature of the signed transaction. */ - signature: string; - /** - * Signed transaction. - * Base64 encoded for NEAR and Solana chains. Hex encoded for EVM chains. - */ - signedTransaction: string; - /** - * Blockchain-generated identifier of the transaction. - * Present if the wallet blockchain is not Solana. - */ - txHash: string; -} - -/** - * A signed delegate action - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/sign-delegate-action - */ -export type SignedTransactionDelegate = SignedTransaction & { - /** Signed delegate action is a base64 encoded string for NEAR. */ - signedDelegateAction?: string; -}; - -/** - * A transaction - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/get-transaction - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/list-transactions - */ -export interface Transaction { - /** System-generated unique identifier of the resource. */ - id: string; - /** - * The contract ABI function signature or callData field is required for interacting with the smart contract. - * The ABI function signature cannot be used simultaneously with callData. - */ - abiFunctionSignature?: string; - /** - * The contract ABI function signature parameters for executing the contract interaction. - * Supported parameter types include string, integer, boolean, and array. - * These parameters should be used exclusively with the abiFunctionSignature and cannot be used with callData. - */ - abiParameters?: (string | number)[] | null; - /** - * Transfer amounts in decimal number format, at least one element is required for transfer. - * For ERC721 token transfer, the amounts field is required to be ["1"] (array with "1" as the only element). - */ - amounts?: string[]; - /** Transaction amount in USD decimal format. */ - amountInUSD?: string; - /** Identifier for the block that includes the transaction. */ - blockHash?: string; - /** Block height of the transaction, representing the number of blockchain confirmations. */ - blockHeight?: number; - /** The blockchain network that the resource is to be created on or is currently on. */ - blockchain: TypeBlockchain; - /** The blockchain address of the contract to be executed. */ - contractAddress?: string; - /** Date and time the resource was created, in ISO-8601 UTC format. */ - createDate: string; - /** Describes who controls the digital assets in a wallet: either the end-user or the developer. */ - custodyType: 'DEVELOPER' | 'ENDUSER'; - /** - * Blockchain generated unique identifier, associated with wallet (account), - * smart contract or other blockchain objects. - */ - destinationAddress: string; - /** Description of the error. Only present for transactions in FAILED state. */ - errorReason?: string; - /** Additional detail associated with the corresponding transaction's error reason */ - errorDetails?: string; - /** - * The estimated fee for the transaction. - * For Get Transactions API, this will only be returned if transaction type is used in - * the request query parameters - */ - estimatedFee?: { - /** - * The maximum units of gas to use for the transaction. - * Using gasLimit together with feeLevel, the provided gasLimit is required to be - * greater or equal to feeLevel estimation and will override the estimation's gasLimit. - */ - gasLimit?: string; - /** - * For blockchains without EIP-1559 support, - * the maximum price of gas, in gwei, to use per each unit of gas (see gasLimit). - * Requires gasLimit. Cannot be used with feeLevel, priorityFee, or maxFee. - */ - gasPrice?: string; - /** - * For blockchains with EIP-1559 support, - * the maximum price per unit of gas (see gasLimit), in gwei. - * Requires priorityFee, and gasLimit to be present. - * Cannot be used with feeLevel or gasPrice. - */ - maxFee?: string; - /** - * For blockchains with EIP-1559 support, - * the “tip”, in gwei, to add to the base fee as an incentive for validators. - * Please note that the maxFee and gasLimit parameters are required alongside the priorityFee. - * The feeLevel and gasPrice parameters cannot be used with the priorityFee. - */ - priorityFee?: string; - /** - * For blockchains with EIP-1559 support, - * the estimated base fee represents the minimum fee required for a transaction to be included - * in a block on the blockchain. - * It is measured in gwei and compensates for the computational resources validators consume to - * process the transaction. The base fee is supplemented by a separate "tip" called the priority fee, - * which acts as an extra incentive for validators to prioritize the transaction. - * The priority fee is added to the base fee to calculate the final transaction fee. - */ - baseFee?: string; - /** - * The estimated network fee is the maximum amount of cryptocurrency (such as ETH, ARB, or SOL) - * that you will pay for your transaction. This fee depends on the parameters you set, including Gas Limit, - * Priority Fee, and Max Fee. It compensates for the computational resources that validators consume to - * process the transaction. It is measured in native token such as ETH, SOL. - * Each blockchain might use different formula for network fee. - * Refer to each specific blockchain's documentation to understand how networkFee is calculated. - */ - networkFee?: string; - }; - /** - * Defines the blockchain fee level which will be paid for the transaction - * e.g. LOW, MEDIUM, HIGH. For Get Transactions API, - * this will only be returned if transaction type is used in the request query parameters - */ - feeLevel?: FeeLevel; - /** Date the transaction was first confirmed in a block. ISO-8601 UTC date/time. */ - firstConfirmDate?: string; - /** Gas fee, in native token, paid to the network for the transaction. */ - networkFee?: string; - /** Gas fee, in USD, paid to the network for the transaction. */ - networkFeeInUSD?: string; - /** List of Nfts, in JSON string format, associated with the transaction. */ - nfts?: string[] | null; // TODO: SDK or API returns null when no NFTs so the type is incorrect - - /** Operation type of the transaction. */ - operation: 'TRANSFER' | 'CONTRACT_EXECUTION' | 'CONTRACT_DEPLOYMENT'; - /** Optional reference or description used to identify the transaction. */ - refId?: string; - /** - * Blockchain generated unique identifier, associated with wallet (account), - * smart contract or other blockchain objects. - */ - sourceAddress: string; - /** Current state of the transaction. */ - state: TransactionState; - /** System-generated unique identifier of the resource. */ - tokenId?: string; - transactionType: TypeTransactionType; - /** Blockchain generated identifier of the transaction. */ - txHash?: string; - /** Date and time the resource was last updated, in ISO-8601 UTC format. */ - updateDate: string; - /** Unique system generated identifier for the user. */ - userId?: string; - /** System-generated unique identifier of the resource. */ - walletId: string; - transactionScreeningEvaluation?: { - /** Name of the matched rule found in screening. */ - ruleName?: string; - /** Actions to take for the decision. */ - actions?: string[]; - /** Date and time the resource was created, in ISO-8601 UTC format. */ - screeningDate?: string; - /** - * Risk signals found include source, value, and type of the signal. - * It also contains risk score and risk category. - */ - reasons?: { - /** Source of the risk signal. */ - source: string; - /** - * Value of the source. For example, if source is “ADDRESS”. - * The source value would be an blockchain address. - */ - sourceValue: string; - /** Risk score of the signal. */ - riskScore: string; - /** List of risk categories for the signal. */ - riskCategories: string[]; - /** Type of the signal. */ - type: string; - }[]; - }; -} - export interface TransactionWithToken extends Transaction { token?: Token; } -/** - * A transfer transaction - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-developer-transaction-transfer - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-developer-transaction-contract-execution - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-developer-transaction-cancel - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-developer-transaction-accelerate - */ -export interface Transfer { - /** System-generated unique identifier of the resource. */ - id: string; - /** Current state of the transaction. */ - state?: TransferState; -} - -/** - * An estimate of a fee - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/estimate-contract-deploy - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/estimate-contract-template-deploy - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-transaction-estimate-fee - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/create-transfer-estimate-fee - */ -export interface EstimateFee { - high: { - /** - * The maximum units of gas to use for the transaction. - * Using gasLimit together with feeLevel, the provided gasLimit is required to be - * greater or equal to feeLevel estimation and will override the estimation's gasLimit. - */ - gasLimit: string; - /** - * For blockchains without EIP-1559 support, - * the maximum price of gas, in gwei, to use per each unit of gas (see gasLimit). - * Requires gasLimit. Cannot be used with feeLevel, priorityFee, or maxFee. - */ - gasPrice?: string; - /** - * For blockchains with EIP-1559 support, - * the maximum price per unit of gas (see gasLimit), in gwei. - * Requires priorityFee, and gasLimit to be present. - * Cannot be used with feeLevel or gasPrice. - */ - maxFee: string; - /** - * For blockchains with EIP-1559 support, - * the “tip”, in gwei, to add to the base fee as an incentive for validators. - * Please note that the maxFee and gasLimit parameters are required alongside the priorityFee. - * The feeLevel and gasPrice parameters cannot be used with the priorityFee. - */ - priorityFee: string; - /** - * For blockchains with EIP-1559 support, - * the estimated base fee represents the minimum fee required for a transaction to be included - * in a block on the blockchain. - * It is measured in gwei and compensates for the computational resources validators consume to - * process the transaction. The base fee is supplemented by a separate "tip" called the priority fee, - * which acts as an extra incentive for validators to prioritize the transaction. - * The priority fee is added to the base fee to calculate the final transaction fee. - */ - baseFee: string; - /** - * The estimated network fee is the maximum amount of cryptocurrency (such as ETH, ARB, or SOL) - * that you will pay for your transaction. This fee depends on the parameters you set, including Gas Limit, - * Priority Fee, and Max Fee. It compensates for the computational resources that validators consume to - * process the transaction. It is measured in native token such as ETH, SOL. - * Each blockchain might use different formula for network fee. - * Refer to each specific blockchain's documentation to understand how networkFee is calculated. - */ - networkFee: string; - }; - low: { - /** - * The maximum units of gas to use for the transaction. - * Using gasLimit together with feeLevel, the provided gasLimit is required to be - * greater or equal to feeLevel estimation and will override the estimation's gasLimit. - */ - gasLimit: string; - /** - * For blockchains without EIP-1559 support, - * the maximum price of gas, in gwei, to use per each unit of gas (see gasLimit). - * Requires gasLimit. Cannot be used with feeLevel, priorityFee, or maxFee. - */ - gasPrice?: string; - /** - * For blockchains with EIP-1559 support, - * the maximum price per unit of gas (see gasLimit), in gwei. - * Requires priorityFee, and gasLimit to be present. - * Cannot be used with feeLevel or gasPrice. - */ - maxFee: string; - /** - * For blockchains with EIP-1559 support, - * the “tip”, in gwei, to add to the base fee as an incentive for validators. - * Please note that the maxFee and gasLimit parameters are required alongside the priorityFee. - * The feeLevel and gasPrice parameters cannot be used with the priorityFee. - */ - priorityFee: string; - /** - * For blockchains with EIP-1559 support, - * the estimated base fee represents the minimum fee required for a transaction to be included - * in a block on the blockchain. - * It is measured in gwei and compensates for the computational resources validators consume to - * process the transaction. The base fee is supplemented by a separate "tip" called the priority fee, - * which acts as an extra incentive for validators to prioritize the transaction. - * The priority fee is added to the base fee to calculate the final transaction fee. - */ - baseFee: string; - /** - * The estimated network fee is the maximum amount of cryptocurrency (such as ETH, ARB, or SOL) - * that you will pay for your transaction. This fee depends on the parameters you set, including Gas Limit, - * Priority Fee, and Max Fee. It compensates for the computational resources that validators consume to - * process the transaction. It is measured in native token such as ETH, SOL. - * Each blockchain might use different formula for network fee. - * Refer to each specific blockchain's documentation to understand how networkFee is calculated. - */ - networkFee: string; - }; - medium: { - /** - * The maximum units of gas to use for the transaction. - * Using gasLimit together with feeLevel, the provided gasLimit is required to be - * greater or equal to feeLevel estimation and will override the estimation's gasLimit. - */ - gasLimit: string; - /** - * For blockchains without EIP-1559 support, - * the maximum price of gas, in gwei, to use per each unit of gas (see gasLimit). - * Requires gasLimit. Cannot be used with feeLevel, priorityFee, or maxFee. - */ - gasPrice?: string; - /** - * For blockchains with EIP-1559 support, - * the maximum price per unit of gas (see gasLimit), in gwei. - * Requires priorityFee, and gasLimit to be present. - * Cannot be used with feeLevel or gasPrice. - */ - maxFee: string; - /** - * For blockchains with EIP-1559 support, - * the “tip”, in gwei, to add to the base fee as an incentive for validators. - * Please note that the maxFee and gasLimit parameters are required alongside the priorityFee. - * The feeLevel and gasPrice parameters cannot be used with the priorityFee. - */ - priorityFee: string; - /** - * For blockchains with EIP-1559 support, - * the estimated base fee represents the minimum fee required for a transaction to be included - * in a block on the blockchain. - * It is measured in gwei and compensates for the computational resources validators consume to - * process the transaction. The base fee is supplemented by a separate "tip" called the priority fee, - * which acts as an extra incentive for validators to prioritize the transaction. - * The priority fee is added to the base fee to calculate the final transaction fee. - */ - baseFee: string; - /** - * The estimated network fee is the maximum amount of cryptocurrency (such as ETH, ARB, or SOL) - * that you will pay for your transaction. This fee depends on the parameters you set, including Gas Limit, - * Priority Fee, and Max Fee. It compensates for the computational resources that validators consume to - * process the transaction. It is measured in native token such as ETH, SOL. - * Each blockchain might use different formula for network fee. - * Refer to each specific blockchain's documentation to understand how networkFee is calculated. - */ - networkFee: string; - }; - callGasLimit: string; - verificationGasLimit: string; - preVerificationGas: string; -} - -/** - * A token - * https://developers.circle.com/api-reference/w3s/developer-controlled-wallets/get-token-id - */ -export interface Token { - /** System-generated unique identifier of the resource. */ - id: string; - /** Blockchain name of the specified token. */ - name: string; - standard: string; - /** The blockchain network that the resource is to be created on or is currently on. */ - blockchain: TypeBlockchain; - /** Number of decimal places shown in the token amount. */ - decimals: number; - /** - * Defines if the token is a native token of the specified blockchain. - * If TRUE, the token is a native token. - */ - isNative: boolean; - /** Blockchain symbol of the specified token. */ - symbol: string; - /** - * Blockchain generated unique identifier, associated with wallet (account), - * smart contract or other blockchain objects. - */ - tokenAddress: string; - /** Date and time the resource was last updated, in ISO-8601 UTC format. */ - updateDate: string; - /** Date and time the resource was created, in ISO-8601 UTC format. */ - createDate: string; -} - -/** - * A response from a request to deploy a contract from a template - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/deploy-contract-template - */ -export interface DeployContractFromTemplate { - /** Unique identifiers of the created smart contracts. */ - contractIds: string[]; - /** Unique identifier of the pending deployment transaction. transaction. */ - transactionId: string; -} - -/** - * A deployed contract - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/deploy-contract - */ -export interface DeployContract { - /** Unique identifier of the created smart contract. */ - contractId: string; - /** Unique identifier of the deployment transaction. */ - transactionId: string; -} - -/** - * The result of querying a contract - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/query-contract - */ -export interface QueryContract { - /** Output for the ABI interaction. */ - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - outputValues: any[]; - /** OutputData is output in hex format. */ - outputData: string; -} - -/** - * Information about a smart contract - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/list-contracts - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/get-contract - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/update-contract - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/import-contract - */ -export interface Contract { - /** System-generated unique identifier of the resource. */ - id: string; - /** The id of the Programmable Wallet that deployed this contract. */ - deployerWalletID: string; - /** The id of the deployment transaction for this contract. */ - deploymentTransactionId: string; - /** Blockchain generated identifier of the transaction. */ - txHash: string; - /** The contract's ABI in a JSON stringified format. */ - abiJson: string; - /** - * The archive state of the contract. - * If true, the contract will not be visible in your dashboard. - */ - archived: boolean; - /** - * The blockchain network that the resource is to be created on or is currently on. - * Required along with sourceAddress if you don't provide walletId. - * The blockchain and walletId fields are mutually exclusive. - */ - blockchain: TypeBlockchain; - /** Bytecode of the contract being deployed. */ - bytecode: string; - /** The on-chain address of this contract. */ - contractAddress: string; - /** The input type for the contract. */ - contractInputType: string; - /** The address that created this contract, if deployed. */ - deployerAddress: string; - deployerUserID?: string; - deploymentErrorReason?: string; - deploymentErrorDetails?: string; - /** The name for a contract. Must be alphanumeric [a-zA-Z0-9]. */ - name: string; - /** The description for a contract. */ - description: string; - /** The status of the contract. */ - status: string; - /** The verification status of the contract. */ - verificationStatus: string; - /** The ipfs metadata link of the contract. */ - metadataLink: string; - /** Date and time the resource was last updated, in ISO-8601 UTC format. */ - updateDate: string; - /** Date and time the resource was created, in ISO-8601 UTC format. */ - createDate: string; - /** Contract source code */ - sourceCode?: { - /** Name of the file. */ - fileName: string; - /** - * Content of the file. - * If the contract's source code was flattened before verification, - * this may be the entire source code. - */ - fileContent: string; - }[]; - /** Functions supported by this contract. Parsed from abi_json. */ - functions?: { - name: string; - stateMutability: string; - type: string; - inputs: { - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - components?: any[]; - indexed: boolean; - name: string; - type: string; - flattenedType?: string; - }[]; - outputs?: { - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - components?: any[]; - indexed: boolean; - name: string; - type: string; - flattenedType?: string; - }[]; - }[]; - /** Events this contract can emit. Parsed from abi_json. */ - events?: { - name: string; - type: string; - anonymous: boolean; - inputs: { - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - components?: any[]; - indexed: boolean; - name: string; - type: string; - flattenedType?: string; - }[]; - }[]; - /** Object of the implementation contract. */ - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - implementationContract?: any; -} - -/** - * An event monitor - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/get-event-monitors - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/create-event-monitor - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/update-event-monitor - */ -export interface EventMonitor { - id: string; - blockchain: TypeBlockchain; - /** The on-chain address of this contract. */ - contractAddress: string; - eventSignature: string; - eventSignatureHash: string; - isEnabled: boolean; - createDate: string; - updateDate: string; +export interface WalletSet extends SdkWalletSet { + name?: string; + custodyType?: string; } -/** - * An event log - * https://developers.circle.com/api-reference/w3s/smart-contract-platform/list-event-logs - */ -export interface EventLog { - blockHash: string; - blockHeight: number; - blockchain: TypeBlockchain; - /** The on-chain address of this contract. */ - contractAddress: string; - data: string; - eventSignature: string; - eventSignatureHash: string; - firstConfirmDate: string; - id: string; - logIndex: string; - topics: string[]; - txHash: string; - userOpHash: string; +export interface Wallet extends SdkWallet { + accountType?: string; } diff --git a/packages/circle-demo-webapp/app/routes/api.createWallet.tsx b/packages/circle-demo-webapp/app/routes/api.createWallet.tsx index 15a3dbd..475c3ee 100644 --- a/packages/circle-demo-webapp/app/routes/api.createWallet.tsx +++ b/packages/circle-demo-webapp/app/routes/api.createWallet.tsx @@ -1,4 +1,4 @@ -import { AccountType } from '@circle-fin/developer-controlled-wallets'; +import { AccountType, Blockchain } from '@circle-fin/developer-controlled-wallets'; import { ActionFunctionArgs } from '@remix-run/node'; import { sdk } from '~/lib/sdk'; @@ -7,10 +7,9 @@ import { errorResponse, successResponse, } from '~/lib/server.responses'; -import { TypeBlockchain } from '~/lib/types'; import { isValidString } from '~/lib/utils'; -const CHAIN_TO_ACCOUNT_TYPE: Record = { +const CHAIN_TO_ACCOUNT_TYPE: Record = { ARB: 'SCA', AVAX: 'EOA', ETH: 'SCA', @@ -25,6 +24,7 @@ const CHAIN_TO_ACCOUNT_TYPE: Record = { 'MATIC-AMOY': 'SCA', 'NEAR-TESTNET': 'EOA', 'SOL-DEVNET': 'EOA', + 'UNI-SEPOLIA': 'EOA', }; interface RequestBody { @@ -54,8 +54,8 @@ export async function action({ request }: ActionFunctionArgs) { await sdk.createWallets({ walletSetId, count: 1, - accountType: CHAIN_TO_ACCOUNT_TYPE[blockchain as TypeBlockchain], - blockchains: [blockchain as TypeBlockchain], + accountType: CHAIN_TO_ACCOUNT_TYPE[blockchain as Blockchain], + blockchains: [blockchain as Blockchain], metadata: [ { name, diff --git a/packages/circle-demo-webapp/app/routes/transactions.$walletId/components/TransactionTableRow/TransactionTableRow.tsx b/packages/circle-demo-webapp/app/routes/transactions.$walletId/components/TransactionTableRow/TransactionTableRow.tsx index 42330e8..575b147 100644 --- a/packages/circle-demo-webapp/app/routes/transactions.$walletId/components/TransactionTableRow/TransactionTableRow.tsx +++ b/packages/circle-demo-webapp/app/routes/transactions.$walletId/components/TransactionTableRow/TransactionTableRow.tsx @@ -1,9 +1,8 @@ +import { TokenItem, TransactionStateText } from '@circle-libs/circle-react-elements'; import { Link } from '@remix-run/react'; import { ArrowUpRight } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; -import { TokenItem } from '~/components/TokenItem'; -import { TransactionStateText } from '~/components/TransactionStatusText'; import { useGetTransaction } from '~/hooks/useGetTransaction'; import { TransactionType } from '~/lib/constants'; import { formatDate, shortenAddress } from '~/lib/format'; @@ -44,7 +43,7 @@ export function TransactionTableRow({ {shortenAddress(tx.destinationAddress)} - + {tx?.token ? : '-'} @@ -65,6 +64,7 @@ export function TransactionTableRow({ className="text-primary" onClick={() => { if (typeof onClickDetails === 'function') { + getTransaction().catch(console.error); onClickDetails(tx); } }} diff --git a/packages/circle-demo-webapp/app/routes/transactions.$walletId/route.tsx b/packages/circle-demo-webapp/app/routes/transactions.$walletId/route.tsx index 303bf2e..f214707 100644 --- a/packages/circle-demo-webapp/app/routes/transactions.$walletId/route.tsx +++ b/packages/circle-demo-webapp/app/routes/transactions.$walletId/route.tsx @@ -1,9 +1,9 @@ import { ListTransactionsInput } from '@circle-fin/developer-controlled-wallets'; +import { TransactionDetails } from '@circle-libs/circle-react-elements'; import { useParams } from '@remix-run/react'; import { LoaderCircle } from 'lucide-react'; import { useEffect, useMemo, useState } from 'react'; -import { TransactionDetails } from '~/components/TransactionDetails'; import { Card } from '~/components/ui/card'; import { Dialog, DialogContent, DialogTitle } from '~/components/ui/dialog'; import { InputWithIcon } from '~/components/ui/inputWithIcon'; diff --git a/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletDialog.tsx b/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletDialog.tsx index 74add9d..51a9399 100644 --- a/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletDialog.tsx +++ b/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletDialog.tsx @@ -1,3 +1,4 @@ +import { Wallet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { FilePenLine } from 'lucide-react'; import { useState } from 'react'; @@ -10,7 +11,6 @@ import { DialogTitle, DialogTrigger, } from '~/components/ui/dialog'; -import { Wallet } from '~/lib/types'; import { EditWalletForm } from './EditWalletForm'; diff --git a/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletForm.tsx b/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletForm.tsx index 353825f..8a24717 100644 --- a/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletForm.tsx +++ b/packages/circle-demo-webapp/app/routes/wallet.$id/components/EditWalletForm.tsx @@ -1,3 +1,4 @@ +import { Wallet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { LoaderCircle } from 'lucide-react'; import { FormEvent } from 'react'; @@ -5,7 +6,6 @@ import { Button } from '~/components/ui/button'; import { Input } from '~/components/ui/input'; import { Textarea } from '~/components/ui/textarea'; import { useUpdateWallet } from '~/hooks/useUpdateWallet'; -import { Wallet } from '~/lib/types'; interface EditWalletFormProps { wallet: Wallet; diff --git a/packages/circle-demo-webapp/app/routes/wallet.$id/components/FaucetButton.tsx b/packages/circle-demo-webapp/app/routes/wallet.$id/components/FaucetButton.tsx index 007c68f..0c1c8b4 100644 --- a/packages/circle-demo-webapp/app/routes/wallet.$id/components/FaucetButton.tsx +++ b/packages/circle-demo-webapp/app/routes/wallet.$id/components/FaucetButton.tsx @@ -1,9 +1,9 @@ +import { Wallet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { LoaderCircle, Plus } from 'lucide-react'; import { FormEvent } from 'react'; import { Button } from '~/components/ui/button'; import { useFaucet } from '~/hooks/useFaucet'; -import { Wallet } from '~/lib/types'; interface FaucetButtonProps { wallet: Wallet; diff --git a/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletReceiveDialog.tsx b/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletReceiveDialog.tsx index 7dee6e5..9595aa0 100644 --- a/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletReceiveDialog.tsx +++ b/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletReceiveDialog.tsx @@ -1,10 +1,10 @@ +import { Wallet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { ArrowDown } from 'lucide-react'; import { useState } from 'react'; import { Button } from '~/components/ui/button'; import { Dialog, DialogContent, DialogTrigger } from '~/components/ui/dialog'; import { WalletReceive } from '~/components/WalletReceive'; -import { Wallet } from '~/lib/types'; interface WalletReceiveDialogProps { wallet: Wallet; diff --git a/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletSendDialog.tsx b/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletSendDialog.tsx index b58e39c..3c5c106 100644 --- a/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletSendDialog.tsx +++ b/packages/circle-demo-webapp/app/routes/wallet.$id/components/WalletSendDialog.tsx @@ -1,4 +1,5 @@ import { Balance } from '@circle-fin/developer-controlled-wallets'; +import { Wallet } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { ArrowUp } from 'lucide-react'; import { useState } from 'react'; @@ -16,7 +17,6 @@ import { DialogTrigger, } from '~/components/ui/dialog'; import { WalletDetails } from '~/components/WalletDetails'; -import { Wallet } from '~/lib/types'; export interface WalletSendDialogProps { wallet: Wallet; diff --git a/packages/circle-demo-webapp/app/routes/wallet.$id/route.tsx b/packages/circle-demo-webapp/app/routes/wallet.$id/route.tsx index 6bf0dbb..02be217 100644 --- a/packages/circle-demo-webapp/app/routes/wallet.$id/route.tsx +++ b/packages/circle-demo-webapp/app/routes/wallet.$id/route.tsx @@ -1,4 +1,5 @@ import { CreateTransactionInput } from '@circle-fin/developer-controlled-wallets'; +import { Transaction } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; import { WalletBalance } from '@circle-libs/circle-react-elements'; import { LoaderFunctionArgs } from '@remix-run/node'; import { Link, useLoaderData, useParams, useRevalidator } from '@remix-run/react'; @@ -15,7 +16,6 @@ import { useToast } from '~/hooks/useToast'; import { useTransactions } from '~/hooks/useTransactions'; import { formatDate } from '~/lib/format'; import { sdk } from '~/lib/sdk'; -import { Transaction, Wallet } from '~/lib/types'; import { callFetch } from '~/lib/utils'; import { EditWalletDialog } from './components/EditWalletDialog'; @@ -39,7 +39,7 @@ export async function loader({ params }: LoaderFunctionArgs) { return { balances: balancesRes?.data?.tokenBalances ?? [], - wallet: walletRes?.data?.wallet as Wallet, + wallet: walletRes?.data?.wallet, }; } @@ -66,6 +66,10 @@ export default function WalletBalancePage() { throw new Error('Wallet ID is required'); } + if (!wallet) { + throw new Error('Wallet not found'); + } + return (
diff --git a/packages/circle-demo-webapp/app/routes/wallets.$id/route.tsx b/packages/circle-demo-webapp/app/routes/wallets.$id/route.tsx index 4958c9d..04933bb 100644 --- a/packages/circle-demo-webapp/app/routes/wallets.$id/route.tsx +++ b/packages/circle-demo-webapp/app/routes/wallets.$id/route.tsx @@ -26,8 +26,10 @@ export async function loader({ params }: { params: { id: string } }) { ]); return { - wallets: walletsResp?.data?.wallets as Wallet[], - walletSet: walletSetResp?.data?.walletSet as WalletSet, + // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain + wallets: walletsResp?.data?.wallets! as Wallet[], + // eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain + walletSet: walletSetResp?.data?.walletSet! as WalletSet, }; } diff --git a/packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.stories.ts b/packages/circle-react-elements/src/components/ChainIcon/ChainIcon.stories.ts similarity index 66% rename from packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.stories.ts rename to packages/circle-react-elements/src/components/ChainIcon/ChainIcon.stories.ts index dae160c..8fd747f 100644 --- a/packages/circle-demo-webapp/app/components/ChainIcon/ChainIcon.stories.ts +++ b/packages/circle-react-elements/src/components/ChainIcon/ChainIcon.stories.ts @@ -1,7 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { Blockchain } from '~/lib/constants'; - import { ChainIcon } from './ChainIcon'; const meta = { @@ -16,72 +14,78 @@ type Story = StoryObj; export const EthSepolia: Story = { args: { - blockchain: Blockchain.EthSepolia, + blockchain: 'ETH-SEPOLIA', }, }; export const EthMainnet: Story = { args: { - blockchain: Blockchain.Eth, + blockchain: 'ETH', }, }; export const ArbSepolia: Story = { args: { - blockchain: Blockchain.ArbSepolia, + blockchain: 'ARB-SEPOLIA', }, }; export const ArbMainnet: Story = { args: { - blockchain: Blockchain.Arb, + blockchain: 'ARB', }, }; export const AvaxFuji: Story = { args: { - blockchain: Blockchain.AvaxFuji, + blockchain: 'AVAX-FUJI', }, }; export const AvaxMainnet: Story = { args: { - blockchain: Blockchain.Avax, + blockchain: 'AVAX', }, }; export const PolygonAmoy: Story = { args: { - blockchain: Blockchain.MaticAmoy, + blockchain: 'MATIC-AMOY', }, }; export const PolygonMainnet: Story = { args: { - blockchain: Blockchain.Matic, + blockchain: 'MATIC', }, }; export const SolanaDevnet: Story = { args: { - blockchain: Blockchain.SolDevnet, + blockchain: 'SOL-DEVNET', }, }; export const SolanaMainnet: Story = { args: { - blockchain: Blockchain.Sol, + blockchain: 'SOL', }, }; export const NearTestnet: Story = { args: { - blockchain: Blockchain.NearTestnet, + blockchain: 'NEAR-TESTNET', }, }; export const NearMainnet: Story = { args: { - blockchain: Blockchain.Near, + blockchain: 'NEAR-TESTNET', + }, +}; + +export const UniSepolia: Story = { + args: { + blockchain: 'UNI-SEPOLIA', }, }; diff --git a/packages/circle-react-elements/src/components/ChainIcon/ChainIcon.tsx b/packages/circle-react-elements/src/components/ChainIcon/ChainIcon.tsx new file mode 100644 index 0000000..7f8378c --- /dev/null +++ b/packages/circle-react-elements/src/components/ChainIcon/ChainIcon.tsx @@ -0,0 +1,32 @@ +import type { Blockchain } from '@circle-fin/developer-controlled-wallets'; +import { NetworkIcon } from '@web3icons/react'; + +export interface ChainIconProps { + /** The blockchain network */ + blockchain: Blockchain; +} + +const BlockchainToIconMap: Record = { + 'ARB-SEPOLIA': 'arbitrum', + ARB: 'arbitrum', + 'AVAX-FUJI': 'avalanche', + AVAX: 'avalanche', + 'ETH-SEPOLIA': 'ethereum', + ETH: 'ethereum', + 'EVM-TESTNET': '', + EVM: '', + 'MATIC-AMOY': 'polygon', + MATIC: 'polygon', + 'NEAR-TESTNET': 'near-protocol', + NEAR: 'near-protocol', + 'SOL-DEVNET': 'solana', + SOL: 'solana', + 'UNI-SEPOLIA': 'uni', +}; + +/** A label with an icon and text to identify a blockchain network */ +export function ChainIcon({ blockchain }: ChainIconProps) { + return ( + + ); +} diff --git a/packages/circle-demo-webapp/app/components/ChainIcon/index.ts b/packages/circle-react-elements/src/components/ChainIcon/index.ts similarity index 100% rename from packages/circle-demo-webapp/app/components/ChainIcon/index.ts rename to packages/circle-react-elements/src/components/ChainIcon/index.ts diff --git a/packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.stories.ts b/packages/circle-react-elements/src/components/ChainLabel/ChainLabel.stories.ts similarity index 66% rename from packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.stories.ts rename to packages/circle-react-elements/src/components/ChainLabel/ChainLabel.stories.ts index 48b52b8..5533282 100644 --- a/packages/circle-demo-webapp/app/components/ChainLabel/ChainLabel.stories.ts +++ b/packages/circle-react-elements/src/components/ChainLabel/ChainLabel.stories.ts @@ -1,7 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { Blockchain } from '~/lib/constants'; - import { ChainLabel } from './ChainLabel'; const meta = { @@ -16,72 +14,78 @@ type Story = StoryObj; export const EthSepolia: Story = { args: { - blockchain: Blockchain.EthSepolia, + blockchain: 'ETH-SEPOLIA', }, }; export const EthMainnet: Story = { args: { - blockchain: Blockchain.Eth, + blockchain: 'ETH', }, }; export const ArbSepolia: Story = { args: { - blockchain: Blockchain.ArbSepolia, + blockchain: 'ARB-SEPOLIA', }, }; export const ArbMainnet: Story = { args: { - blockchain: Blockchain.Arb, + blockchain: 'ARB', }, }; export const AvaxFuji: Story = { args: { - blockchain: Blockchain.AvaxFuji, + blockchain: 'AVAX-FUJI', }, }; export const AvaxMainnet: Story = { args: { - blockchain: Blockchain.Avax, + blockchain: 'AVAX', }, }; export const PolygonAmoy: Story = { args: { - blockchain: Blockchain.MaticAmoy, + blockchain: 'MATIC-AMOY', }, }; export const PolygonMainnet: Story = { args: { - blockchain: Blockchain.Matic, + blockchain: 'MATIC', }, }; export const SolanaDevnet: Story = { args: { - blockchain: Blockchain.SolDevnet, + blockchain: 'SOL-DEVNET', }, }; export const SolanaMainnet: Story = { args: { - blockchain: Blockchain.Sol, + blockchain: 'SOL', }, }; export const NearTestnet: Story = { args: { - blockchain: Blockchain.NearTestnet, + blockchain: 'NEAR-TESTNET', }, }; export const NearMainnet: Story = { args: { - blockchain: Blockchain.Near, + blockchain: 'NEAR-TESTNET', + }, +}; + +export const UniSepolia: Story = { + args: { + blockchain: 'UNI-SEPOLIA', }, }; diff --git a/packages/circle-react-elements/src/components/ChainLabel/ChainLabel.tsx b/packages/circle-react-elements/src/components/ChainLabel/ChainLabel.tsx new file mode 100644 index 0000000..5cfefab --- /dev/null +++ b/packages/circle-react-elements/src/components/ChainLabel/ChainLabel.tsx @@ -0,0 +1,37 @@ +import type { Blockchain } from '@circle-fin/developer-controlled-wallets'; + +import { ChainIcon } from '../ChainIcon'; + +export interface ChainSelectProps { + /** The blockchain network */ + blockchain: Blockchain; +} + +const BlockchainLabelMap: Record = { + 'ARB-SEPOLIA': 'Arbitrum Sepolia', + ARB: 'Arbitrum', + 'AVAX-FUJI': 'Avalanche Fuji', + AVAX: 'Avalanche', + 'ETH-SEPOLIA': 'Ethereum Sepolia', + ETH: 'Ethereum', + 'EVM-TESTNET': '', + EVM: '', + 'MATIC-AMOY': 'Polygon Amoy', + MATIC: 'Polygon', + 'NEAR-TESTNET': 'NEAR Testnet', + NEAR: 'NEAR', + 'SOL-DEVNET': 'Solana Devnet', + SOL: 'Solana', + 'UNI-SEPOLIA': 'Uni Sepolia', +}; + +/** A label with an icon and text to identify a blockchain network */ +export function ChainLabel({ blockchain }: ChainSelectProps) { + return ( +

+ + + {BlockchainLabelMap[blockchain]} +

+ ); +} diff --git a/packages/circle-demo-webapp/app/components/ChainLabel/index.ts b/packages/circle-react-elements/src/components/ChainLabel/index.ts similarity index 100% rename from packages/circle-demo-webapp/app/components/ChainLabel/index.ts rename to packages/circle-react-elements/src/components/ChainLabel/index.ts diff --git a/packages/circle-react-elements/src/components/FormErrorText/FormErrorText.tsx b/packages/circle-react-elements/src/components/FormErrorText/FormErrorText.tsx new file mode 100644 index 0000000..9e19e28 --- /dev/null +++ b/packages/circle-react-elements/src/components/FormErrorText/FormErrorText.tsx @@ -0,0 +1,15 @@ +interface FormErrorTextProps { + /** The message to display **/ + message?: string; +} + +/** Display form error text **/ +export function FormErrorText({ message }: FormErrorTextProps) { + return ( + message && ( +

+ {message} +

+ ) + ); +} diff --git a/packages/circle-react-elements/src/components/FormErrorText/index.ts b/packages/circle-react-elements/src/components/FormErrorText/index.ts new file mode 100644 index 0000000..ddf265f --- /dev/null +++ b/packages/circle-react-elements/src/components/FormErrorText/index.ts @@ -0,0 +1 @@ +export * from './FormErrorText'; diff --git a/packages/circle-demo-webapp/app/components/TokenItem/TokenItem.stories.ts b/packages/circle-react-elements/src/components/TokenItem/TokenItem.stories.ts similarity index 67% rename from packages/circle-demo-webapp/app/components/TokenItem/TokenItem.stories.ts rename to packages/circle-react-elements/src/components/TokenItem/TokenItem.stories.ts index 3351cfb..0da7726 100644 --- a/packages/circle-demo-webapp/app/components/TokenItem/TokenItem.stories.ts +++ b/packages/circle-react-elements/src/components/TokenItem/TokenItem.stories.ts @@ -1,7 +1,5 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { Token } from '~/lib/types'; - import { TokenItem } from './TokenItem'; const meta = { @@ -17,6 +15,21 @@ export default meta; type Story = StoryObj; +export const Sol: Story = { + args: { + token: { + blockchain: 'SOL', + createDate: '2024-08-12T21:58:31Z', + decimals: 18, + id: '9ad91eb5-e152-5d81-b60e-151d5fd2b3d3', + isNative: true, + name: 'Solana', + symbol: 'SOL', + updateDate: '2024-08-12T21:58:31Z', + }, + }, +}; + export const Default: Story = { args: { token: { @@ -28,6 +41,6 @@ export const Default: Story = { name: 'Arbitrum Ethereum-Sepolia', symbol: 'ETH-SEPOLIA', updateDate: '2024-08-12T21:58:31Z', - } as Token, + }, }, }; diff --git a/packages/circle-demo-webapp/app/components/TokenItem/TokenItem.tsx b/packages/circle-react-elements/src/components/TokenItem/TokenItem.tsx similarity index 79% rename from packages/circle-demo-webapp/app/components/TokenItem/TokenItem.tsx rename to packages/circle-react-elements/src/components/TokenItem/TokenItem.tsx index af45213..5f4efdd 100644 --- a/packages/circle-demo-webapp/app/components/TokenItem/TokenItem.tsx +++ b/packages/circle-react-elements/src/components/TokenItem/TokenItem.tsx @@ -1,7 +1,6 @@ +import type { Token } from '@circle-fin/developer-controlled-wallets'; import { TokenIcon } from '@web3icons/react'; -import { Token } from '~/lib/types'; - export interface TokenItemProps { /** The balance details */ token: Token; @@ -12,7 +11,7 @@ export function TokenItem({ token }: TokenItemProps) { return (
({ id: props.transaction?.id }), - [props.transaction], - ); - const { data: transaction, reFetch } = useGetTransaction( - getTransactionFilter, - props.transaction, - ); +export function TransactionDetails({ transaction }: TransactionDetailsProps) { const shortHash = useMemo( () => (transaction?.txHash ? shortenHash(transaction.txHash) : ''), [transaction], @@ -38,16 +28,14 @@ export function TransactionDetails(props: TransactionDetailsProps) { return null; } - const isInbound = transaction.transactionType === TransactionType.Inbound; + const isInbound = transaction.transactionType === 'INBOUND'; return (
- } + value={} /> diff --git a/packages/circle-demo-webapp/app/components/TransactionDetails/index.ts b/packages/circle-react-elements/src/components/TransactionDetails/index.ts similarity index 100% rename from packages/circle-demo-webapp/app/components/TransactionDetails/index.ts rename to packages/circle-react-elements/src/components/TransactionDetails/index.ts diff --git a/packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.stories.ts b/packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.stories.ts new file mode 100644 index 0000000..7acb6d0 --- /dev/null +++ b/packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.stories.ts @@ -0,0 +1,63 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { TransactionStateText } from './TransactionStateText'; + +const meta = { + title: 'TransactionStateText', + component: TransactionStateText, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Complete: Story = { + args: { + state: 'COMPLETE', + }, +}; + +export const Cancelled: Story = { + args: { + state: 'CANCELLED', + }, +}; + +export const Confirmed: Story = { + args: { + state: 'CONFIRMED', + }, +}; + +export const Sent: Story = { + args: { + state: 'SENT', + }, +}; + +export const Denied: Story = { + args: { + state: 'DENIED', + }, +}; +export const Failed: Story = { + args: { + state: 'FAILED', + }, +}; +export const Initiated: Story = { + args: { + state: 'INITIATED', + }, +}; +export const PendingRiskScreening: Story = { + args: { + state: 'PENDING_RISK_SCREENING', + }, +}; +export const Queued: Story = { + args: { + state: 'QUEUED', + }, +}; diff --git a/packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.tsx b/packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.tsx new file mode 100644 index 0000000..faf5558 --- /dev/null +++ b/packages/circle-react-elements/src/components/TransactionStatusText/TransactionStateText.tsx @@ -0,0 +1,45 @@ +import { TransactionState } from '@circle-fin/developer-controlled-wallets'; + +import { Badge } from '../ui/badge'; + +export interface TransactionStateTextProps { + /** The state of the transaction: + * 'CANCELLED', 'CONFIRMED', 'COMPLETE', 'DENIED', 'FAILED', 'INITIATED', 'PENDING_RISK_SCREENING', 'QUEUED', 'SENT'; + * + * **/ + state: TransactionState; +} + +const greenStates = ['COMPLETE', 'CONFIRMED']; +const yellowStates = ['SENT', 'INITIATED', 'QUEUED', 'PENDING_RISK_SCREENING']; + +const capitalize = (str: string) => + str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); + +const toText = (state: string) => state.replace(/_/gi, ' '); + +/** Display transaction state text **/ +export function TransactionStateText({ state }: TransactionStateTextProps) { + return greenStates.includes(state) ? ( + + {capitalize(toText(state))} ✓ + + ) : yellowStates.includes(state) ? ( + + {capitalize(toText(state))} + + ) : ( + + {capitalize(toText(state))} ✘ + + ); +} diff --git a/packages/circle-demo-webapp/app/components/TransactionStatusText/index.ts b/packages/circle-react-elements/src/components/TransactionStatusText/index.ts similarity index 100% rename from packages/circle-demo-webapp/app/components/TransactionStatusText/index.ts rename to packages/circle-react-elements/src/components/TransactionStatusText/index.ts diff --git a/packages/circle-react-elements/src/components/ui/badge.tsx b/packages/circle-react-elements/src/components/ui/badge.tsx new file mode 100644 index 0000000..b37ccff --- /dev/null +++ b/packages/circle-react-elements/src/components/ui/badge.tsx @@ -0,0 +1,33 @@ +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; + +import { cn } from '../../lib/utils'; + +const badgeVariants = cva( + 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold', + { + variants: { + variant: { + default: 'border-transparent bg-primary text-primary-foreground', + secondary: 'border-transparent bg-secondary text-secondary-foreground', + accent: 'border-transparent bg-accent text-accent-foreground', + destructive: 'border-transparent bg-destructive text-destructive-foreground', + positive: 'border-transparent bg-positive text-positive-foreground', + outline: 'text-foreground', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return
; +} + +export { Badge }; diff --git a/packages/circle-react-elements/src/index.tsx b/packages/circle-react-elements/src/index.tsx index 0c06293..9f3bb6c 100644 --- a/packages/circle-react-elements/src/index.tsx +++ b/packages/circle-react-elements/src/index.tsx @@ -1,3 +1,8 @@ export * from './components/Amount'; export * from './components/TokenSelect'; export * from './components/WalletBalance'; +export * from './components/TransactionStatusText'; +export * from './components/TransactionDetails'; +export * from './components/ChainLabel'; +export * from './components/ChainIcon'; +export * from './components/TokenItem'; diff --git a/packages/circle-react-elements/src/lib/format.ts b/packages/circle-react-elements/src/lib/format.ts new file mode 100644 index 0000000..045c7e9 --- /dev/null +++ b/packages/circle-react-elements/src/lib/format.ts @@ -0,0 +1,15 @@ +export function shortenAddress(address: string): string { + return `${address.slice(0, 6)}...${address.slice(-4)}`; +} + +export function shortenHash(hash: string): string { + return `${hash.slice(0, 10)}...${hash.slice(-10)}`; +} + +export function formatDate(date: string): string { + return new Date(date).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric', + }); +} diff --git a/packages/circle-react-elements/src/lib/types.ts b/packages/circle-react-elements/src/lib/types.ts index e69de29..c520b0a 100644 --- a/packages/circle-react-elements/src/lib/types.ts +++ b/packages/circle-react-elements/src/lib/types.ts @@ -0,0 +1,6 @@ +import type { Token } from '@circle-fin/developer-controlled-wallets'; +import type { Transaction } from '@circle-fin/developer-controlled-wallets/dist/types/clients/developer-controlled-wallets'; + +export interface TransactionWithToken extends Transaction { + token?: Token; +}