@zerodev/smart-routing-address-react-ui 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_types/components/QrSheet/index.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +667 -781
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/QrSheet/index.tsx +3 -12
- package/dist/_types/components/QrSheet/QrCode.d.ts +0 -28
- package/dist/_types/components/QrSheet/QrCode.d.ts.map +0 -1
- package/src/components/QrSheet/QrCode.tsx +0 -163
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/constants.ts","../src/utils/chains.ts","../src/utils/fees.ts","../src/utils/config.ts","../src/context/SmartRoutingAddressContext.ts","../src/context/SmartRoutingAddressProvider.tsx","../src/hooks/useCreateSmartRoutingAddress.ts","../src/hooks/useSmartRoutingAddress.ts","../src/components/QrSheet/QrCode.tsx","../src/components/QrSheet/index.tsx","../src/components/LoadingCard/index.tsx","../src/components/AddressDisplay/index.tsx","../src/components/ErrorRetryCard/index.tsx","../src/iconAssets.ts","../src/utils/format.ts","../src/utils/providerFees.ts","../src/components/FeeBreakdown/feeInfo.ts","../src/components/FeeBreakdown/index.tsx","../src/utils/deposits.ts","../src/components/TxnItem/index.tsx","../src/components/PendingDeposits/index.tsx","../src/hooks/useDepositStatus.ts","../src/hooks/useNewDeposits.ts","../src/hooks/useProviderFees.ts","../src/pages/Deposit.tsx","../src/pages/PastDeposits.tsx","../src/pages/TransactionDetails.tsx","../src/pages/index.tsx"],"sourcesContent":["import type { TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { SUPPORTED_TOKENS } from '@zerodev/smart-routing-address'\nimport type { Chain } from 'viem'\nimport {\n arbitrum,\n base,\n blast,\n bsc,\n celo,\n flowMainnet,\n hyperEvm,\n ink,\n linea,\n mainnet,\n megaeth,\n mode,\n monad,\n optimism,\n plasma,\n polygon,\n scroll,\n soneium,\n tempo,\n unichain,\n worldchain,\n zora,\n} from 'viem/chains'\nimport type { SourceToken } from './types'\n\nexport const DEFAULT_POLLING_INTERVAL_MS = 5_000\n\nexport const DEFAULT_FILL_TIME_SECONDS = 30\n\nexport const DEFAULT_DASHBOARD_URL = 'https://smart-routing-address.zerodev.app'\n\n/**\n * Chains supported by the smart routing address SDK; mirrors the\n * smart-account-plus core `supportedChainIds` list.\n */\nexport const SUPPORTED_CHAINS: readonly Chain[] = [\n mainnet,\n optimism,\n arbitrum,\n polygon,\n plasma,\n base,\n celo,\n mode,\n monad,\n blast,\n bsc,\n flowMainnet,\n hyperEvm,\n linea,\n ink,\n megaeth,\n scroll,\n soneium,\n tempo,\n unichain,\n worldchain,\n zora,\n]\n\nexport const CHAINS_BY_ID: ReadonlyMap<number, Chain> = new Map(\n SUPPORTED_CHAINS.map((chain) => [chain.id, chain]),\n)\n\n/**\n * Token types the SDK ships in `SUPPORTED_TOKENS` but the SRA server does not\n * yet recognize. Sending one of these as a source token makes the server\n * reject the whole `createSmartRoutingAddress` request with\n * `Invalid params: Token address … is not supported on chain N`, which breaks\n * the entire destination (e.g. Base). Remove entries here as the server\n * registry catches up.\n *\n * TODO: file/track ZeroDev SRA server bug for EURC on Base\n * (chain 8453, address 0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42) — once the\n * server accepts it, drop this filter.\n */\nconst UNSUPPORTED_TOKEN_TYPES: ReadonlySet<TOKEN_TYPE> = new Set(['EURC'])\n\n/**\n * Source tokens offered for deposits: every supported mainnet token the SDK\n * exposes (NATIVE plus each ERC-20, with wrapped native surfaced as WETH),\n * mapped to its viem chain object. Testnets are excluded from the default;\n * chains this package cannot resolve to a viem chain are skipped, and token\n * types the server can't route yet are filtered via `UNSUPPORTED_TOKEN_TYPES`.\n */\nexport const DEFAULT_SOURCE_TOKENS: SourceToken[] = Object.entries(\n SUPPORTED_TOKENS,\n).flatMap(([chainId, tokens]) => {\n // Skip chains this package cannot resolve to a viem chain object\n const chain = CHAINS_BY_ID.get(Number(chainId))\n if (!chain) return []\n return Object.keys(tokens)\n .filter((t) => !UNSUPPORTED_TOKEN_TYPES.has(t as TOKEN_TYPE))\n .map((tokenType) => ({\n chain,\n tokenType: tokenType as TOKEN_TYPE,\n }))\n})\n","import type { Chain } from 'viem'\nimport { CHAINS_BY_ID, SUPPORTED_CHAINS } from '../constants'\n\n/** Resolve a chain id to its viem chain object, throwing for unknown ids */\nexport function getChainById(chainId: number): Chain {\n const chain = CHAINS_BY_ID.get(chainId)\n if (!chain) {\n const supported = SUPPORTED_CHAINS.map((c) => `${c.name} (${c.id})`)\n throw new Error(\n `Unsupported chain id ${chainId}. Supported chains: ${supported.join(', ')}`,\n )\n }\n return chain\n}\n\n/** Block explorer URL for a transaction, or `undefined` when no explorer is\n * known. Returns `undefined` (not `null`) so the value can be passed straight\n * to optional link `href` props under `exactOptionalPropertyTypes`. */\nexport function getTxUrl(\n chainId: number,\n transactionHash: string,\n): string | undefined {\n const explorer = CHAINS_BY_ID.get(chainId)?.blockExplorers?.default\n if (!explorer) return undefined\n return `${explorer.url}/tx/${transactionHash}`\n}\n","import type { TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { SUPPORTED_TOKENS } from '@zerodev/smart-routing-address'\nimport type { Address } from 'viem'\nimport { isAddressEqual, zeroAddress } from 'viem'\nimport type { EstimatedFee, EstimatedFeeData } from '../types'\n\n/**\n * Resolve the on-chain token address used by the routing server for a given\n * token type on a chain. Returns null when the type cannot be resolved\n * (generic ERC20 or unknown token on that chain).\n */\nexport function resolveTokenAddress(\n tokenType: TOKEN_TYPE,\n chainId: number,\n): Address | null {\n if (tokenType === 'NATIVE') return zeroAddress\n if (tokenType === 'ERC20') return null\n return SUPPORTED_TOKENS[chainId]?.[tokenType] ?? null\n}\n\n/** Whether the token type resolves to the given on-chain address on a chain. */\nexport function tokenAddressMatches(\n tokenType: TOKEN_TYPE,\n chainId: number,\n token: Address,\n): boolean {\n const address = resolveTokenAddress(tokenType, chainId)\n return address !== null && isAddressEqual(address, token)\n}\n\nexport function findFeeDataByToken(\n estimatedFees: EstimatedFee[],\n chainId: number,\n token: Address,\n): EstimatedFeeData | null {\n const chainFees = estimatedFees.find((fee) => fee.chainId === chainId)\n if (!chainFees) return null\n return (\n chainFees.data.find((data) => isAddressEqual(data.token, token)) ?? null\n )\n}\n\nexport function findFeeData(\n estimatedFees: EstimatedFee[],\n chainId: number,\n tokenType: TOKEN_TYPE,\n): EstimatedFeeData | null {\n const token = resolveTokenAddress(tokenType, chainId)\n if (!token) return null\n return findFeeDataByToken(estimatedFees, chainId, token)\n}\n","import type {\n CreateSmartRoutingAddressParams,\n SmartRoutingAddressVersion,\n TOKEN_TYPE,\n} from '@zerodev/smart-routing-address'\nimport {\n createCall,\n FLEX,\n SMART_ROUTING_ADDRESS_SERVER_URL,\n SMART_ROUTING_ADDRESS_V0_2_1,\n SUPPORTED_TOKENS,\n} from '@zerodev/smart-routing-address'\nimport { type Address, type Chain, erc20Abi } from 'viem'\nimport { DEFAULT_DASHBOARD_URL, DEFAULT_SOURCE_TOKENS } from '../constants'\nimport type {\n EstimatedFee,\n SmartRoutingAddressConfig,\n SourceToken,\n} from '../types'\nimport { getChainById } from './chains'\nimport { tokenAddressMatches } from './fees'\n\nexport function resolveVersion(\n config: SmartRoutingAddressConfig,\n): SmartRoutingAddressVersion {\n return config.version ?? SMART_ROUTING_ADDRESS_V0_2_1\n}\n\n/**\n * Server URL for all smart routing address requests: the server root\n * (default or `config.baseUrl`) with the ZeroDev project id appended.\n * Without a project id the URL is only overridden when `config.baseUrl`\n * is set; undefined leaves the SDK default in place.\n */\nexport function resolveBaseUrl(\n config: SmartRoutingAddressConfig,\n): string | undefined {\n if (!config.projectId) return config.baseUrl\n const root = config.baseUrl ?? SMART_ROUTING_ADDRESS_SERVER_URL\n return `${root.replace(/\\/+$/, '')}/${config.projectId}`\n}\n\nexport function resolveDashboardUrl(address?: string): string {\n if (!address) return DEFAULT_DASHBOARD_URL\n return `${DEFAULT_DASHBOARD_URL.replace(/\\/+$/, '')}/address/${address}`\n}\n\n/** Chain where the routed funds settle */\nexport function resolveDestChain(config: SmartRoutingAddressConfig): Chain {\n return getChainById(config.targetChainId)\n}\n\n/**\n * Whether the SDK can resolve the token type to an asset on the chain:\n * generic ERC20 deposits are always accepted, every other type (including\n * NATIVE) needs a SUPPORTED_TOKENS entry for the chain.\n */\nfunction isTokenOnChain(tokenType: TOKEN_TYPE, chainId: number): boolean {\n if (tokenType === 'ERC20') return true\n return SUPPORTED_TOKENS[chainId]?.[tokenType] !== undefined\n}\n\n/**\n * The DEFAULT_SOURCE_TOKENS, excluding token types that do not exist on the\n * destination chain (the default actions deliver the deposited token type\n * there, so a missing destination token would make the deposit unfulfillable).\n */\nexport function resolveSourceTokens(\n config: SmartRoutingAddressConfig,\n): SourceToken[] {\n const destChainId = resolveDestChain(config).id\n return DEFAULT_SOURCE_TOKENS.filter((source) =>\n isTokenOnChain(source.tokenType, destChainId),\n )\n}\n\n/**\n * Source tokens the server actually returned routes for, taken straight from\n * the fee estimates. Each returned (chain, token address) pair is matched back\n * to a DEFAULT_SOURCE_TOKENS entry to recover its TOKEN_TYPE.\n */\nexport function sourceTokensFromFees(\n estimatedFees: EstimatedFee[],\n): SourceToken[] {\n return estimatedFees.flatMap((fee) =>\n fee.data.flatMap((data) => {\n const token = DEFAULT_SOURCE_TOKENS.find(\n (source) =>\n source.chain.id === fee.chainId &&\n tokenAddressMatches(source.tokenType, fee.chainId, data.token),\n )\n return token ? [token] : []\n }),\n )\n}\n\nfunction uniqueTokenTypes(sources: SourceToken[]): TOKEN_TYPE[] {\n return [...new Set(sources.map((source) => source.tokenType))]\n}\n\n/**\n * Destination actions for every resolved source token type: ERC-20 deposits\n * are transferred to the recipient and native deposits are forwarded as\n * value. FLEX placeholders are resolved by the server per deposit.\n */\nexport function resolveActions(\n config: SmartRoutingAddressConfig,\n recipient: Address,\n): CreateSmartRoutingAddressParams['actions'] {\n const erc20Call = createCall({\n target: FLEX.TOKEN_ADDRESS,\n value: 0n,\n abi: erc20Abi,\n functionName: 'transfer',\n args: [recipient, FLEX.AMOUNT],\n })\n const nativeCall = createCall({\n target: recipient,\n value: FLEX.NATIVE_AMOUNT,\n })\n\n return Object.fromEntries(\n uniqueTokenTypes(resolveSourceTokens(config)).map((tokenType) => [\n tokenType,\n {\n action: tokenType === 'NATIVE' ? [nativeCall] : [erc20Call],\n fallBack: tokenType === 'NATIVE' ? [nativeCall] : [erc20Call],\n },\n ]),\n )\n}\n\n/** Display symbol for a source token (native tokens use the chain symbol) */\nexport function getSourceTokenSymbol(source: SourceToken): string {\n if (source.tokenType === 'NATIVE') {\n return source.chain.nativeCurrency.symbol\n }\n if (source.tokenType === 'WRAPPED_NATIVE') {\n return `W${source.chain.nativeCurrency.symbol}`\n }\n return source.tokenType\n}\n","import { createContext, useContext } from 'react'\nimport type { Address } from 'viem'\nimport type {\n ActiveRoute,\n AddressState,\n SmartRoutingAddressConfig,\n} from '../types'\n\nexport type SmartRoutingAddressContextValue = {\n config: SmartRoutingAddressConfig\n addressState: AddressState\n /** Recipient of the active (or last requested) smart routing address */\n recipient?: Address | undefined\n /**\n * Return the smart routing address for the recipient, creating it if it\n * has not been created yet. Safe to call multiple times; concurrent calls\n * for the same recipient share one request, while a new recipient\n * triggers a fresh creation. Rejects when creation fails (the failure\n * also lands in `addressState`).\n */\n getOrCreateAddress: (recipient: Address) => Promise<Address>\n /**\n * Re-run address creation for the current recipient. No-op if no recipient\n * has been set yet. Wired to the \"Failed to create deposit address\" retry\n * button in the deposit UI.\n */\n retry: () => Promise<void>\n /**\n * The route currently shown in the deposit UI. `null` until the picker\n * seeds a selection. Hosts can read this to mirror the widget's state.\n */\n activeRoute: ActiveRoute | null\n /** Deposit UI internal — writes the current picker selection to context. */\n setActiveRoute: (route: ActiveRoute | null) => void\n}\n\nexport const SmartRoutingAddressContext =\n createContext<SmartRoutingAddressContextValue | null>(null)\n\nexport function useSmartRoutingAddressContext(): SmartRoutingAddressContextValue {\n const context = useContext(SmartRoutingAddressContext)\n if (!context) {\n throw new Error(\n 'Smart routing address components must be rendered inside <SmartRoutingAddressProvider>',\n )\n }\n return context\n}\n","import { createSmartRoutingAddress } from '@zerodev/smart-routing-address'\nimport { type ReactNode, useCallback, useMemo, useRef, useState } from 'react'\nimport type { Address } from 'viem'\nimport type {\n ActiveRoute,\n AddressState,\n SmartRoutingAddressConfig,\n} from '../types'\nimport {\n resolveActions,\n resolveBaseUrl,\n resolveDestChain,\n resolveSourceTokens,\n resolveVersion,\n} from '../utils/config'\nimport { SmartRoutingAddressContext } from './SmartRoutingAddressContext'\n\nexport type SmartRoutingAddressProviderProps = {\n config: SmartRoutingAddressConfig\n children: ReactNode\n}\n\n/**\n * Holds the config and the lazily created routing address. Wrap the subtree\n * that renders <SmartRoutingAddress /> with this provider — the deposit UI\n * itself is rendered inline by the consumer, not by this provider.\n */\nexport function SmartRoutingAddressProvider({\n config,\n children,\n}: SmartRoutingAddressProviderProps) {\n const [addressState, setAddressState] = useState<AddressState>({\n status: 'idle',\n })\n const [recipient, setRecipient] = useState<Address | undefined>(undefined)\n const [activeRoute, setActiveRoute] = useState<ActiveRoute | null>(null)\n const pendingRef = useRef<Promise<Address> | null>(null)\n const recipientRef = useRef<Address | null>(null)\n // Each creation request gets a generation; only the latest generation\n // may write state, so superseded requests are ignored entirely\n const genRef = useRef(0)\n const configRef = useRef(config)\n\n const getOrCreateAddress = useCallback(\n async (nextRecipient: Address): Promise<Address> => {\n // A new config invalidates any cached request\n if (configRef.current !== config) {\n configRef.current = config\n genRef.current += 1\n pendingRef.current = null\n recipientRef.current = null\n }\n\n // Reuse the pending/settled request for the same recipient\n if (pendingRef.current && recipientRef.current === nextRecipient) {\n return pendingRef.current\n }\n\n genRef.current += 1\n const gen = genRef.current\n recipientRef.current = nextRecipient\n setRecipient(nextRecipient)\n\n const request = (async () => {\n setAddressState({ status: 'loading' })\n try {\n const baseUrl = resolveBaseUrl(config)\n const result = await createSmartRoutingAddress({\n owner: nextRecipient,\n destChain: resolveDestChain(config),\n slippage: config.slippage,\n srcTokens: resolveSourceTokens(config),\n ...(resolveActions(config, nextRecipient) && {\n actions: resolveActions(config, nextRecipient),\n }),\n // Drop source tokens without an available route instead\n // of failing the whole address creation\n allowPartialRoutes: true,\n config: {\n ...(baseUrl && { baseUrl }),\n version: resolveVersion(config),\n },\n })\n // State writes are generation-gated (results superseded by a newer\n // request must not clobber the live one), but the promise still\n // resolves with the address this call created — per-call semantics\n // stay honest even after the provider has moved on.\n if (genRef.current === gen) {\n setAddressState({\n status: 'success',\n address: result.smartRoutingAddress,\n estimatedFees: result.estimatedFees,\n })\n }\n return result.smartRoutingAddress\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n // Superseded failures must not clear the live request\n if (genRef.current === gen) {\n // Allow a retry after failures\n pendingRef.current = null\n setAddressState({ status: 'error', error: err })\n }\n throw err\n }\n })()\n\n pendingRef.current = request\n return request\n },\n [config],\n )\n\n const retry = useCallback(async () => {\n const current = recipientRef.current\n if (!current) return\n // Force a fresh request even if we still have a settled one cached\n pendingRef.current = null\n recipientRef.current = null\n // Failures surface via `addressState`; swallow the rejection so retry\n // callers (e.g. the ErrorRetryCard click handler) don't need a catch.\n await getOrCreateAddress(current).catch(() => {})\n }, [getOrCreateAddress])\n\n const value = useMemo(\n () => ({\n config,\n addressState,\n recipient,\n getOrCreateAddress,\n retry,\n activeRoute,\n setActiveRoute,\n }),\n [config, addressState, recipient, getOrCreateAddress, retry, activeRoute],\n )\n\n return (\n <SmartRoutingAddressContext.Provider value={value}>\n {children}\n </SmartRoutingAddressContext.Provider>\n )\n}\n","import type { Address } from 'viem'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\n\nexport type UseCreateSmartRoutingAddressResult = {\n /**\n * Return the deposit address for the recipient, creating it if it doesn't\n * exist yet. Idempotent per recipient — concurrent and repeated calls\n * share one request, so it's safe to call on every hover/focus/mount.\n * Rejects when creation fails (the failure also lands in the read hook's\n * `addressState`). Creation params (`actions`, `slippage`, …) come from\n * the provider config so the address always matches what the widget\n * displays — there are no per-call overrides. To create addresses with\n * bespoke params, use `createSmartRoutingAddress` from\n * `@zerodev/smart-routing-address`.\n */\n getOrCreateAddress: (recipient: Address) => Promise<Address>\n}\n\n/**\n * Action counterpart to `useSmartRoutingAddress` (which is read-only): lets\n * hosts embedding the `<SmartRoutingAddress />` widget pre-create the\n * deposit address — e.g. on hover or route entry, before the modal opens —\n * so the widget renders instantly.\n */\nexport function useCreateSmartRoutingAddress(): UseCreateSmartRoutingAddressResult {\n const { getOrCreateAddress } = useSmartRoutingAddressContext()\n return { getOrCreateAddress }\n}\n","import { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport type { ActiveRoute, AddressState } from '../types'\n\nexport type UseSmartRoutingAddressResult = {\n addressState: AddressState\n /**\n * The route the widget's deposit UI is currently showing (source token +\n * chain + estimated fee). `null` until the picker has seeded a selection.\n * Read-only by design: the widget's picker owns this value; hosts mirror\n * it (e.g. to drive a companion send panel), they don't set it.\n */\n activeRoute: ActiveRoute | null\n}\n\n/**\n * Read-only companion hook for hosts embedding the `<SmartRoutingAddress />`\n * widget: observe the address state and mirror the route the widget is\n * showing, from anywhere inside the provider. Its action counterpart is\n * `useCreateSmartRoutingAddress`. Not a kit for building a custom deposit\n * UI — for that, use `@zerodev/smart-routing-address` directly.\n */\nexport function useSmartRoutingAddress(): UseSmartRoutingAddressResult {\n const { addressState, activeRoute } = useSmartRoutingAddressContext()\n return { addressState, activeRoute }\n}\n","import { encode } from 'uqr'\n\ninterface QrCodeProps {\n /** Data to encode. */\n value: string\n /** Pixel size of the rendered SVG square. */\n size: number\n /** Error correction level. Defaults to `'M'`. */\n errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'\n /** Corner radius (in modules, scaled to px internally) for finder patterns. */\n eyeRadius?: number\n}\n\nconst FINDER_SIZE = 7 // every QR has three 7×7 finder patterns\nconst MODULE_COLOR = '#000'\nconst BG_COLOR = '#fff'\n/** Vertical shrink applied to data-module pills so rows read as distinct\n * without introducing white slivers wide enough to look like transitions\n * to a scanner. Kept small (5%) so total black area stays close to spec. */\nconst PILL_PAD_RATIO = 0.05\n\n/**\n * Custom QR renderer that draws runs of horizontally-adjacent data modules as\n * a single rounded pill. Finder patterns stay as sharp concentric squares\n * (rounding them breaks the 1:1:3:1:1 corner ratio scanners use to locate the\n * code). Isolated data modules render as pill-ish rects — visually close to\n * circles at very small `PILL_PAD_RATIO`, still square-adjacent for scanners.\n *\n * Default `errorCorrectionLevel` is `'H'` (30% recovery) so the decorative\n * rounding + shrinkage has plenty of headroom before scans fail.\n *\n * Quiet zone (spec: ≥4 modules of white around the code) is expected to be\n * provided by the caller — e.g. via a white-background padded wrapper. This\n * component fills the given `size` with the QR data area itself so the\n * consumer controls the visual footprint.\n */\nexport function QrCode({\n value,\n size,\n errorCorrectionLevel = 'H',\n eyeRadius = 0,\n}: QrCodeProps) {\n // `uqr` returns a 2D boolean matrix (`data[row][col]`) and the module count\n // per side. Same information as `qrcode`, just shaped differently — the\n // pill/finder rendering below is unchanged.\n const qr = encode(value, { ecc: errorCorrectionLevel, border: 0 })\n const matrix = qr.data\n const moduleCount = qr.size\n const cellSize = size / moduleCount\n const eyeRadiusPx = eyeRadius * cellSize\n\n const finders = [\n { row: 0, col: 0 },\n { row: 0, col: moduleCount - FINDER_SIZE },\n { row: moduleCount - FINDER_SIZE, col: 0 },\n ]\n\n const inFinder = (row: number, col: number) =>\n finders.some(\n (f) =>\n row >= f.row &&\n row < f.row + FINDER_SIZE &&\n col >= f.col &&\n col < f.col + FINDER_SIZE,\n )\n\n // Collect maximal horizontal runs of `on` modules, skipping finder regions.\n const runs: { row: number; col: number; length: number }[] = []\n for (let row = 0; row < moduleCount; row++) {\n let col = 0\n while (col < moduleCount) {\n if (inFinder(row, col)) {\n col++\n continue\n }\n if (matrix[row]?.[col]) {\n let length = 1\n while (\n col + length < moduleCount &&\n !inFinder(row, col + length) &&\n matrix[row]?.[col + length]\n ) {\n length++\n }\n runs.push({ row, col, length })\n col += length\n } else {\n col++\n }\n }\n }\n\n return (\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n xmlns=\"http://www.w3.org/2000/svg\"\n role=\"img\"\n aria-label={`QR code for ${value}`}\n >\n <rect width={size} height={size} fill={BG_COLOR} />\n {runs.map(({ row, col, length }) => {\n // Shrink each pill vertically so rows read as distinct without\n // creating scanner-confusing white gaps mid-run. Isolated modules\n // (length === 1) also shrink horizontally so they render close to a\n // circle instead of an oval.\n const pad = cellSize * PILL_PAD_RATIO\n const pillHeight = cellSize - 2 * pad\n const isSingle = length === 1\n return (\n <rect\n key={`r${row}-${col}`}\n x={col * cellSize + (isSingle ? pad : 0)}\n y={row * cellSize + pad}\n width={length * cellSize - (isSingle ? 2 * pad : 0)}\n height={pillHeight}\n rx={pillHeight / 2}\n ry={pillHeight / 2}\n fill={MODULE_COLOR}\n />\n )\n })}\n {finders.map(({ row, col }) => {\n const x = col * cellSize\n const y = row * cellSize\n const outerSize = FINDER_SIZE * cellSize\n const innerSize = 3 * cellSize\n return (\n <g key={`f${row}-${col}`}>\n <rect\n x={x}\n y={y}\n width={outerSize}\n height={outerSize}\n rx={eyeRadiusPx}\n ry={eyeRadiusPx}\n fill={MODULE_COLOR}\n />\n <rect\n x={x + cellSize}\n y={y + cellSize}\n width={outerSize - 2 * cellSize}\n height={outerSize - 2 * cellSize}\n rx={Math.max(eyeRadiusPx - cellSize, 0)}\n ry={Math.max(eyeRadiusPx - cellSize, 0)}\n fill={BG_COLOR}\n />\n <rect\n x={x + 2 * cellSize}\n y={y + 2 * cellSize}\n width={innerSize}\n height={innerSize}\n rx={Math.max(eyeRadiusPx - 2 * cellSize, 0)}\n ry={Math.max(eyeRadiusPx - 2 * cellSize, 0)}\n fill={MODULE_COLOR}\n />\n </g>\n )\n })}\n </svg>\n )\n}\n","import {\n BottomSheet,\n BottomSheetClose,\n BottomSheetContent,\n BottomSheetTitle,\n Button,\n Text,\n} from '@zerodev/react-ui'\nimport { QrCode } from './QrCode'\n\nexport interface QrSheetProps {\n /** Whether the modal is open. Controlled. */\n open: boolean\n /** Called when the modal requests to close (backdrop click, ESC,\n * Cancel button). */\n onOpenChange: (open: boolean) => void\n /** Address to encode in the QR code and display below it. */\n address: string\n /** Called when the user taps \"Copy address\". */\n onCopy: () => void\n}\n\n/** Bottom-anchored modal showing the deposit address as a QR code. Composes\n * `<BottomSheet>` (state) + `<BottomSheetContent>` (chrome); this file owns the\n * QR / address / copy-cancel layout inside it. */\nexport function QrSheet({ open, onOpenChange, address, onCopy }: QrSheetProps) {\n return (\n <BottomSheet open={open} onOpenChange={onOpenChange}>\n <BottomSheetContent>\n <BottomSheetTitle>Your deposit address</BottomSheetTitle>\n {/* Bottom-half gradient — light blue at bottom-left fading into\n peach/orange at bottom-right — mirrors the \"amorphic\" image used\n in the Figma design. Colors echo `MultiRadialBackground`. */}\n <div\n aria-hidden\n className=\"zd:absolute zd:inset-0 zd:pointer-events-none\"\n style={{\n background:\n 'radial-gradient(ellipse 78% 65% at 5% 105%, rgba(69,171,251,0.35) 0%, rgba(69,171,251,0) 72%), radial-gradient(ellipse 82% 65% at 100% 105%, rgba(250,200,172,0.65) 0%, rgba(250,200,172,0) 72%), radial-gradient(ellipse 58% 52% at 100% 100%, rgba(242,123,62,0.35) 0%, rgba(242,123,62,0) 72%)',\n }}\n />\n <div className=\"zd:relative zd:flex zd:flex-col zd:gap-6 zd:items-center zd:pt-6 zd:px-4 zd:pb-3\">\n <div className=\"zd:flex zd:flex-col zd:gap-3 zd:items-center\">\n <Text className=\"zd:text-h2 zd:text-center\">\n Your deposit address\n </Text>\n <Text className=\"zd:text-body2 zd:text-center zd:max-w-[300px]\">\n Send funds to this address to automatically bridge and swap\n desired assets.\n </Text>\n </div>\n\n {/* The white bg + `p-5` (20px) padding around the QR doubles as\n the required 4-module quiet zone — QrCode itself no longer\n reserves one internally so the code fills its declared size. */}\n <div className=\"zd:relative zd:bg-white zd:w-[240px] zd:h-[240px] zd:p-5 zd:flex zd:items-center zd:justify-center\">\n <QrCode value={address} size={200} eyeRadius={2} />\n {/* Corner brackets — viewfinder-style framing. Color/thickness\n match the Figma's `rgba(19,14,11,0.1)` 1px outline. */}\n <div className=\"zd:absolute zd:top-0 zd:left-0 zd:w-5 zd:h-5 zd:border-t zd:border-l zd:border-greyScale/10 zd:rounded-tl-lg zd:pointer-events-none\" />\n <div className=\"zd:absolute zd:top-0 zd:right-0 zd:w-5 zd:h-5 zd:border-t zd:border-r zd:border-greyScale/10 zd:rounded-tr-lg zd:pointer-events-none\" />\n <div className=\"zd:absolute zd:bottom-0 zd:left-0 zd:w-5 zd:h-5 zd:border-b zd:border-l zd:border-greyScale/10 zd:rounded-bl-lg zd:pointer-events-none\" />\n <div className=\"zd:absolute zd:bottom-0 zd:right-0 zd:w-5 zd:h-5 zd:border-b zd:border-r zd:border-greyScale/10 zd:rounded-br-lg zd:pointer-events-none\" />\n </div>\n\n <Text className=\"zd:text-body2 zd:text-center zd:break-all zd:max-w-[230px]\">\n {address}\n </Text>\n\n <div className=\"zd:flex zd:flex-col zd:gap-1 zd:w-full\">\n <Button action=\"primary\" text=\"Copy address\" onClick={onCopy} />\n <BottomSheetClose asChild>\n <Button action=\"secondary\" text=\"Cancel\" />\n </BottomSheetClose>\n </div>\n </div>\n </BottomSheetContent>\n </BottomSheet>\n )\n}\n","import { cn, Icon, Text, Wrapper } from '@zerodev/react-ui'\nimport type { HTMLAttributes } from 'react'\n\nexport interface LoadingCardProps extends HTMLAttributes<HTMLDivElement> {\n text: string\n}\n\nexport function LoadingCard({ text, className, ...rest }: LoadingCardProps) {\n return (\n <Wrapper\n variant=\"ghost\"\n className={cn(\n 'zd:relative zd:flex zd:h-[68px] zd:w-full zd:items-center zd:justify-start zd:gap-2 zd:overflow-hidden zd:rounded-2xl zd:px-4',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n {...rest}\n >\n <Icon\n name=\"loading\"\n className=\"zd:w-4 zd:h-4 zd:animate-spin zd:text-orange\"\n data-testid=\"loading-card-icon\"\n />\n <Text className=\"zd:text-body1 zd:text-greyScale/50\">{text}</Text>\n </Wrapper>\n )\n}\n","import { cn, Icon, Text, Wrapper } from '@zerodev/react-ui'\nimport type { AddressState } from '../../types'\nimport { LoadingCard } from '../LoadingCard'\n\n/**\n * The card that renders the deposit address in the SRA \"Deposit funds\" screen.\n *\n * Two visual states, each mapped 1:1 to a Figma node:\n * - Loading (Figma 17634:104343, \"Smart Funding\" card): delegates to\n * `LoadingCard`, which is the shared spinner+text pill used elsewhere in\n * the SRA flow (e.g., SmartFunding's \"Watching for deposit\" state).\n * - Ready (Figma 17762:78875, address+QR row): 14px radius, 40% offWhite\n * surface, left-aligned address text + a 52×52 white QR button on the\n * right. Rendered when `address` is supplied.\n *\n * The two states have deliberately different visuals; they share this\n * component because the parent renders the same slot in both cases.\n */\nexport interface AddressDisplayUIProps {\n /** Deposit address to render; when omitted, the loading variant is shown. */\n address?: string\n /**\n * Message rendered in the loading variant. Include chain-specific context\n * from the caller, e.g., `Watching for your deposit on Base…`.\n */\n loadingText?: string\n /** Handler for the QR icon button (ready variant). */\n onQrClick?: (() => void) | undefined\n className?: string\n}\n\nexport function AddressDisplayUI({\n address,\n loadingText = 'Watching for your deposit…',\n onQrClick,\n className,\n}: AddressDisplayUIProps) {\n if (address === undefined) {\n return (\n <LoadingCard\n text={loadingText}\n className={className}\n data-testid=\"address-display-loading\"\n />\n )\n }\n\n return (\n <Wrapper\n variant=\"ghost\"\n // Figma's 40% offWhite surface — none of Wrapper's white-only variants\n // hit this tint, so override the backgroundColor. Inline style wins\n // over Wrapper's own style prop.\n style={{ backgroundColor: 'rgba(247, 245, 240, 0.4)' }}\n className={cn(\n // Figma: rounded-[14px], pl-16 pr-8 py-8, gap-12 items-center.\n // Height pinned to 68px so the loading and ready variants swap without\n // the layout jumping.\n 'zd:relative zd:flex zd:h-[68px] zd:w-full zd:items-center zd:gap-3 zd:overflow-hidden zd:rounded-[14px] zd:pl-4 zd:pr-2 zd:py-2',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n data-testid=\"address-display-ready\"\n >\n <Text\n className=\"zd:min-w-0 zd:flex-1 zd:break-all zd:text-body2\"\n data-testid=\"address-display-address\"\n >\n {address}\n </Text>\n <button\n type=\"button\"\n onClick={onQrClick}\n aria-label=\"Show QR code\"\n className=\"zd:flex zd:w-13 zd:h-13 zd:shrink-0 zd:cursor-pointer zd:items-center zd:justify-center zd:rounded-2xl zd:bg-white\"\n data-testid=\"address-display-qr-button\"\n >\n <Icon name=\"qrCode\" className=\"zd:w-5 zd:h-5 zd:text-greyScale\" />\n </button>\n </Wrapper>\n )\n}\n\nexport interface AddressDisplayProps {\n /** Current address-generation state from the SRA context. */\n status: AddressState['status']\n /** Deposit address, present when `status === 'success'`. */\n address?: string | undefined\n /** Handler for the QR icon button (only meaningful once `address` resolves). */\n onQrClick?: (() => void) | undefined\n}\n\n/**\n * State-driven wrapper around `AddressDisplayUI`. Picks the right variant\n * (loading / ready) based on the SRA address-generation status; the parent\n * page renders `ErrorRetryCard` in the error case instead of this component.\n */\nexport function AddressDisplay({\n status,\n address,\n onQrClick,\n}: AddressDisplayProps) {\n if (status === 'error') return null\n if (status === 'success' && address !== undefined) {\n return <AddressDisplayUI address={address} onQrClick={onQrClick} />\n }\n return <AddressDisplayUI loadingText=\"Generating deposit address…\" />\n}\n","import { cn, Icon, Text } from '@zerodev/react-ui'\n\nexport interface ErrorRetryCardProps {\n /** Error copy shown on the left side, e.g. \"Failed to create deposit\n * address…\" — kept short (Figma design truncates on one line). */\n message: string\n /** Called when the user clicks the refresh affordance. */\n onRetry: () => void\n /** Marks the button as busy while a retry is in flight — disables clicks\n * and spins the icon so back-to-back taps don't stack requests. */\n busy?: boolean\n /** Accessible label for the icon-only refresh button. Defaults to \"Retry\". */\n retryLabel?: string\n className?: string\n}\n\n/**\n * Error banner with an inline retry affordance. Renders as a compact pill\n * matching the Figma spec (`bg-negative/10`, error-red text, right-hand\n * 52×52 refresh button). Used above the \"Min deposit\" row in the deposit UI\n * to surface address-creation, empty-route and polling failures.\n */\nexport function ErrorRetryCard({\n message,\n onRetry,\n busy,\n retryLabel = 'Retry',\n className,\n}: ErrorRetryCardProps) {\n return (\n <div\n role=\"alert\"\n className={cn(\n 'zd:relative zd:flex zd:w-full zd:items-center zd:justify-center zd:gap-3',\n 'zd:overflow-hidden zd:rounded-[14px] zd:border-[0.3px] zd:border-offWhite',\n 'zd:bg-negative/10 zd:backdrop-blur-[15px] zd:py-2 zd:pr-2 zd:pl-4',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n >\n <Text className=\"zd:flex-1 zd:min-w-0 zd:text-body1 zd:font-medium zd:text-negative\">\n {message}\n </Text>\n <button\n type=\"button\"\n onClick={onRetry}\n disabled={busy}\n aria-label={retryLabel}\n aria-busy={busy}\n className={cn(\n 'zd:inline-flex zd:h-[52px] zd:w-[52px] zd:shrink-0 zd:items-center zd:justify-center',\n 'zd:rounded-2xl zd:bg-negative/10 zd:text-negative zd:cursor-pointer',\n 'zd:transition-colors zd:hover:bg-negative/20',\n 'zd:disabled:cursor-not-allowed zd:disabled:opacity-50',\n )}\n >\n <Icon\n name=\"rotateRight\"\n className={cn(\n 'zd:h-6 zd:w-6 zd:text-negative',\n busy && 'zd:animate-spin',\n )}\n aria-hidden\n />\n </button>\n </div>\n )\n}\n","/**\n * Icon data URIs sourced from smart-routing-address-dashboard/public/icons\n * (raster images downscaled to 64px). Generated file - do not edit the\n * encoded strings by hand; regenerate from the dashboard assets instead.\n */\nimport {\n arbitrum,\n arbitrumSepolia,\n base,\n baseSepolia,\n blast,\n bsc,\n hyperEvm,\n ink,\n linea,\n mainnet,\n mode,\n monad,\n optimism,\n optimismSepolia,\n polygon,\n scroll,\n sepolia,\n soneium,\n tempo,\n unichain,\n worldchain,\n zora,\n} from 'viem/chains'\n\nconst CHAIN_ARBITRUM =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE2LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgd2lkdGg9IjQ3MC4yODdweCIgaGVpZ2h0PSI1MTQuMjUxcHgiIHZpZXdCb3g9IjAgMCA0NzAuMjg3IDUxNC4yNTEiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ3MC4yODcgNTE0LjI1MSIKCSB4bWw6c3BhY2U9InByZXNlcnZlIj4KPGcgaWQ9IkJhY2tncm91bmQiPgo8L2c+CjxnIGlkPSJMb2dvc19hbmRfc3ltYm9scyI+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8zIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzNfM18iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfNCI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl80XzFfIj4KCQk8ZyBpZD0iU1lNQk9MX1ZFUl80XzNfIj4KCQk8L2c+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl81XzFfIj4KCTwvZz4KCTxnIGlkPSJvZmZfMl8xXyI+Cgk8L2c+Cgk8ZyBpZD0iVkVSXzNfMV8iPgoJCTxnIGlkPSJTWU1CT0xfVkVSXzJfMV8iPgoJCTwvZz4KCTwvZz4KCTxnIGlkPSJWRVJfMyI+CgkJPGcgaWQ9IlNZTUJPTF9WRVJfMiI+CgkJPC9nPgoJPC9nPgoJPGcgaWQ9Im9mZl8yIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzUiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMSI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMV8zXyI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xLTFfMl8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMS0xIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMV8xXyI+CgkJPGcgaWQ9Il94MzFfLTMiPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMTRfIj4KCQkJPHBhdGggZmlsbD0iIzJEMzc0QiIgZD0iTTI5MS4xMzQsMjM3LjQ2OWwzNS42NTQtNjAuNWw5Ni4xMDMsMTQ5LjY4NGwwLjA0NiwyOC43MjdsLTAuMzEzLTE5Ny42NzIKCQkJCWMtMC4yMjgtNC44MzItMi43OTQtOS4yNTItNi44ODctMTEuODU5TDI0Mi43MTUsNDYuMzI0Yy00LjA0NS0xLjk5LTkuMTgtMS45NjctMTMuMjIsMC4wNjNjLTAuNTQ2LDAuMjcyLTEuMDYsMC41Ny0xLjU0OCwwLjg5NQoJCQkJbC0wLjYwNCwwLjM3OUw1OS4zOTksMTQ0Ljk4M2wtMC42NTEsMC4yOTZjLTAuODM4LDAuMzg1LTEuNjg2LDAuODc1LTIuNDgsMS40NDRjLTMuMTg1LDIuMjgzLTUuMjk5LDUuNjYtNS45ODMsOS40NDgKCQkJCWMtMC4xMDMsMC41NzQtMC4xNzksMS4xNTgtMC4yMTQsMS43NDlsMC4yNjQsMTYxLjA4M2w4OS41MTUtMTM4Ljc0NWMxMS4yNzEtMTguMzk3LDM1LjgyNS0yNC4zMjMsNTguNjItMjQuMDAxbDI2Ljc1MywwLjcwNgoJCQkJTDY3LjU4OCw0MDkuNzY1bDE4LjU4MiwxMC42OTdMMjQ1LjY5MiwxNTcuMjJsNzAuNTEtMC4yNTZMMTU3LjA5MSw0MjYuODQ5bDY2LjMwNiwzOC4xMzhsNy45MjIsNC41NTYKCQkJCWMzLjM1MSwxLjM2Miw3LjMwMiwxLjQzMSwxMC42ODEsMC4yMWwxNzUuNDUzLTEwMS42NzhsLTMzLjU0NCwxOS40MzhMMjkxLjEzNCwyMzcuNDY5eiBNMzA0LjczNiw0MzMuMzk1bC02Ni45NjktMTA1LjEwOAoJCQkJbDQwLjg4MS02OS4zNzFsODcuOTUyLDEzOC42MjhMMzA0LjczNiw0MzMuMzk1eiIvPgoJCQk8cG9seWdvbiBmaWxsPSIjMjhBMEYwIiBwb2ludHM9IjIzNy43NjgsMzI4LjI4NiAzMDQuNzM2LDQzMy4zOTUgMzY2LjYwMSwzOTcuNTQzIDI3OC42NDgsMjU4LjkxNSAJCQkiLz4KCQkJPHBhdGggZmlsbD0iIzI4QTBGMCIgZD0iTTQyMi45MzcsMzU1LjM3OWwtMC4wNDYtMjguNzI3bC05Ni4xMDMtMTQ5LjY4NGwtMzUuNjU0LDYwLjVsOTIuNzc0LDE1MC4wNDNsMzMuNTQ0LTE5LjQzOAoJCQkJYzMuMjktMi42NzMsNS4yODEtNi41OTQsNS40OS0xMC44MjVMNDIyLjkzNywzNTUuMzc5eiIvPgoJCQk8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMjAuMjE5LDM4Mi40NjlsNDcuMzY5LDI3LjI5NmwxNTcuNjM0LTI1Mi44MDFsLTI2Ljc1My0wLjcwNmMtMjIuNzk1LTAuMzIyLTQ3LjM1LDUuNjA0LTU4LjYyLDI0LjAwMQoJCQkJTDUwLjMzNCwzMTkuMDA0bC0zMC4xMTUsNDYuMjcxVjM4Mi40Njl6Ii8+CgkJCTxwb2x5Z29uIGZpbGw9IiNGRkZGRkYiIHBvaW50cz0iMzE2LjIwMiwxNTYuOTY0IDI0NS42OTIsMTU3LjIyIDg2LjE3LDQyMC40NjIgMTQxLjkyOCw0NTIuNTY1IDE1Ny4wOTEsNDI2Ljg0OSAJCQkiLz4KCQkJPHBhdGggZmlsbD0iIzk2QkVEQyIgZD0iTTQ1Mi42NSwxNTYuNjAxYy0wLjU5LTE0Ljc0Ni04LjU3NC0yOC4yNDUtMjEuMDgtMzYuMTA0TDI1Ni4yOCwxOS42OTIKCQkJCWMtMTIuMzcxLTYuMjI5LTI3LjgyNS02LjIzNy00MC4yMTgtMC4wMDRjLTEuNDY1LDAuNzM5LTE3MC40NjUsOTguNzUyLTE3MC40NjUsOTguNzUyYy0yLjMzOSwxLjEyMi00LjU5MiwyLjQ1OC02LjcxMSwzLjk3NQoJCQkJYy0xMS4xNjQsOC4wMDEtMTcuOTY5LDIwLjQzNS0xOC42NjgsMzQuMDk1djIwOC43NjVsMzAuMTE1LTQ2LjI3MUw1MC4wNywxNTcuOTIxYzAuMDM1LTAuNTg5LDAuMTA5LTEuMTY5LDAuMjE0LTEuNzQxCgkJCQljMC42ODEtMy43OSwyLjc5Ny03LjE3MSw1Ljk4My05LjQ1NmMwLjc5NS0wLjU2OSwxNzIuNjgyLTEwMC4wNjQsMTczLjIyOC0xMDAuMzM3YzQuMDQtMi4wMjksOS4xNzUtMi4wNTMsMTMuMjItMC4wNjMKCQkJCWwxNzMuMDIyLDk5LjUyM2M0LjA5MywyLjYwNyw2LjY1OSw3LjAyNyw2Ljg4NywxMS44NTl2MTk5LjU0MmMtMC4yMDksNC4yMzEtMS44ODIsOC4xNTItNS4xNzIsMTAuODI1bC0zMy41NDQsMTkuNDM4CgkJCQlsLTE3LjMwOCwxMC4wMzFsLTYxLjg2NCwzNS44NTJsLTYyLjczNywzNi4zNTdjLTMuMzc5LDEuMjIxLTcuMzMsMS4xNTItMTAuNjgxLTAuMjFsLTc0LjIyOC00Mi42OTNsLTE1LjE2MywyNS43MTcKCQkJCWw2Ni43MDYsMzguNDA2YzIuMjA2LDEuMjU1LDQuMTcxLDIuMzY3LDUuNzg0LDMuMjcyYzIuNDk3LDEuNCw0LjE5OSwyLjMzNyw0LjgsMi42MjljNC43NDEsMi4zMDMsMTEuNTYzLDMuNjQzLDE3LjcxLDMuNjQzCgkJCQljNS42MzYsMCwxMS4xMzItMS4wMzUsMTYuMzMyLTMuMDcybDE4Mi4yMjUtMTA1LjUzMWMxMC40NTktOC4xMDQsMTYuNjEyLTIwLjMyNSwxNy4xNjYtMzMuNTY0VjE1Ni42MDF6Ii8+CgkJPC9nPgoJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF8xM18iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfNl8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfNF8iPgoJCTwvZz4KCQk8ZyBpZD0iT25lX2NvbG9yX3ZlcnNpb25fLV9XaGl0ZV8zXyI+CgkJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF8xNV8iPgoJCQk8L2c+CgkJPC9nPgoJCTxnIGlkPSJPbmVfY29sb3JfdmVyc2lvbl8tX1doaXRlIj4KCQkJPGcgaWQ9IlN5bWJvbF8tX09yaWdpbmFsIj4KCQkJPC9nPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fTW9ub2Nocm9tYXRpY18zXyI+CgkJCTxnIGlkPSJfeDMzX183XyI+CgkJCTwvZz4KCQk8L2c+CgkJPGcgaWQ9IlN5bWJvbF8tX01vbm9jaHJvbWF0aWMiPgoJCQk8ZyBpZD0iX3gzM19fM18iPgoJCQk8L2c+CgkJPC9nPgoJCTxnIGlkPSJfeDMzX18yXyI+CgkJPC9nPgoJCTxnIGlkPSJfeDMzX18xXyI+CgkJPC9nPgoJCTxnIGlkPSJfeDMzXyI+CgkJPC9nPgoJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF8xMF8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMV8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMl8iPgoJCTwvZz4KCQk8ZyBpZD0iX3gzNF9fMV8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fTW9ub2Nocm9tYXRpY18yXyI+CgkJCTxnIGlkPSJfeDMzX182XyI+CgkJCTwvZz4KCQk8L2c+CgkJPGcgaWQ9Ik9uZV9jb2xvcl92ZXJzaW9uXy1fV2hpdGVfMl8iPgoJCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMTFfIj4KCQkJPC9nPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfNV8iPgoJCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMTJfIj4KCQkJPC9nPgoJCTwvZz4KCQk8ZyBpZD0iT25lX2NvbG9yX3ZlcnNpb25fLV9XaGl0ZV8xXyI+CgkJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF85XyI+CgkJCTwvZz4KCQk8L2c+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xXzJfIj4KCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yXzRfIj4KCQk8L2c+CgkJPGcgaWQ9IlNZTUJPTF9WRVJfMi0xLTFfMV8iPgoJCTwvZz4KCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yLTItMV8xXyI+CgkJPC9nPgoJCTxnIGlkPSJTWU1CT0xfVkVSXzItMy0xXzRfIj4KCQk8L2c+CgkJPGcgaWQ9Ik5ld19TeW1ib2xfMV8iPgoJCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yLTMtMV8zXyI+CgkJCTwvZz4KCQk8L2c+CgkJPGcgaWQ9Ik5ld19TeW1ib2wiPgoJCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yLTMtMV8xXyI+CgkJCTwvZz4KCQk8L2c+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8yXzJfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzRfMl8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfM18yXyI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8zXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMS0xXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMS0xIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMS0xXzJfMl8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMS0xLTFfMiI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xLTEtMV8yXzFfIj4KCTwvZz4KCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF83XyI+Cgk8L2c+Cgk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfOF8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMi0xLTEiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMi0yLTEiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMi0zLTEiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfNS0xXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzUtMSI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl81LTJfMV8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfNS0yIj4KCTwvZz4KCTxnIGlkPSJTeW1ib2xfLV9Nb25vY2hyb21hdGljXzFfIj4KCQk8ZyBpZD0iX3gzM19fNF8iPgoJCTwvZz4KCTwvZz4KPC9nPgo8L3N2Zz4K'\nconst CHAIN_BASE =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE2IDMyQzE5LjE2NDUgMzIgMjIuMjU3OSAzMS4wNjE2IDI0Ljg4OTEgMjkuMzAzNUMyNy41MjAzIDI3LjU0NTQgMjkuNTcxMSAyNS4wNDY2IDMwLjc4MjEgMjIuMTIyOUMzMS45OTMxIDE5LjE5OTMgMzIuMzA5OSAxNS45ODIzIDMxLjY5MjYgMTIuODc4NkMzMS4wNzUyIDkuNzc0ODYgMjkuNTUxMyA2LjkyMzk0IDI3LjMxMzcgNC42ODYzQzI1LjA3NjEgMi40NDg2NiAyMi4yMjUxIDAuOTI0ODA2IDE5LjEyMTQgMC4zMDc0NDNDMTYuMDE3NyAtMC4zMDk5MjEgMTIuODAwNyAwLjAwNjkzMjY1IDkuODc3MDYgMS4yMTc5M0M2Ljk1MzQ1IDIuNDI4OTQgNC40NTQ1OSA0LjQ3OTcgMi42OTY0OSA3LjExMDg4QzAuOTM4Mzg0IDkuNzQyMDcgMCAxMi44MzU1IDAgMTZDMCAyMC4yNDM1IDEuNjg1NzEgMjQuMzEzMSA0LjY4NjI5IDI3LjMxMzdDNy42ODY4NyAzMC4zMTQzIDExLjc1NjUgMzIgMTYgMzJaIiBmaWxsPSIjMDA1MkZGIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTUuOTYyNCAyNy4yNjc2QzIyLjE4NTMgMjcuMjY3NiAyNy4yMyAyMi4yMjMgMjcuMjMgMTZDMjcuMjMgOS43NzcxIDIyLjE4NTMgNC43MzI0MiAxNS45NjI0IDQuNzMyNDJDMTAuMDU4OCA0LjczMjQyIDUuMjE1NjIgOS4yNzI2MiA0LjczNDA5IDE1LjA1MThIMjEuNDU0NFYxNi45MjgxSDQuNzMyNDJDNS4yMDQzNSAyMi43MTY5IDEwLjA1MTkgMjcuMjY3NiAxNS45NjI0IDI3LjI2NzZaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K'\nconst CHAIN_BSC =\n 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAwLjAxIDI1MDAiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojZjNiYTJmO308L3N0eWxlPjwvZGVmcz48dGl0bGU+Ymk8L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNzY0LjQ4LDEwNTAuNTIsMTI1MCw1NjVsNDg1Ljc1LDQ4NS43MywyODIuNS0yODIuNUwxMjUwLDAsNDgyLDc2OGwyODIuNDksMjgyLjVNMCwxMjUwLDI4Mi41MSw5NjcuNDUsNTY1LDEyNDkuOTQsMjgyLjQ5LDE1MzIuNDVabTc2NC40OCwxOTkuNTFMMTI1MCwxOTM1bDQ4NS43NC00ODUuNzIsMjgyLjY1LDI4Mi4zNS0uMTQuMTVMMTI1MCwyNTAwLDQ4MiwxNzMybC0uNC0uNCwyODIuOTEtMjgyLjEyTTE5MzUsMTI1MC4xMmwyODIuNTEtMjgyLjUxTDI1MDAsMTI1MC4xLDIyMTcuNSwxNTMyLjYxWiIvPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTE1MzYuNTIsMTI0OS44NWguMTJMMTI1MCw5NjMuMTksMTAzOC4xMywxMTc1aDBsLTI0LjM0LDI0LjM1LTUwLjIsNTAuMjEtLjQuMzkuNC40MUwxMjUwLDE1MzYuODFsMjg2LjY2LTI4Ni42Ni4xNC0uMTYtLjI2LS4xNCIvPjwvZz48L2c+PC9zdmc+'\nconst CHAIN_ETHEREUM =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPCEtLSBDcmVhdG9yOiBDb3JlbERSQVcgMjAxOSAoNjQtQml0KSAtLT4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIxMCUiIGhlaWdodD0iMTAlIiB2ZXJzaW9uPSIxLjEiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiB0ZXh0LXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiCnZpZXdCb3g9IjAgMCA3ODQuMzcgMTI3Ny4zOSIKIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogeG1sbnM6eG9kbT0iaHR0cDovL3d3dy5jb3JlbC5jb20vY29yZWxkcmF3L29kbS8yMDAzIj4KIDxnIGlkPSJMYXllcl94MDAyMF8xIj4KICA8bWV0YWRhdGEgaWQ9IkNvcmVsQ29ycElEXzBDb3JlbC1MYXllciIvPgogIDxnIGlkPSJfMTQyMTM5NDM0MjQwMCI+CiAgIDxnPgogICAgPHBvbHlnb24gZmlsbD0iIzM0MzQzNCIgZmlsbC1ydWxlPSJub256ZXJvIiBwb2ludHM9IjM5Mi4wNywwIDM4My41LDI5LjExIDM4My41LDg3My43NCAzOTIuMDcsODgyLjI5IDc4NC4xMyw2NTAuNTQgIi8+CiAgICA8cG9seWdvbiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHBvaW50cz0iMzkyLjA3LDAgLTAsNjUwLjU0IDM5Mi4wNyw4ODIuMjkgMzkyLjA3LDQ3Mi4zMyAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiMzQzNDM0IiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIzOTIuMDcsOTU2LjUyIDM4Ny4yNCw5NjIuNDEgMzg3LjI0LDEyNjMuMjggMzkyLjA3LDEyNzcuMzggNzg0LjM3LDcyNC44OSAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiM4QzhDOEMiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIzOTIuMDcsMTI3Ny4zOCAzOTIuMDcsOTU2LjUyIC0wLDcyNC44OSAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiMxNDE0MTQiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIzOTIuMDcsODgyLjI5IDc4NC4xMyw2NTAuNTQgMzkyLjA3LDQ3Mi4zMyAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiMzOTM5MzkiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIwLDY1MC41NCAzOTIuMDcsODgyLjI5IDM5Mi4wNyw0NzIuMzMgIi8+CiAgIDwvZz4KICA8L2c+CiA8L2c+Cjwvc3ZnPgo='\nconst CHAIN_HYPERLIQUID =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xNDQgNzEuNjk5MUMxNDQgMTE5LjMwNiAxMTQuODY2IDEzNC41ODIgOTkuNTE1NiAxMjAuOThDODYuODgwNCAxMDkuODg5IDgzLjEyMTEgODYuNDUyMSA2NC4xMTYgODQuMDQ1NkMzOS45OTQyIDgxLjAxMTMgMzcuOTA1NyAxMTMuMTMzIDIyLjAzMzQgMTEzLjEzM0MzLjU1MDQgMTEzLjEzMyAwIDg2LjI0MjggMCA3Mi40MzE1QzAgNTguMzA2MyAzLjk2ODA5IDM5LjA1NDIgMTkuNzM2IDM5LjA1NDJDMzguMTE0NiAzOS4wNTQyIDM5LjE1ODggNjYuNTcyMiA2Mi4xMzIgNjUuMTA3M0M4NS4wMDA3IDYzLjUzNzkgODUuNDE4NCAzNC44Njg5IDEwMC4yNDcgMjIuNjI3MUMxMTMuMTk1IDEyLjA1OTMgMTQ0IDIzLjQ2NDEgMTQ0IDcxLjY5OTFaIiBmaWxsPSIjOTdGQ0U0Ii8+Cjwvc3ZnPgo='\nconst CHAIN_LINEA =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwOCIgdmlld0JveD0iMCAwIDIwMCAyMDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8yMzAzXzYzMikiPgo8cGF0aCBkPSJNMTMyLjM2OSAxNTUuOTlINDkuN1Y2OC44ODU0SDY4LjYxNDdWMTM5LjEwOUgxMzIuMzY5VjE1NS45ODFWMTU1Ljk5WiIgZmlsbD0iIzEyMTIxMiIvPgo8cGF0aCBkPSJNMTMyLjM2OSA4NS43NTc1QzE0MS42ODcgODUuNzU3NSAxNDkuMjQxIDc4LjIwMzYgMTQ5LjI0MSA2OC44ODU1QzE0OS4yNDEgNTkuNTY3MyAxNDEuNjg3IDUyLjAxMzQgMTMyLjM2OSA1Mi4wMTM0QzEyMy4wNSA1Mi4wMTM0IDExNS40OTcgNTkuNTY3MyAxMTUuNDk3IDY4Ljg4NTVDMTE1LjQ5NyA3OC4yMDM2IDEyMy4wNSA4NS43NTc1IDEzMi4zNjkgODUuNzU3NVoiIGZpbGw9IiMxMjEyMTIiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8yMzAzXzYzMiI+CjxyZWN0IHdpZHRoPSI5OS41NDA3IiBoZWlnaHQ9IjEwMy45NzciIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0OS43IDUyLjAxMzQpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg=='\nconst CHAIN_MONAD =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgyIiBoZWlnaHQ9IjE4NCIgdmlld0JveD0iMCAwIDE4MiAxODQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik05MC41MzU4IDBDNjQuMzkxMSAwIDAgNjUuMjU5OCAwIDkxLjc1OTNDMCAxMTguMjU5IDY0LjM5MTEgMTgzLjUyIDkwLjUzNTggMTgzLjUyQzExNi42ODEgMTgzLjUyIDE4MS4wNzMgMTE4LjI1OCAxODEuMDczIDkxLjc1OTNDMTgxLjA3MyA2NS4yNjA5IDExNi42ODIgMCA5MC41MzU4IDBaTTc2LjQyNzMgMTQ0LjIzQzY1LjQwMjQgMTQxLjE4NSAzNS43NjA4IDg4LjYzNCAzOC43NjU1IDc3LjQ1OTlDNDEuNzcwMyA2Ni4yODU0IDkzLjYyIDM2LjI0MzkgMTA0LjY0NSAzOS4yODkyQzExNS42NyA0Mi4zMzQxIDE0NS4zMTIgOTQuODg0NiAxNDIuMzA3IDEwNi4wNTlDMTM5LjMwMiAxMTcuMjM0IDg3LjQ1MjIgMTQ3LjI3NiA3Ni40MjczIDE0NC4yM1oiIGZpbGw9IiM2RTU0RkYiLz4KPC9zdmc+Cg=='\nconst CHAIN_OPTIMISM =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMTZDMTIuNDE4MyAxNiAxNiAxMi40MTgzIDE2IDhDMTYgMy41ODE3MiAxMi40MTgzIDAgOCAwQzMuNTgxNzIgMCAwIDMuNTgxNzIgMCA4QzAgMTIuNDE4MyAzLjU4MTcyIDE2IDggMTZaIiBmaWxsPSIjRkYwNDIwIi8+CjxwYXRoIGQ9Ik01LjY2NTY3IDEwLjEyMTZDNS4yNDk0MyAxMC4xMzkzIDQuODM4NyAxMC4wMjE0IDQuNDk1MzEgOS43ODU0NEM0LjM0Njk3IDkuNjcyMTQgNC4yMjg0NiA5LjUyNDQgNC4xNTAwNCA5LjM1NTAxQzQuMDcxNjEgOS4xODU2MSA0LjAzNTYzIDguOTk5NjcgNC4wNDUyMiA4LjgxMzI1QzQuMDQ3MDQgOC43MDQ2MiA0LjA1NzA4IDguNTk2MjkgNC4wNzUyNSA4LjQ4OTE4QzQuMTI3MjcgOC4yMDA2NSA0LjIwMTI4IDcuODU0NTYgNC4yOTcyOCA3LjQ1MDg4QzQuNTY5MzcgNi4zNTA1NiA1LjI3MTUzIDUuODAwMzkgNi40MDM3NyA1LjgwMDM5QzYuNjg3NTYgNS43OTU3NCA2Ljk2OTMzIDUuODQ4ODQgNy4yMzE5NyA1Ljk1NjQ2QzcuNDY1MSA2LjA0NzgzIDcuNjY1NjkgNi4yMDY2NCA3LjgwODEgNi40MTI1OUM3Ljk1MTcxIDYuNjI0NzkgOC4wMjUxIDYuODc2NzIgOC4wMTc5MyA3LjEzMjg1QzguMDE1ODggNy4yMzk0NiA4LjAwNTg0IDcuMzQ1NzcgNy45ODc5IDcuNDUwODhDNy45Mjc4NCA3LjgwNjk5IDcuODU1ODQgOC4xNTMwOSA3Ljc3MTkgOC40ODkxOEM3LjYzMjAxIDkuMDM3MjkgNy4zODk5NiA5LjQ0NzM5IDcuMDQ1NzQgOS43MTk0OEM2LjcwMTg3IDkuOTg3NTQgNi4yNDE4NSAxMC4xMjE2IDUuNjY1NjcgMTAuMTIxNlpNNS43NDk3NCA5LjI1NzMxQzUuOTU3NjEgOS4yNjMwNiA2LjE2MDQxIDkuMTkyNjMgNi4zMTk5NyA5LjA1OTI4QzYuNDk2MzEgOC44OTkzNSA2LjYxNjI4IDguNjg2NzQgNi42NjIgOC40NTMxMUM2Ljc1NDA3IDguMDc3MTYgNi44MjQwMSA3Ljc0OTA3IDYuODcxODQgNy40Njg4NUM2Ljg4Nzk0IDcuMzgzNzYgNi44OTU5NyA3LjI5NzM1IDYuODk1ODQgNy4yMTA3NUM2Ljg5NTg0IDYuODQ2NiA2LjcwNTgxIDYuNjY0NTcgNi4zMjU3NCA2LjY2NDY2QzYuMTE2MTkgNi42NTk2MyA1LjkxMTc4IDYuNzI5ODkgNS43NDk2MSA2Ljg2MjY5QzUuNTc2NTMgNy4wMjQzIDUuNDU4ODkgNy4yMzY0NCA1LjQxMzQ4IDcuNDY4ODVDNS4zNDE0MyA3LjczNjkyIDUuMjY5NDMgOC4wNjUwMSA1LjE5NzQ4IDguNDUzMTFDNS4xODExOSA4LjUzNjE0IDUuMTczMTUgOC42MjA1NyA1LjE3MzQ4IDguNzA1MThDNS4xNzM0OCA5LjA3MzI3IDUuMzY1NTcgOS4yNTczMSA1Ljc0OTc0IDkuMjU3MzFaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNOC4yOTQ0IDEwLjA2MTZDOC4yNzUzNCAxMC4wNjI3IDguMjU2MjcgMTAuMDU5NSA4LjIzODYgMTAuMDUyM0M4LjIyMDk0IDEwLjA0NSA4LjIwNTE0IDEwLjAzMzkgOC4xOTIzNyAxMC4wMTk3QzguMTcyNDEgOS45ODc0IDguMTY1OTUgOS45NDg1OCA4LjE3NDQgOS45MTE1OUw5LjAwMjYgNi4wMTA0OEM5LjAwOTkzIDUuOTY3NDMgOS4wMzMzOCA1LjkyODc5IDkuMDY4MTcgNS45MDI0MUM5LjEwMDM0IDUuODc1ODcgOS4xNDA1OCA1Ljg2MTA3IDkuMTgyMjcgNS44NjA0NUgxMC43Nzg3QzExLjE1NDYgNS44NDIgMTEuNTI3MiA1LjkzODI4IDExLjg0NzEgNi4xMzY1MUMxMS45Nzg2IDYuMjIyNjYgMTIuMDg1NCA2LjM0MTU4IDEyLjE1NjkgNi40ODE1NkMxMi4yMjg1IDYuNjIxNTQgMTIuMjYyNCA2Ljc3Nzc2IDEyLjI1NTIgNi45MzQ4MUMxMi4yNTQ2IDcuMDM5ODYgMTIuMjQyNSA3LjE0NDUyIDEyLjIxOTEgNy4yNDY5NEMxMi4xNTI5IDcuNjUxMzEgMTEuOTM2NCA4LjAxNTc1IDExLjYxMyA4LjI2NzI2QzExLjMxMjkgOC40ODczMyAxMC45MDA4IDguNTk3MzYgMTAuMzc2NiA4LjU5NzM2SDkuNTY2NTRMOS4yOTA0NyA5LjkxMTcyQzkuMjgzMTMgOS45NTQ3NyA5LjI1OTY4IDkuOTkzNCA5LjIyNDkgMTAuMDE5OEM5LjE5Mjc3IDEwLjA0NjMgOS4xNTI1OCAxMC4wNjExIDkuMTEwOTMgMTAuMDYxOEw4LjI5NDQgMTAuMDYxNlpNMTAuNDE5IDcuNzY4OTFDMTAuNTc2MyA3Ljc3MjM3IDEwLjczMDMgNy43MjM4OCAxMC44NTcyIDcuNjMwOTRDMTAuOTg3NyA3LjUzNTA1IDExLjA3NzcgNy4zOTM3NSAxMS4xMDkyIDcuMjM0ODdDMTEuMTIwNCA3LjE3NTQ4IDExLjEyNjQgNy4xMTUyMyAxMS4xMjcyIDcuMDU0ODFDMTEuMTMwNiA3LjAwNTk5IDExLjEyMzIgNi45NTcwMiAxMS4xMDU2IDYuOTExMzhDMTEuMDg4IDYuODY1NzMgMTEuMDYwNSA2LjgyNDUyIDExLjAyNTIgNi43OTA2OEMxMC45MjUgNi43MTY3MSAxMC44MDEgNi42ODI1IDEwLjY3NzEgNi42OTQ2N0g5Ljk1Njk2TDkuNzI4OSA3Ljc2ODkxSDEwLjQxOVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo='\nconst CHAIN_POLYGON =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzOC40IDMzLjUiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDM4LjQgMzMuNTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiM4MjQ3RTU7fQo8L3N0eWxlPgo8Zz4KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yOSwxMC4yYy0wLjctMC40LTEuNi0wLjQtMi40LDBMMjEsMTMuNWwtMy44LDIuMWwtNS41LDMuM2MtMC43LDAuNC0xLjYsMC40LTIuNCwwTDUsMTYuMwoJCWMtMC43LTAuNC0xLjItMS4yLTEuMi0yLjF2LTVjMC0wLjgsMC40LTEuNiwxLjItMi4xbDQuMy0yLjVjMC43LTAuNCwxLjYtMC40LDIuNCwwTDE2LDcuMmMwLjcsMC40LDEuMiwxLjIsMS4yLDIuMXYzLjNsMy44LTIuMlY3CgkJYzAtMC44LTAuNC0xLjYtMS4yLTIuMWwtOC00LjdjLTAuNy0wLjQtMS42LTAuNC0yLjQsMEwxLjIsNUMwLjQsNS40LDAsNi4yLDAsN3Y5LjRjMCwwLjgsMC40LDEuNiwxLjIsMi4xbDguMSw0LjcKCQljMC43LDAuNCwxLjYsMC40LDIuNCwwbDUuNS0zLjJsMy44LTIuMmw1LjUtMy4yYzAuNy0wLjQsMS42LTAuNCwyLjQsMGw0LjMsMi41YzAuNywwLjQsMS4yLDEuMiwxLjIsMi4xdjVjMCwwLjgtMC40LDEuNi0xLjIsMi4xCgkJTDI5LDI4LjhjLTAuNywwLjQtMS42LDAuNC0yLjQsMGwtNC4zLTIuNWMtMC43LTAuNC0xLjItMS4yLTEuMi0yLjFWMjFsLTMuOCwyLjJ2My4zYzAsMC44LDAuNCwxLjYsMS4yLDIuMWw4LjEsNC43CgkJYzAuNywwLjQsMS42LDAuNCwyLjQsMGw4LjEtNC43YzAuNy0wLjQsMS4yLTEuMiwxLjItMi4xVjE3YzAtMC44LTAuNC0xLjYtMS4yLTIuMUwyOSwxMC4yeiIvPgo8L2c+Cjwvc3ZnPgo='\nconst CHAIN_SCROLL =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI4LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA0NDQgNDQ0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NDQgNDQ0OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0ZGRUVEQTt9Cgkuc3Qxe2ZpbGw6I0VCQzI4RTt9Cgkuc3Qye2ZpbGw6IzEwMTAxMDt9Cjwvc3R5bGU+CjxnPgoJPHJlY3QgY2xhc3M9InN0MCIgd2lkdGg9IjQ0NCIgaGVpZ2h0PSI0NDQiLz4KCTxnPgoJCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0zMzMuNCwyNjJWMTEwLjZjLTAuMi0xMi43LTEwLjMtMjIuOS0yMy0yMi45aC0xNThjLTM0LjEsMC41LTYxLjUsMjguNC02MS41LDYyLjZjMCwxMS41LDMuMSwyMS40LDcuOCwzMC4xCgkJCWM0LDcuMiwxMC4zLDE0LDE2LjUsMTkuMWMxLjgsMS40LDAuOSwwLjgsNi4zLDQuMWM3LjQsNC41LDE1LjksNi44LDE1LjksNi44bC0wLjEsOTAuNmMwLjIsNC4zLDAuNiw4LjQsMS44LDEyLjMKCQkJYzMuNSwxMi44LDEyLjQsMjIuNiwyNC40LDI3LjNjNSwyLDEwLjcsMy4zLDE2LjgsMy40bDEyNi4yLDAuNGMyNS4xLDAsNDUuNS0yMC40LDQ1LjUtNDUuNkMzNTIuMSwyODMuOCwzNDQuNiwyNzAuNCwzMzMuNCwyNjJ6IgoJCQkvPgoJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0zMzYuNSwyOTkuOUMzMzYsMzE2LDMyMi43LDMyOSwzMDYuNCwzMjlsLTg2LjgtMC4zYzYuOS04LDExLjEtMTguNCwxMS4xLTI5LjhjMC0xNy44LTEwLjYtMzAuMS0xMC42LTMwLjEKCQkJaDg2LjRjMTYuNiwwLDMwLjEsMTMuNSwzMC4xLDMwLjFMMzM2LjUsMjk5Ljl6Ii8+CgkJPHBhdGggY2xhc3M9InN0MiIgZD0iTTEyMy41LDE4Ni43Yy0xMC05LjUtMTctMjEuNy0xNy0zNi4zdi0xLjVjMC44LTI0LjgsMjEuMi00NC44LDQ2LTQ1LjVoMTU4YzQuMSwwLjIsNy40LDMuMSw3LjQsNy4zdjEzMy43CgkJCWMzLjYsMC42LDUuNCwxLjEsOC45LDIuNGMyLjgsMSw2LjYsMy4yLDYuNiwzLjJWMTEwLjdjLTAuMi0xMi43LTEwLjMtMjIuOS0yMy0yMi45aC0xNThjLTM0LjEsMC41LTYxLjUsMjguNC02MS41LDYyLjYKCQkJYzAsMTkuOSw5LjEsMzYuOSwyMy45LDQ4LjhjMSwwLjgsMiwxLjksNC42LDEuOWM0LjYsMCw3LjktMy43LDcuNy03LjdDMTI3LjEsMTkwLDEyNS42LDE4OC44LDEyMy41LDE4Ni43eiIvPgoJCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0zMDYuNCwyNTMuMkgxODIuNWMtOC4zLDAuMS0xNSw2LjgtMTUsMTUuMXYxNy44YzAuMiw4LjIsNy4yLDE1LjIsMTUuNiwxNS4yaDkuMnYtMTUuMkgxODN2LTE3LjQKCQkJYzAsMCwyLjMsMCw1LDBjMTUuNywwLDI3LjIsMTQuNSwyNy4yLDMwLjFjMCwxMy44LTEyLjYsMzEuNC0zMy42LDMwYy0xOC42LTEuMi0yOC43LTE3LjgtMjguNy0zMHYtMTUxYzAtNi44LTUuNi0xMi40LTEyLjQtMTIuNAoJCQloLTEyLjR2MTUuNWg5LjJ2MTQ4Yy0wLjUsMzAuMSwyMS40LDQ1LjIsNDQuMyw0NS4ybDEyNC45LDAuNGMyNS4xLDAsNDUuNS0yMC40LDQ1LjUtNDUuNkMzNTIuMSwyNzMuNywzMzEuNiwyNTMuMiwzMDYuNCwyNTMuMnoKCQkJIE0zMzYuNSwyOTkuOUMzMzYsMzE2LDMyMi43LDMyOSwzMDYuNCwzMjlsLTg2LjgtMC4zYzYuOS04LDExLjEtMTguNCwxMS4xLTI5LjhjMC0xNy44LTEwLjYtMzAuMS0xMC42LTMwLjFoODYuNAoJCQljMTYuNiwwLDMwLjEsMTMuNSwzMC4xLDMwLjFMMzM2LjUsMjk5Ljl6Ii8+CgkJPHBhdGggY2xhc3M9InN0MiIgZD0iTTI3MywxNTMuN2gtOTMuNHYtMTUuNUgyNzNjNC4yLDAsNy43LDMuNCw3LjcsNy43QzI4MC44LDE1MC4yLDI3Ny40LDE1My43LDI3MywxNTMuN3oiLz4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJNMjczLDIyNi40aC05My40VjIxMUgyNzNjNC4yLDAsNy43LDMuNCw3LjcsNy43QzI4MC44LDIyMi45LDI3Ny40LDIyNi40LDI3MywyMjYuNHoiLz4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJNMjg5LjUsMTkwSDE3OS42di0xNS41aDEwOS44YzQuMiwwLDcuNywzLjQsNy43LDcuN0MyOTcuMywxODYuNSwyOTMuOCwxOTAsMjg5LjUsMTkweiIvPgoJPC9nPgo8L2c+Cjwvc3ZnPgo='\nconst CHAIN_SONEIUM =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgxIiBoZWlnaHQ9IjE4MSIgdmlld0JveD0iMCAwIDE4MSAxODEiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9IjAuMTI1IiB5PSIwLjE0OTY1OCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxODAuMDAzIiByeD0iOTAiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik05OS4wMTkgMTI3LjgyNUM4Ni4zMjUyIDEzMC44NDEgNzIuNDAzOCAxMjcuNCA2Mi41MDQxIDExNy40OTVDNDkuNzA1NCAxMDQuNjk4IDQ3LjIwNzMgODUuNzA4MyA1Ni40NTMyIDcwLjY2NkM2MC4yNzEzIDY0LjQ1NTQgNjMuODk4MSA2MC43NDI3IDY3LjAzMTUgNTcuNjIyQzc5Ljk0NzQgNDQuNzU2OCAxMDMuNjcgMjEuMzM5MSAxMDMuNjcgMjEuMzM5MUM4MS41MjAyIDE2Ljk1NDEgNTcuNjYyMiAyMy4zMzc0IDQwLjUwMjYgNDAuNTAxMkMxMy4xNjU4IDY3LjgzNTIgMTMuMTY1OCAxMTIuMTYgNDAuNTAyNiAxMzkuNDk0QzQ4Ljk3NzUgMTQ3Ljk2OCA1OS4wODA4IDE1My44MDkgNjkuODEzMyAxNTcuMDM0TDk5LjAyNTIgMTI3LjgyNUg5OS4wMTlaIiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNODAuOTgyNyA1Mi4xN0M5My42NzY2IDQ5LjE1NDEgMTA3LjU5OCA1Mi41OTU1IDExNy40OTggNjIuNTAwNEMxMzAuMjk2IDc1LjI5NzcgMTMyLjc5NCA5NC4yODcyIDEyMy41NDkgMTA5LjMyOUMxMTkuNzMxIDExNS41NCAxMTYuMTA0IDExOS4yNTMgMTEyLjk3IDEyMi4zNzRDMTAwLjA1NCAxMzUuMjM5IDc2LjMzMiAxNTguNjU2IDc2LjMzMiAxNTguNjU2Qzk4LjQ4MTUgMTYzLjA0MSAxMjIuMzQgMTU2LjY1OCAxMzkuNDk5IDEzOS40OTRDMTY2LjgzNiAxMTIuMTYgMTY2LjgzNiA2Ny44MzUyIDEzOS40OTkgNDAuNTAxM0MxMzEuMDI0IDMyLjAyNzMgMTIwLjkyMSAyNi4xODY3IDExMC4xODkgMjIuOTYxMkw4MC45NzY2IDUyLjE3SDgwLjk4MjdaIiBmaWxsPSJibGFjayIvPgo8L3N2Zz4K'\nconst CHAIN_UNICHAIN =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjU3IiBoZWlnaHQ9IjI1NiIgdmlld0JveD0iMCAwIDI1NyAyNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLjUpIiBmaWxsPSJ1cmwoI3BhaW50MF9yYWRpYWxfMTI0Nl8yNzQ3KSIvPgo8cGF0aCBkPSJNMjM0LjY4NCAxMjUuOThDMTc3LjEyOSAxMjUuOTggMTMwLjUyIDc5LjMyNDUgMTMwLjUyIDIxLjgxNTlIMTI2LjQ4VjEyNS45OEgyMi4zMTU5VjEzMC4wMkM3OS44NzE0IDEzMC4wMiAxMjYuNDggMTc2LjY3NSAxMjYuNDggMjM0LjE4NEgxMzAuNTJWMTMwLjAySDIzNC42ODRWMTI1Ljk4WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF8xMjQ2XzI3NDciIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI4IDEyOCkgcm90YXRlKDkwKSBzY2FsZSgxMjgpIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZDNzRGRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGNTBEQjQiLz4KPC9yYWRpYWxHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K'\nconst CHAIN_WORLDCHAIN =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmlld0JveD0iMCAwIDYwMC4xMDYzMiA2MDAuMTA2MzIiCiAgIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmcxMSIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMSI+CiAgICA8Y2xpcFBhdGgKICAgICAgIGlkPSJfX2xvdHRpZV9lbGVtZW50XzIiPgogICAgICA8cmVjdAogICAgICAgICB3aWR0aD0iODAwIgogICAgICAgICBoZWlnaHQ9IjgwMCIKICAgICAgICAgeD0iMCIKICAgICAgICAgeT0iMCIKICAgICAgICAgaWQ9InJlY3QxIiAvPgogICAgPC9jbGlwUGF0aD4KICAgIDxjbGlwUGF0aAogICAgICAgaWQ9Il9fbG90dGllX2VsZW1lbnRfNCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIEggMTcyOCBWIDE3MjggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgPC9kZWZzPgogIDxnCiAgICAgY2xpcC1wYXRoPSJ1cmwoI19fbG90dGllX2VsZW1lbnRfMikiCiAgICAgaWQ9ImcxMSIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtOTkuNjg5ODc1LC05OS45NDcwNjgpIj4KICAgIDxnCiAgICAgICBjbGlwLXBhdGg9InVybCgjX19sb3R0aWVfZWxlbWVudF80KSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjM2NzAwMSwwLDAsMS4yMzY3MDAxLC02NjguMjk5OCwtNjY4LjUwODc5KSIKICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICBzdHlsZT0iZGlzcGxheTpibG9jayIKICAgICAgIGlkPSJnMTAiPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjI5OTQ2OTksMCwwLDEuMjk5NDY5OSw3MjUuMzE0OTQsNzI3Ljg5MzY4KSIKICAgICAgICAgb3BhY2l0eT0iMSIKICAgICAgICAgc3R5bGU9ImRpc3BsYXk6YmxvY2siCiAgICAgICAgIGlkPSJnMyI+CiAgICAgICAgPGcKICAgICAgICAgICBvcGFjaXR5PSIxIgogICAgICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEzMS4xNzk5OSwxMDQuNzQpIgogICAgICAgICAgIGlkPSJnMiI+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogICAgICAgICAgICAgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIKICAgICAgICAgICAgIGZpbGwtb3BhY2l0eT0iMCIKICAgICAgICAgICAgIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIKICAgICAgICAgICAgIHN0cm9rZT0iIzAwMDAwMCIKICAgICAgICAgICAgIHN0cm9rZS1vcGFjaXR5PSIxIgogICAgICAgICAgICAgc3Ryb2tlLXdpZHRoPSIzNXB4IgogICAgICAgICAgICAgZD0ibSAxMTkuMDY3LC04Ny40NzAwMDEgYyAwLDAgLTE0NS41MDcwMDEsMC4yMzAwMDMgLTE0NS41MDcwMDEsMC4yMzAwMDMgQyAtNzQuNjIwMDAzLC04Ny4yMzk5OTggLTExMy42OCwtNDguMTggLTExMy42OCwwIGMgMCw0OC4xOCAzOS4wNTk5OTcsODcuMjM5OTk4IDg3LjIzOTk5OSw4Ny4yMzk5OTggMCwwIDE0MC4xMjAwMDEsMCAxNDAuMTIwMDAxLDAiCiAgICAgICAgICAgICBpZD0icGF0aDIiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICAgIDxnCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjk5NDY5OSwwLDAsMS4yOTk0Njk5LDY0My43Mzk4Nyw4NDEuMjU5MjgpIgogICAgICAgICBvcGFjaXR5PSIxIgogICAgICAgICBzdHlsZT0iZGlzcGxheTpibG9jayIKICAgICAgICAgaWQ9Imc1Ij4KICAgICAgICA8ZwogICAgICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICAgICAgaWQ9Imc0Ij4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgICAgICAgICAgICBzdHJva2UtbGluZWpvaW49Im1pdGVyIgogICAgICAgICAgICAgZmlsbC1vcGFjaXR5PSIwIgogICAgICAgICAgICAgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIgogICAgICAgICAgICAgc3Ryb2tlPSIjMDAwMDAwIgogICAgICAgICAgICAgc3Ryb2tlLW9wYWNpdHk9IjEiCiAgICAgICAgICAgICBzdHJva2Utd2lkdGg9IjM1cHgiCiAgICAgICAgICAgICBkPSJtIDIuMzA5LDE3LjUgYyAwLDAgMzM2LjExMTAxLDAgMzM2LjExMTAxLDAiCiAgICAgICAgICAgICBpZD0icGF0aDMiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICAgIDxnCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjk5NDY5OSwwLDAsMS4yOTk0Njk5LDYyMC45OTkxNSw2MjEuMzc2MSkiCiAgICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmJsb2NrIgogICAgICAgICBpZD0iZzciPgogICAgICAgIDxnCiAgICAgICAgICAgb3BhY2l0eT0iMSIKICAgICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxODYuNzEwMDEsMTg2LjcxMDAxKSIKICAgICAgICAgICBpZD0iZzYiPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICAgICAgICAgICAgIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiCiAgICAgICAgICAgICBmaWxsLW9wYWNpdHk9IjAiCiAgICAgICAgICAgICBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiCiAgICAgICAgICAgICBzdHJva2U9IiMwMDAwMDAiCiAgICAgICAgICAgICBzdHJva2Utb3BhY2l0eT0iMSIKICAgICAgICAgICAgIHN0cm9rZS13aWR0aD0iMzVweCIKICAgICAgICAgICAgIGQ9Ik0gMCwtMTY5LjIxMDAxIEMgOTMuNDUyMDAzLC0xNjkuMjEwMDEgMTY5LjIxMDAxLC05My40NTIwMDMgMTY5LjIxMDAxLDAgMTY5LjIxMDAxLDkzLjQ1MjAwMyA5My40NTIwMDMsMTY5LjIxMDAxIDAsMTY5LjIxMDAxIC05My40NTIwMDMsMTY5LjIxMDAxIC0xNjkuMjEwMDEsOTMuNDUyMDAzIC0xNjkuMjEwMDEsMCAtMTY5LjIxMDAxLC05My40NTIwMDMgLTkzLjQ1MjAwMywtMTY5LjIxMDAxIDAsLTE2OS4yMTAwMSBaIgogICAgICAgICAgICAgaWQ9InBhdGg1IiAvPgogICAgICAgIDwvZz4KICAgICAgPC9nPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjI5OTQ2OTksMCwwLDEuMjk5NDY5OSw2MjEuNDk5MTUsNjIxLjM3NjEpIgogICAgICAgICBvcGFjaXR5PSIxIgogICAgICAgICBzdHlsZT0iZGlzcGxheTpibG9jayIKICAgICAgICAgaWQ9Imc5Ij4KICAgICAgICA8ZwogICAgICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTg2LjcxMDAxLDE4Ni43MTAwMSkiCiAgICAgICAgICAgaWQ9Imc4Ij4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgICAgICAgICAgICBzdHJva2UtbGluZWpvaW49Im1pdGVyIgogICAgICAgICAgICAgZmlsbC1vcGFjaXR5PSIwIgogICAgICAgICAgICAgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIgogICAgICAgICAgICAgc3Ryb2tlPSIjMDAwMDAwIgogICAgICAgICAgICAgc3Ryb2tlLW9wYWNpdHk9IjEiCiAgICAgICAgICAgICBzdHJva2Utd2lkdGg9IjM1cHgiCiAgICAgICAgICAgICBkPSJNIDAsMCIKICAgICAgICAgICAgIGlkPSJwYXRoNyIgLz4KICAgICAgICA8L2c+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo='\nconst CHAIN_BLAST =\n 'data:image/png;base64,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'\nconst CHAIN_INK =\n 'data:image/png;base64,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'\nconst CHAIN_MODE =\n 'data:image/png;base64,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'\nconst CHAIN_TEMPO =\n 'data:image/png;base64,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'\nconst CHAIN_ZORA =\n 'data:image/png;base64,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'\nconst TOKEN_ETH =\n 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzIgMzIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxjaXJjbGUgY3g9IjE2IiBjeT0iMTYiIHI9IjE2IiBmaWxsPSIjNjI3RUVBIi8+PGcgZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIj48cGF0aCBmaWxsLW9wYWNpdHk9Ii42MDIiIGQ9Ik0xNi40OTggNHY4Ljg3bDcuNDk3IDMuMzV6Ii8+PHBhdGggZD0iTTE2LjQ5OCA0TDkgMTYuMjJsNy40OTgtMy4zNXoiLz48cGF0aCBmaWxsLW9wYWNpdHk9Ii42MDIiIGQ9Ik0xNi40OTggMjEuOTY4djYuMDI3TDI0IDE3LjYxNnoiLz48cGF0aCBkPSJNMTYuNDk4IDI3Ljk5NXYtNi4wMjhMOSAxNy42MTZ6Ii8+PHBhdGggZmlsbC1vcGFjaXR5PSIuMiIgZD0iTTE2LjQ5OCAyMC41NzNsNy40OTctNC4zNTMtNy40OTctMy4zNDh6Ii8+PHBhdGggZmlsbC1vcGFjaXR5PSIuNjAyIiBkPSJNOSAxNi4yMmw3LjQ5OCA0LjM1M3YtNy43MDF6Ii8+PC9nPjwvZz48L3N2Zz4='\nconst TOKEN_EURC =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzM4NTNfMjE1NjIpIj4KPHBhdGggZD0iTTQ4IDk2Qzc0LjUwOTcgOTYgOTYgNzQuNTA5NyA5NiA0OEM5NiAyMS40OTAzIDc0LjUwOTcgMCA0OCAwQzIxLjQ5MDMgMCAwIDIxLjQ5MDMgMCA0OEMwIDc0LjUwOTcgMjEuNDkwMyA5NiA0OCA5NloiIGZpbGw9IiMwQjUzQkYiLz4KPHBhdGggZD0iTTU4LjIgNTkuNDMwNUM1Ni4xIDYwLjI3MDUgNTMuODIgNjAuNzUwNSA1MS42MyA2MC43NTA1QzQ3LjI5MjkgNjAuNzUwNSA0My4yMDM5IDU4LjkwMzQgNDEuMjUgNTQuNDUwNUg1MC43OUw1Mi42NSA0OS45NTA1SDQwLjEzOTdDNDAuMDgwNiA0OS4zMzA3IDQwLjA1IDQ4LjY4MTIgNDAuMDUgNDguMDAwNUM0MC4wNSA0Ny4zMTk4IDQwLjA4MDYgNDYuNjcwMyA0MC4xMzk3IDQ2LjA1MDVINTQuMjRMNTYuMSA0MS41NTA1SDQxLjI1QzQzLjIwMzkgMzcuMDk3NiA0Ny4yOTI5IDM1LjI1MDUgNTEuNjMgMzUuMjUwNUM1My44MiAzNS4yNTA1IDU2LjEgMzUuNzMwNSA1OC4yIDM2LjU3MDVMNjAuMTIgMzIuMDEwNUM1Ny41NCAzMC42NjA1IDU0LjYzIDMwLjAwMDUgNTEuNzIgMzAuMDAwNUM0NC42OTY0IDMwLjAwMDUgMzcuNTk2NiAzMy45MjcyIDM1LjAyNjUgNDEuNTUwNUgzMC40MlY0Ni4wNTA1SDM0LjEwMzdDMzQuMDQ4OCA0Ni42ODIzIDM0LjAyIDQ3LjMzMjQgMzQuMDIgNDguMDAwNUMzNC4wMiA0OC42Njg2IDM0LjA0ODUgNDkuMzE4NyAzNC4xMDM3IDQ5Ljk1MDVIMzAuNDJWNTQuNDUwNUgzNS4wMjY1QzM3LjU5NjYgNjIuMDczOCA0NC42OTY0IDY2LjAwMDUgNTEuNzIgNjYuMDAwNUM1NC42MyA2Ni4wMDA1IDU3LjU0IDY1LjM0MDUgNjAuMTIgNjMuOTkwNUw1OC4yIDU5LjQzMDVaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMEI1M0JGIiBzdHJva2Utd2lkdGg9IjAuMDMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNMTggNDguMDAwM0MxOCAzNC40MTAzIDI3LjAzIDIyLjk1MDMgMzkuMzYgMTkuMjMwM1YxMy4wNTAzQzIzLjY0IDE2Ljg5MDMgMTIgMzEuMDgwMyAxMiA0OC4wMDAzQzEyIDY0LjkyMDMgMjMuNjQgNzkuMTEwMyAzOS4zNiA4Mi45NTAzVjc2Ljc3MDNDMjcuMDMgNzMuMDgwMyAxOCA2MS41OTAzIDE4IDQ4LjAwMDNaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMEI1M0JGIiBzdHJva2Utd2lkdGg9IjAuMDMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNNTYuNjQgMTMuMDUwM1YxOS4yMzAzQzY4Ljk3IDIyLjk1MDMgNzggMzQuNDEwMyA3OCA0OC4wMDAzQzc4IDYxLjU5MDMgNjguOTcgNzMuMDUwMyA1Ni42NCA3Ni43NzAzVjgyLjk1MDNDNzIuMzYgNzkuMTEwMyA4NCA2NC45MjAzIDg0IDQ4LjAwMDNDODQgMzEuMDgwMyA3Mi4zNiAxNi44OTAzIDU2LjY0IDEzLjA1MDNaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMEI1M0JGIiBzdHJva2Utd2lkdGg9IjAuMDMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzM4NTNfMjE1NjIiPgo8cmVjdCB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg=='\nconst TOKEN_WBTC =\n 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDkuMjYgMTA5LjI2Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6IzVhNTU2NDt9LmNscy0ye2ZpbGw6I2YwOTI0Mjt9LmNscy0ze2ZpbGw6IzI4MjEzODt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPndyYXBwZWQtYml0Y29pbi13YnRjPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iTGF5ZXJfMS0yIiBkYXRhLW5hbWU9IkxheWVyIDEiPjxnIGlkPSJQYWdlLTEiPjxnIGlkPSJ3YnRjX2NvbG91ciIgZGF0YS1uYW1lPSJ3YnRjIGNvbG91ciI+PHBhdGggaWQ9IlNoYXBlIiBjbGFzcz0iY2xzLTEiIGQ9Ik04OS4wOSwyMi45M2wtMywzYTQyLjQ3LDQyLjQ3LDAsMCwxLDAsNTcuMzJsMywzYTQ2Ljc2LDQ2Ljc2LDAsMCwwLDAtNjMuMzlaIi8+PHBhdGggaWQ9IlNoYXBlLTIiIGRhdGEtbmFtZT0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTTI2LDIzLjE5YTQyLjQ3LDQyLjQ3LDAsMCwxLDU3LjMyLDBsMy0zYTQ2Ljc2LDQ2Ljc2LDAsMCwwLTYzLjM5LDBaIi8+PHBhdGggaWQ9IlNoYXBlLTMiIGRhdGEtbmFtZT0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTTIzLjE5LDgzLjI4YTQyLjQ3LDQyLjQ3LDAsMCwxLDAtNTcuMjlsLTMtM2E0Ni43Niw0Ni43NiwwLDAsMCwwLDYzLjM5WiIvPjxwYXRoIGlkPSJTaGFwZS00IiBkYXRhLW5hbWU9IlNoYXBlIiBjbGFzcz0iY2xzLTEiIGQ9Ik04My4yOCw4Ni4wNWE0Mi40Nyw0Mi40NywwLDAsMS01Ny4zMiwwbC0zLDNhNDYuNzYsNDYuNzYsMCwwLDAsNjMuMzksMFoiLz48cGF0aCBpZD0iU2hhcGUtNSIgZGF0YS1uYW1lPSJTaGFwZSIgY2xhc3M9ImNscy0yIiBkPSJNNzMuNTcsNDQuNjJjLS42LTYuMjYtNi04LjM2LTEyLjgzLTlWMjdINTUuNDZ2OC40NmMtMS4zOSwwLTIuODEsMC00LjIyLDBWMjdINDZ2OC42OEgzNS4yOXY1LjY1czMuOS0uMDcsMy44NCwwYTIuNzMsMi43MywwLDAsMSwzLDIuMzJWNjcuNDFhMS44NSwxLjg1LDAsMCwxLS42NCwxLjI5LDEuODMsMS44MywwLDAsMS0xLjM2LjQ2Yy4wNy4wNi0zLjg0LDAtMy44NCwwbC0xLDYuMzFINDUuOXY4LjgyaDUuMjhWNzUuNkg1NS40djguNjVoNS4yOVY3NS41M2M4LjkyLS41NCwxNS4xNC0yLjc0LDE1LjkyLTExLjA5LjYzLTYuNzItMi41My05LjcyLTcuNTgtMTAuOTNDNzIuMSw1Miw3NCw0OS4yLDczLjU3LDQ0LjYyWk02Ni4xNyw2My40YzAsNi41Ni0xMS4yNCw1LjgxLTE0LjgyLDUuODFWNTcuNTdDNTQuOTMsNTcuNTgsNjYuMTcsNTYuNTUsNjYuMTcsNjMuNFpNNjMuNzIsNDdjMCw2LTkuMzgsNS4yNy0xMi4zNiw1LjI3VjQxLjY5QzU0LjM0LDQxLjY5LDYzLjcyLDQwLjc1LDYzLjcyLDQ3WiIvPjxwYXRoIGlkPSJTaGFwZS02IiBkYXRhLW5hbWU9IlNoYXBlIiBjbGFzcz0iY2xzLTMiIGQ9Ik01NC42MiwxMDkuMjZhNTQuNjMsNTQuNjMsMCwxLDEsNTQuNjQtNTQuNjRBNTQuNjMsNTQuNjMsMCwwLDEsNTQuNjIsMTA5LjI2Wm0wLTEwNUE1MC4zNCw1MC4zNCwwLDEsMCwxMDUsNTQuNjIsNTAuMzQsNTAuMzQsMCwwLDAsNTQuNjIsNC4yNloiLz48L2c+PC9nPjwvZz48L2c+PC9zdmc+'\nconst TOKEN_DAI =\n 'data:image/png;base64,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'\nconst TOKEN_USDC =\n 'data:image/png;base64,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'\nconst TOKEN_USDT =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAAABaAAAAAAAAAEgAAAABAAAASAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAAC1ay+zAAAACXBIWXMAAAsTAAALEwEAmpwYAAACyGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzI8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj44MDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+ODA8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KOIVP2AAAEIZJREFUeAHlW3mQHFd5/15fMzuzu6O9dFg2kowl+QBHjikJiKuSMnEQ5QopSMl/BCwfRSwbqhKqgssECzQCccWkihQk4OCE+MhRGJNUqihjqmKrYsWJVXaMFeNDWqwVRveutLOruXq6++X3ez295+zsjHYlhHhbvdP9+vX3vt93ve+9fq1k8YoypDT+K+F/ufaBT2XDftUV2KmrlaM2RpF1jejgciVqQGvpER0tYWMcBWXJKS36pCjnTcuKfqoDvdcJq6/aw3p8371fK5IeqOJRcxZfTZye/ckkuYXQmAG6nPPWqqx9g6XUjVGgN4qlL7FcF8wrrSPAxKGiUOkwMr0q2xJt2VpZaIJDtFZRraYlUkcsR+2NtH5aF8M9HQX/QANhGGGfLfsLEsCWLVvsxx9/PGTnq76zfY3n6j+00t5miaLrAWoJ7SAKcDsMNDBNMqo0REFt1ruHOWhazZQ2aKDEdpTl2MZIIKxRsawXo4r/I99STxzauusg+53KA6/bLWcnADLPAqaXPfKpbC7y7rY6UrcB5dWos3UAzQZRBE2iDYBMIG2XPSMZ9AYSjmUpx6IbhEqpV6Ny9eG05X9731a4xxR+2u2hfQFAlTTlSx68K5PNDHxAWdb9tuO+IwoCV4chzJaape7xf3ELLAQ04S3KtmEZTi0Maq/oKPpisXTyySPb/rZE1yFv7XTbDpOARY0qfeW3Pr1acqmd2lZ/JKF2Ir9GrUA9iw56LiwwNh1ZnmuLrQIV6n+SQnXH6/d8ZaguBD7XkiDI9PyFks3njXTXP/bZj0pPx4+1bW3V1cBisAJ4OOp5A09+0aWy2Td5IC/kyfBGCyCv5LmFQsbnKyqP3nbn89H6hz9zn6RTX5IwWqn9GkM443ZLHc3Xydncr/etJMBwYql+cZ0b+z/4WzLyp5/fA56t3bt3z0t2XuYZmt/xvZ2uXw2+bqe8P9bVmg1f/2XibgwK7qksW1TaDcKq/x0v5XzylVt21MBoU1eY2wVAL5/PW+rBbY5f9XfZrnNPVPUVgg4NsDETv8xa8MQkgzySV/JM3olhYpRowF9jJIy2O3HkJVr7yP3fgubvhlSRuSAGn19fb8DyvFX0/gg822HZ//aB2794D3BYssOIYZY1zCGAeDhZ//D2+1TK+XLkY2BH0L0wVd9IIMYfIst1LO0Hf/7Gbbu+Wh8dZgmgkQvQv/W6f/jMViuTug/gaVtMxxoLC/2T6vk+GsGerDP+YCM3UcRALMSE+7MwzKzgtV7z0J+tSnXnnkJ0XR/VgoYPTnYm4iEFsGbTntpk0c8jZFw+85LmRcMKlDj2G9WxwvsPfuwvD6G5wZg8NksAq7+bT7lO8JDtuR9B3m2GuqTxzN9EMkdrJaS+NQh5JrmZTyzSNYBHjicrvAzUxYDVtESYn1ihX/vHWuB8bOiOfBWtJyTnJI/mdd7Kq3yUdqKbxfNuCQEeeGD+SYvpv6x2cHtUh3L3qutkWWcO6QHlde6Lg+FucPSEfP/4z6QfOVgAJucUAjCElVpkp71b0PJfwd0TCVZyOu25ax94IFtZUdiDJGtDFCDDa+L3hNoJ0x8JK/If7/+ErF3+NihjDmmxp0UstLRnB1+WLc8+JsvdjBQ18qAm9JHLaMtxMRcPf5I+mrth3733xusLeCZ+rp42VvpPbbNd7xqAbynTiQEjEQMDlBVyYvNr5HaOzpM+wrqwWxE5FUlMxFYZOH2XkVUdMwXA+3rd33/6ckxp7+CsDhWtpMh1+5k0vxgzyZ3bgwAS001+Dagm/4iJ2BAP7iRWYiaZSctxnA+B6pVmStuE0K/yLYMNGIVY68WiGXNRQ3nuB6BLx8znk7vz/CbSb8UM5yF1fm5jrYIYiZWYiR3Ldkp3V9RaxInrpIblK4SKlrlBS5gWhtl4MOH5uS5JD7Z1FpkHsXGJTvR1xEzs5FzZHekbIIreOOmhJ89f2IgjQQ3Nj48OS6eXxjAYGoHMfpqLOYK1C0uWLukTG8NYo+IjlzhROAUabN2YDd5xAf7kmVH0bWE9ZjIGNaI5vQ6IsT5p2aleg1nkZXX9g/lMsVs/iuj6YY3xEv1OxoXpTze8ClgLhlLgFxOGOdgGpCiQdEdOnrn5E1i76JxGK4H71ukTcvMP/0pqFvTCkaVBYVsyWMSJhdVlr0GbplVca067FozhB9kxdatTEj8XBdYmEw/jBcymz8+8SROykQDZYGi6XslqnHLRNUrQ1KWYUzXWq2kqIQR4GsuKfbAkrCObysn2U8+0ZIzAJ+tiCi38B0Yu2mLqvKkkUc6JOqyr8NhKidAzxoYWSMxqQivAyoMxXN6khiyYJwVCgjZqSN3jggWu5y5KQrShq9C0+UePhaKNcPgcxUKBkk5zWmzdqAAjsSq1ktix8C6blOtJWK4yx2iLJpkhkw4ApuAGBE7DLYWhHIt8CcMAL0BwAEwY1eRlpM2JZhuxFkHz48VhKcEFDG2kIxHOPRxLHUc6cM0+mPpWYXUUDq/bLfAubXd4Smr+Jge8XQPg7K+tQllRwy6O0wB2uFoUh0HQdqXLy8r7OnplWUeX9KYz0uV2SIfrSCaVxe9sr02k3ovY8LXrPygVCK5Urcp4rSLDlaIcq4zLT8oFOVkdxzuXSAKMOn12SnLQnm9Yh1LbhQDMxO7AFlYbGwOQVooxPUisWvPlDLpdAmBru5fJh/pXy4psj3R4KWhNSREgKojq1VpVymxbLUvJDwyAufrx8czx8VFJuykIMS0D2S65yr1UUrYn2zhyAHyxWpGfnxmWfx8ekiNnRuQ0/LkH/TloE481c1GfXm9e0YlajcmyXsoL2CmwJbqY3njqFcU2Bs2s71kut666Vt6ZWyFH/KK8MnZCDgwflF9geHqrVJCfVc9INfDxWjAeGkMIa1mmV+56101TyZlzmh97LkJYfzH4nNAv6Q4sdIEUtH0lrOmyTLeszC6R5V19sv3q35ElTkr+e+SQ/PPP98kQBNcDwTUeOwypyX8MhHw/CexwAd2juMqbcDHZbNoZb9N4T6DhF67bLFvWbJAvv/6sPPTCv8lBmKmGtrn6iGmX2DDRZWDOhekTmg2LGUUsWJfqNOfTCJsWcQ0DZ2d6iVwKbdO0ma1TqzU47VC1JG/CDdTJId6RlJOWVdmsfOSKTfLk5o/LN/c9LX89uFf6YQlcKGmmSqaDwEwf6EG00TkMCeBz7kcIvgNB7i2/LHeu+g3Z9pu/K//yf3vkG//7lFwGzeSgISflTXRKf8QbXakw2uBZC8ZVgkarqJuwMpzzKimcQFF7FVhMGTcSEOSKga7HxghiMk7qCgkdBPqLsRH56t4nZGP/2+T+9/yBvHDyLdk7dlz6LNcILaE96xd9mdVt0TkM402Q158kE/QSjanC4WJBxkrj8uErN8Kvi/LNweflROmMlOGLnSDlgl28L0RbyyyYuKijBdCsXRwZrOSYgrqZIs8ggKbhz1xiQ4/oUMMSEPUhSAX/ZwCkYCqoy+CV+kBuQD539W/LhsvWytDIURmCK3ai/2SqbPpp+g9iX/fIdmxKwFsVmEQzWVBb1PHxoCI3LV0jf7LhJnn38jWYPoTywuH98v0j++W10SMyWhyTUcSIU7UaSIZgOMRzNGeNgJmSrVe9R3KwGvMSg7NuSCHWBobOwoj8zWvPSRp1Pq0AQvLQJgW36nVdWZJKSx8C7bt7V8rmS9bLhkuuMHHmuaODsuvFH8lL48OyHALmUDtTuNPkwPuwKPQ7otY/un2/tp0rNCI1dNL8OQDhMlgh9E1y8/Zcn2xesV5uXP52eeey1XhrlkHUr8jpyhkZwXHcL8mh8riUKiVE7zJGg6qMlsfiMRwmlQQsduqg6zSY6kWgS0FQnaCVSWfl8nSnDOC8D79MoR1YyThovnT0oDx57ID857FBBMDTxuq6cK+VuQFcSDP3UWEwqNY9+tk9ynXeiwVQJkIt5RVkNoBP+/DDMUiTGuvCAuUVXf2yMbcMw+JSWdUzIP3ZnHR7zAFSiORIl/Ac1/Pow4wRNHFT2DEOmgMnVEyJK1AIh88CAuxJuN0Q1gBfL5yQ/yock6OlUzKGPIElS1cDcMNTQs/cmfsfmnGhVOla8ByHwSFsS3nv3M1n3zEmho45Pi8F3x5wRDD3l08dlt0nD2FeECLwwW85diNuZCCA5Wh7TWevfOP3bpduaJaSJmQWCoQR4TBmlbf9+O+QQ9TkzVoZM1eMBcgNGKQj9BcguA3AHbrh/2mMAjXzbEyhWYbJFjOL2YoD7I6y1Sumf/LRRkkaU+hYFDeAuqGJXgBl0CM4tqFJ8hhEwPQQ4CJGU5QEfHweX/nQ/vPQ7goIrQ80PAyjFhfo0CihVcNZhZ3idyoN0mmr4HFid7gbS0PSEHCcC7RFJW6c+A21QAYNt7hFNskk4wZXkLPQoLH0+LGJ/0k7DoUuNJxGWw6ZJUT95F7SmPQWBJzPA2vkA7OWvZZVjl5D3WGxbNA1ok36OqvfhEH+TjXzeFZHOM0LM82pwTGhkdBt/nQrd9GBwSqHid3KiFewbGtvvAGJuddFXpAFEyt2nz1vsL+4LV+Gkz5N8zMp20WOnxgN1iB6hthpYTosV/ZgcnAKW68ghYW7wYUrQ4z/wEisxEzsXBZXY2l9ANHpJcGmq/j1zoULYUGcMdMhRmAlZmLnsrgcx2ZDbHp6EsNAgMh18cYBTlGAkViJmdiTEQwzDrw51fI6NyEuSMoX8MMGGzAarHU+TQyA26v9d37lTWw//S53YCIzi1cjLmAw7bJGTMRGjMRKzKChYwuIXxRKerj3wbDm/xSvkrHKffEEQ2IhJmIjRiO8OuYJF+CmAb43t7S1Szk20myLueavfjwwGDD2AROxESOxJhY0ccLdIahUlcD6Yej737Px9gTwF00AE4GF+caMMrtmRoOFXAIDsRATsYEUdr4arIbqhACSPobuyFeCavl+DBVvcJsZ6hdNCKaPumdxOsxZnpnpIednieW9qOLAvB8YgIWYiM10NOVfo95YZ7bJ2dmOr+OFCT5tWbgMCJGTnOt7VmDCgzUBQ3KSLmeQZ7CK/D+jx7CstkhSB027I3U6LJY/uf/2Lz0CsgYbfidKIwGgd0RIBIl4o6SLjZJ4aboIGyUphKOc3xujmtk1XnSC4aWYDS68QLzKwnZ6bJSsNt8oOZOLuG+Gv5048ou/VZYLno075TIol8AnreIsBUH1xVtlq9gqu7X5VlnkhQ3KTtQ9I4JgYf0gffypHiuVtj3vBqSO5JH8z4WhAbHpVVzumuuII8H09m1ecctHhD2OHPIeOFAevjf/rt+X3Tt2zzmizQsE5tpgu3wUL9O0yd05bU6rt/HlWcoNF2e7fJ1bIt3yqgQHbt31cV2ubMeSbUF5xk8XQWGLJpII+36EvOmqv528kudWtDSvBRgW6VU7dyIm4KsRfDKjHOdzqFmLjycwmpkNpa3RWTS8MSEOpPgwhFrHjg85oIPg82989AuPgU9sj98Bk5h/gacdxpFTIUCB6MX00VQ7AqiLPR4ifx0/m5s04Hgk4FgQfzipU9vwouF2jBLn9cPJAj6c5Ly+PjIZfiaZbO2sfQuYQnfqZ6u/Xp/OThECTuM5Y/zffDG+qB9Pu9bzeCv8zAX58fR0OdSTIyZyU4RxoX8+//+N9EREmyKFvQAAAABJRU5ErkJggg=='\n\n/** Chain icon by chain id; testnets reuse their mainnet icon */\nexport const CHAIN_ICONS: Record<number, string> = {\n [mainnet.id]: CHAIN_ETHEREUM,\n [sepolia.id]: CHAIN_ETHEREUM,\n [arbitrum.id]: CHAIN_ARBITRUM,\n [arbitrumSepolia.id]: CHAIN_ARBITRUM,\n [base.id]: CHAIN_BASE,\n [baseSepolia.id]: CHAIN_BASE,\n [blast.id]: CHAIN_BLAST,\n [bsc.id]: CHAIN_BSC,\n [hyperEvm.id]: CHAIN_HYPERLIQUID,\n [ink.id]: CHAIN_INK,\n [linea.id]: CHAIN_LINEA,\n [mode.id]: CHAIN_MODE,\n [monad.id]: CHAIN_MONAD,\n [optimism.id]: CHAIN_OPTIMISM,\n [optimismSepolia.id]: CHAIN_OPTIMISM,\n [polygon.id]: CHAIN_POLYGON,\n [scroll.id]: CHAIN_SCROLL,\n [soneium.id]: CHAIN_SONEIUM,\n [tempo.id]: CHAIN_TEMPO,\n [unichain.id]: CHAIN_UNICHAIN,\n [worldchain.id]: CHAIN_WORLDCHAIN,\n [zora.id]: CHAIN_ZORA,\n}\n\n/** Token icon by display symbol; wrapped variants reuse the base icon */\nexport const TOKEN_ICONS: Record<string, string> = {\n USDC: TOKEN_USDC,\n USDT: TOKEN_USDT,\n DAI: TOKEN_DAI,\n EURC: TOKEN_EURC,\n ETH: TOKEN_ETH,\n WETH: TOKEN_ETH,\n WBTC: TOKEN_WBTC,\n POL: CHAIN_POLYGON,\n WPOL: CHAIN_POLYGON,\n BNB: CHAIN_BSC,\n WBNB: CHAIN_BSC,\n}\n\nconst PROVIDER_ACROSS =\n 'data:image/png;base64,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'\nconst PROVIDER_RELAY =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAABGUUKwAAAC52lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOklwdGM0eG1wRXh0PSJodHRwOi8vaXB0Yy5vcmcvc3RkL0lwdGM0eG1wRXh0LzIwMDgtMDItMjkvIj4KICAgICAgICAgPHBob3Rvc2hvcDpDcmVkaXQ+TWFkZSB3aXRoIEdvb2dsZSBBSTwvcGhvdG9zaG9wOkNyZWRpdD4KICAgICAgICAgPElwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWE8L0lwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPgogICAgICAgICA8SXB0YzR4bXBFeHQ6RGlnaXRhbFNvdXJjZUZpbGVUeXBlPmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWE8L0lwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VGaWxlVHlwZT4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cp6mSPIAABIISURBVGgFtVp7jF3HWZ+Z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'\n\n/** Provider brand icon by `FeeBreakdown.provider` value (\"Across\" / \"Relay\"). */\nexport const PROVIDER_ICONS: Record<string, string> = {\n Across: PROVIDER_ACROSS,\n Relay: PROVIDER_RELAY,\n}\n","import { formatUnits } from 'viem'\n\n/**\n * Format a raw token amount (decimal string, hex string or bigint) into a\n * human readable unit string. Falls back to the raw value if parsing fails.\n */\nexport function formatTokenAmount(\n value: string | bigint,\n decimals: number,\n): string {\n try {\n const amount = typeof value === 'bigint' ? value : BigInt(value)\n return formatUnits(amount, decimals)\n } catch {\n return String(value)\n }\n}\n\n/** Rounding direction for display amounts. `'up'` / `'down'` are ceil / floor\n * — use them for values where over- or under-stating is unsafe (fees, min\n * deposit). `'nearest'` is `Math.round` — use for values the user reads as a\n * final quantity (\"you received X\") so 249.9996… reads as 250.00. */\nexport type RoundDirection = 'up' | 'down' | 'nearest'\n\nfunction displayFractionDigits(value: number): number {\n if (value >= 1000) return 0\n if (value >= 1) return 2\n // Two significant digits for sub-unit amounts\n return Math.min(8, 1 - Math.floor(Math.log10(value)))\n}\n\n/**\n * Format a raw token amount for display: thousands grouping and a\n * magnitude-aware precision (whole numbers above 1000, two decimals above 1,\n * two significant digits below). Rounds in the given direction so limits and\n * fees are never overstated/understated. Falls back to the raw value if\n * parsing fails.\n */\nexport function formatDisplayAmount(\n value: string | bigint,\n decimals: number,\n round: RoundDirection,\n): string {\n let amount: number\n try {\n amount = Number(\n formatUnits(typeof value === 'bigint' ? value : BigInt(value), decimals),\n )\n } catch {\n return String(value)\n }\n if (amount === 0) return '0'\n\n const digits = displayFractionDigits(amount)\n const factor = 10 ** digits\n const roundFn =\n round === 'up' ? Math.ceil : round === 'down' ? Math.floor : Math.round\n const rounded = roundFn(amount * factor) / factor\n return rounded.toLocaleString('en-US', {\n maximumFractionDigits: digits,\n })\n}\n\nexport function truncateAddress(address: string): string {\n if (address.length <= 12) return address\n return `${address.slice(0, 6)}…${address.slice(-4)}`\n}\n\nexport function formatSlippage(basisPoints: number): string {\n return `${(basisPoints / 100).toFixed(2).replace(/\\.?0+$/, '')}%`\n}\n\nexport function formatDuration(seconds: number): string {\n if (seconds < 60) return `~${Math.max(1, Math.round(seconds))} sec`\n return `~${Math.round(seconds / 60)} min`\n}\n\n/** Symbols treated as ~$1, so a USD equivalent can be shown for their amounts */\nexport const STABLE_SYMBOLS = new Set([\n 'USDC',\n 'USDT',\n 'DAI',\n 'USDBC',\n 'USDC.E',\n])\n\n/** ISO timestamp → compact \"N unit ago\" (\"just now\", \"2 m ago\", \"3 h ago\",\n * \"5 d ago\", \"2 mo ago\", \"1 y ago\"). Returns `null` on invalid input. */\nexport function formatRelativeTime(\n iso: string,\n now: number = Date.now(),\n): string | null {\n const then = Date.parse(iso)\n if (Number.isNaN(then)) return null\n const seconds = Math.max(0, Math.round((now - then) / 1000))\n if (seconds < 30) return 'just now'\n if (seconds < 60) return `${seconds} s ago`\n const minutes = Math.round(seconds / 60)\n if (minutes < 60) return `${minutes} m ago`\n const hours = Math.round(minutes / 60)\n if (hours < 24) return `${hours} h ago`\n const days = Math.round(hours / 24)\n if (days < 30) return `${days} d ago`\n const months = Math.round(days / 30)\n if (months < 12) return `${months} mo ago`\n const years = Math.round(months / 12)\n return `${years} y ago`\n}\n","import { formatUnits } from 'viem'\nimport { z } from 'zod/mini'\nimport type { EstimatedFeeData } from '../types'\nimport { formatDisplayAmount, STABLE_SYMBOLS } from './format'\n\n/**\n * Standardised fee breakdown shared across routing providers. Each provider\n * (Across, Relay, …) exposes fees in its own shape; the parsers below map\n * them onto this single model so the fees view can render any of them\n * identically.\n *\n * A leg is either a `rate` (proportional to the deposit, e.g. capital / LP)\n * or `flat` (a fixed cost, e.g. destination gas). Because the deposit amount\n * is not known up front, each leg is shown only in its amount-invariant\n * form: a percentage for rates, a fixed USD value for flat costs.\n */\nexport type FeeKind = 'rate' | 'flat'\n\nexport type FeeLine = {\n key: string\n label: string\n kind: FeeKind\n /** Right-aligned accent: gas pump for gas legs, $ disc otherwise */\n accent: 'gas' | 'usd'\n /** Proportional rate as a percent (e.g. 0.01 for 0.01%); rate legs only */\n pct: number | null\n /** USD value at the quoted amount; the display value for flat legs */\n usd: number | null\n /** Raw fallback text (e.g. a token amount) when neither pct nor usd applies */\n text?: string\n /** True when the leg is waived (shown as \"Sponsored\") */\n sponsored?: boolean\n}\n\nexport type FeeBreakdown = {\n /** Routing provider, or null when no itemised provider data is available */\n provider: string | null\n lines: FeeLine[]\n /** Combined proportional rate as a percent, e.g. 0.013 for \"0.013%\" */\n ratePct: number | null\n /** Combined flat (fixed) cost in USD */\n flatUsd: number | null\n /** Full cost in USD at the quoted amount — used to compare routes */\n quotedTotalUsd: number | null\n /** Headline fallback when USD isn't derivable (e.g. \"0.00002 ETH\") */\n totalText: string | null\n /** Estimated fill time in seconds, when the provider reports it */\n fillTimeSec: number | null\n}\n\nfunction sum(values: (number | null)[]): number | null {\n return values.reduce<number | null>(\n (total, v) => (v === null ? total : (total ?? 0) + v),\n null,\n )\n}\n\n// ---------------------------------------------------------------------------\n// Across — GET https://app.across.to/api/suggested-fees\n// Fees are nested { pct, total } objects. `pct` is an 18-decimal fraction\n// (1e18 = 100%); `total` is in input-token units. Capital and LP fees are\n// true rates; the relayer gas fee is a fixed destination-gas cost (its pct\n// only looks like a rate because it is gas/amount). totalRelayFee = sum of\n// the three legs.\n//\n// Schemas validate the response at the fetch boundary — the API is external,\n// so a shape change (added required field, renamed leg, changed type) must\n// surface as a failed parse, not silently corrupted numbers. Unknown keys\n// are stripped (Zod default); we only assert what we actually consume.\n// ---------------------------------------------------------------------------\n\nconst AcrossLegSchema = z.object({\n pct: z.string(),\n total: z.string(),\n})\n\nexport const AcrossSuggestedFeesSchema = z.object({\n totalRelayFee: AcrossLegSchema,\n relayerCapitalFee: AcrossLegSchema,\n relayerGasFee: AcrossLegSchema,\n lpFee: AcrossLegSchema,\n estimatedFillTimeSec: z.optional(z.number()),\n})\n\ntype AcrossLeg = z.infer<typeof AcrossLegSchema>\nexport type AcrossSuggestedFees = z.infer<typeof AcrossSuggestedFeesSchema>\n\nconst E18 = 10n ** 18n\n\n/** 18-decimal Across fraction → percent (e.g. \"150298578165425\" → 0.0150) */\nfunction acrossPct(raw: string): number | null {\n try {\n // percent = raw/1e18 * 100, kept to 4-decimal percent precision via\n // BigInt before Number conversion (raw can exceed 2^53).\n return Number((BigInt(raw) * 1_000_000n) / E18) / 10_000\n } catch {\n return null\n }\n}\n\n/** Across totals are in input-token units; USD only when the token is ~$1 */\nfunction tokenUsd(\n total: string,\n decimals: number,\n symbol: string,\n): number | null {\n if (!STABLE_SYMBOLS.has(symbol.toUpperCase())) return null\n try {\n return Number(formatUnits(BigInt(total), decimals))\n } catch {\n return null\n }\n}\n\nexport function parseAcrossFees(\n res: AcrossSuggestedFees,\n symbol: string,\n decimals: number,\n): FeeBreakdown {\n const leg = (\n key: string,\n label: string,\n kind: FeeKind,\n accent: FeeLine['accent'],\n data: AcrossLeg,\n ): FeeLine => ({\n key,\n label,\n kind,\n accent,\n pct: acrossPct(data.pct),\n usd: tokenUsd(data.total, decimals, symbol),\n })\n\n const lines: FeeLine[] = [\n leg('capital', 'Capital Fee', 'rate', 'usd', res.relayerCapitalFee),\n leg('destGas', 'Destination Gas', 'flat', 'gas', res.relayerGasFee),\n leg('lp', 'LP Fee', 'rate', 'usd', res.lpFee),\n ]\n\n return {\n provider: 'Across',\n lines,\n ratePct: sum(lines.filter((l) => l.kind === 'rate').map((l) => l.pct)),\n flatUsd: sum(lines.filter((l) => l.kind === 'flat').map((l) => l.usd)),\n quotedTotalUsd: tokenUsd(res.totalRelayFee.total, decimals, symbol),\n totalText: null,\n fillTimeSec:\n typeof res.estimatedFillTimeSec === 'number'\n ? res.estimatedFillTimeSec\n : null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Relay — POST https://api.relay.link/quote\n// Each fee carries `amountUsd` only (no rate), so every leg is treated as a\n// fixed cost. `relayer` is the full relayer fee (relayerGas + relayerService);\n// `gas` is the user's origin-chain gas.\n// ---------------------------------------------------------------------------\n\nconst RelayFeeSchema = z.object({\n amountUsd: z.optional(z.string()),\n})\n\nexport const RelayQuoteSchema = z.object({\n fees: z.optional(\n z.object({\n gas: z.optional(RelayFeeSchema),\n relayer: z.optional(RelayFeeSchema),\n relayerGas: z.optional(RelayFeeSchema),\n relayerService: z.optional(RelayFeeSchema),\n app: z.optional(RelayFeeSchema),\n }),\n ),\n details: z.optional(\n z.object({\n timeEstimate: z.optional(z.number()),\n }),\n ),\n timeEstimate: z.optional(z.number()),\n})\n\ntype RelayFee = z.infer<typeof RelayFeeSchema>\nexport type RelayQuote = z.infer<typeof RelayQuoteSchema>\n\nfunction usdOf(fee?: RelayFee): number | null {\n if (!fee?.amountUsd) return null\n const value = Number(fee.amountUsd)\n return Number.isFinite(value) ? value : null\n}\n\nexport function parseRelayFees(res: RelayQuote): FeeBreakdown {\n const fees = res.fees ?? {}\n const lines: FeeLine[] = []\n const push = (\n key: string,\n label: string,\n accent: FeeLine['accent'],\n fee?: RelayFee,\n ) => {\n const usd = usdOf(fee)\n if (usd === null) return\n // Drop zero-value optional legs (e.g. app fee)\n if (usd === 0 && (key === 'app' || key === 'originGas')) return\n // Relay exposes USD only, so every leg is shown as a fixed cost\n lines.push({ key, label, kind: 'flat', accent, pct: null, usd })\n }\n\n push('service', 'Service Fee', 'usd', fees.relayerService)\n push('destGas', 'Destination Gas', 'gas', fees.relayerGas)\n push('originGas', 'Origin Gas', 'gas', fees.gas)\n push('app', 'App Fee', 'usd', fees.app)\n\n const totalUsd = usdOf(fees.relayer)\n return {\n provider: 'Relay',\n lines,\n ratePct: null,\n flatUsd: sum(lines.map((l) => l.usd)),\n quotedTotalUsd: totalUsd,\n totalText: null,\n fillTimeSec: res.details?.timeEstimate ?? res.timeEstimate ?? null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Combine SRA fee + provider legs into the final breakdown\n// ---------------------------------------------------------------------------\n\n/**\n * Present the SRA fee as the actual all-in charge, with the provider's\n * bridge legs as a breakdown *of* it (not added on top — the SRA server fee\n * already covers bridging + execution). The execution portion is derived as\n * `SRA fee − bridge cost` so the legs sum back to the SRA fee. Without\n * provider data, the whole SRA fee is shown as a single execution line.\n */\nexport function buildFeeBreakdown(\n feeData: EstimatedFeeData,\n symbol: string,\n provider: FeeBreakdown | null = null,\n): FeeBreakdown {\n // The SRA fee is the all-in amount ZeroDev charges (bridging + execution)\n const sraUsd = feeData.isSponsored\n ? 0\n : tokenUsd(feeData.fee, feeData.decimal, symbol)\n const bridgeUsd = provider?.quotedTotalUsd ?? null\n // Token-unit fallback for non-stablecoins where USD isn't derivable\n const feeToken = `${formatDisplayAmount(feeData.fee, feeData.decimal, 'up')} ${symbol}`\n\n // Execution = the part of the SRA fee not explained by the bridge legs\n const executionUsd = feeData.isSponsored\n ? 0\n : sraUsd === null\n ? null\n : bridgeUsd === null\n ? sraUsd\n : Math.max(0, sraUsd - bridgeUsd)\n\n const showTokenFallback = !feeData.isSponsored && sraUsd === null\n const executionLine: FeeLine = {\n key: 'execution',\n label: 'Execution Fee',\n kind: 'flat',\n accent: 'usd',\n pct: null,\n usd: executionUsd,\n // Show the SRA fee in token units when we can't price it in USD\n ...(showTokenFallback && { text: feeToken }),\n sponsored: feeData.isSponsored,\n }\n\n const lines = [executionLine, ...(provider?.lines ?? [])]\n\n return {\n provider: provider?.provider ?? null,\n lines,\n ratePct: sum(lines.filter((l) => l.kind === 'rate').map((l) => l.pct)),\n flatUsd: sum(lines.filter((l) => l.kind === 'flat').map((l) => l.usd)),\n // The headline charge is the SRA fee itself, never the sum on top of it\n quotedTotalUsd: feeData.isSponsored ? 0 : sraUsd,\n // Headline fallback for non-stable tokens (e.g. \"0.00002 ETH\")\n totalText: !feeData.isSponsored && sraUsd === null ? feeToken : null,\n fillTimeSec: provider?.fillTimeSec ?? null,\n }\n}\n\n/** Format a percent number for display, trimming to a sensible precision */\nexport function formatFeePct(pct: number): string {\n const digits = pct >= 1 ? 2 : pct >= 0.1 ? 2 : 3\n return `${pct.toFixed(digits)}%`\n}\n\n/** Format a USD number for display */\nexport function formatFeeUsd(usd: number): string {\n const digits = usd > 0 && usd < 0.01 ? 4 : 2\n return `$${usd.toLocaleString('en-US', {\n minimumFractionDigits: 2,\n maximumFractionDigits: digits,\n })}`\n}\n","/**\n * Plain-language explanations for each fee/route line, surfaced as tooltips\n * on the info icons in the fee section so users understand what they're\n * charged.\n */\nexport const FEE_INFO = {\n minDeposit: 'Smallest amount this route can process after fees.',\n maxSlippage: 'Maximum price movement allowed during the swap.',\n estimatedFee: 'Estimated swap, bridge, and network costs.',\n readyIn: 'Estimated arrival after the deposit is detected.',\n // Breakdown legs\n provider: 'Bridge provider selected for this route.',\n execution: 'Cost to execute and deliver funds on the destination chain.',\n capital: 'Relayer cost for fronting capital while bridging.',\n destGas: 'Gas to complete delivery on the destination chain.',\n lp: 'Bridge liquidity-provider fee.',\n service: 'Solver fee for filling the route.',\n originGas: 'Gas to submit from the source chain.',\n app: 'Optional application fee.',\n // Transaction progress steps (transaction-details view)\n detected: 'Deposit detected on the source chain.',\n routing: 'Bridge and swap are in progress.',\n completed: 'Funds arrived in the delivery account.',\n failed: 'Deposit could not be completed.',\n} as const\n","import { cn, Icon, Text, Tooltip } from '@zerodev/react-ui'\nimport type { ReactNode } from 'react'\nimport { PROVIDER_ICONS } from '../../iconAssets'\nimport type { FeeBreakdown, FeeLine } from '../../utils/providerFees'\nimport { formatFeePct, formatFeeUsd } from '../../utils/providerFees'\nimport { FEE_INFO } from './feeInfo'\n\n/** Home pages for supported providers, so the name links out */\nconst PROVIDER_URLS: Record<string, string> = {\n Across: 'https://across.to',\n Relay: 'https://relay.link',\n}\n\nexport type LiveValueProps = {\n /** While true, the value is being re-quoted: show a spinner */\n loading: boolean\n /** Changes with the value so the flash-in animation re-triggers */\n flashKey: string | number\n children: ReactNode\n}\n\n/**\n * A value that swaps to a spinner while its route is re-quoting, then flashes\n * the fresh value in. Used so a route change visibly recalculates the min\n * deposit / estimated fee rather than silently snapping to new numbers.\n */\nexport function LiveValue({ loading, flashKey, children }: LiveValueProps) {\n if (loading) {\n return (\n <span\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:text-orange\"\n role=\"img\"\n aria-label=\"Updating estimate\"\n >\n <Icon\n name=\"loading\"\n className=\"zd:w-3.5 zd:h-3.5 zd:animate-spin zd:text-orange\"\n aria-hidden\n />\n </span>\n )\n }\n return (\n <span\n key={flashKey}\n className=\"zd:inline-flex zd:items-center zd:gap-1.5 zd:animate-fee-flash\"\n >\n {children}\n </span>\n )\n}\n\n/** Combined fee value: proportional rate (emphasised) + fixed USD cost */\nexport function FeeSummary({ breakdown }: { breakdown: FeeBreakdown }) {\n // When the SRA fee can't be priced in USD (non-stable token), show it as a\n // token amount — the partial USD bridge legs must not headline as the total.\n if (breakdown.totalText) {\n return (\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">\n {breakdown.totalText}\n </Text>\n )\n }\n const pct =\n breakdown.ratePct !== null && breakdown.ratePct > 0\n ? formatFeePct(breakdown.ratePct)\n : null\n const usd =\n breakdown.flatUsd !== null ? formatFeeUsd(breakdown.flatUsd) : null\n if (!pct && !usd) {\n return <Text className=\"zd:whitespace-nowrap\">—</Text>\n }\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1 zd:leading-none\">\n {pct && (\n <b className=\"zd:text-body2 zd:font-bold zd:text-greyScale zd:leading-none\">\n {pct}\n </b>\n )}\n {pct && usd && (\n <span className=\"zd:text-body2 zd:text-greyScale/50 zd:leading-none\">\n +\n </span>\n )}\n {usd && (\n <span className=\"zd:text-body2 zd:font-medium zd:text-greyScale/70 zd:leading-none\">\n {usd}\n </span>\n )}\n </span>\n )\n}\n\n/** Provider name + brand icon, linked to the provider's site when known */\nexport function ProviderValue({ provider }: { provider: string }) {\n const url = PROVIDER_URLS[provider]\n const iconUrl = PROVIDER_ICONS[provider]\n const inner = (\n <>\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">{provider}</Text>\n {iconUrl && (\n <img\n src={iconUrl}\n alt=\"\"\n aria-hidden\n className=\"zd:size-3.5 zd:shrink-0 zd:rounded-[4px] zd:object-cover\"\n />\n )}\n </>\n )\n if (!url) {\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1\">{inner}</span>\n )\n }\n return (\n <a\n className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-greyScale zd:hover:underline\"\n href={url}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {inner}\n </a>\n )\n}\n\nfunction InfoMark({ info }: { info: string }) {\n // Real DOM element so Radix's `Tooltip` (via `asChild`) can attach hover /\n // focus handlers and wire `aria-describedby` to its content. Focusable so\n // keyboard users can trigger the tooltip.\n return (\n <Tooltip content={info}>\n {/* button (not span+tabIndex): natively focusable, so keyboard users\n can trigger the tooltip; Radix wires aria-describedby to the\n tooltip copy on hover / focus. `type=\"button\"` keeps it inert\n inside forms. */}\n <button\n type=\"button\"\n aria-label=\"More info\"\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-help zd:outline-none zd:bg-transparent\"\n >\n <Icon\n name=\"info\"\n className=\"zd:w-3 zd:h-3 zd:text-greyScale/50\"\n aria-hidden\n />\n </button>\n </Tooltip>\n )\n}\n\nfunction LineValue({ line }: { line: FeeLine }) {\n if (line.sponsored) {\n return (\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">Sponsored</Text>\n )\n }\n // Rates are amount-invariant → show percent; flat costs → show USD; fall\n // back to a raw token amount when neither is available.\n const value =\n line.kind === 'rate' && line.pct !== null\n ? formatFeePct(line.pct)\n : line.usd !== null\n ? formatFeeUsd(line.usd)\n : line.pct !== null\n ? formatFeePct(line.pct)\n : (line.text ?? '—')\n return <Text className=\"zd:whitespace-nowrap zd:font-medium\">{value}</Text>\n}\n\nfunction BreakdownRow({\n label,\n info,\n children,\n className,\n}: {\n label: string\n info?: string\n children: ReactNode\n className?: string\n}) {\n return (\n <div\n className={cn(\n 'zd:flex zd:w-full zd:items-center zd:gap-1 zd:py-1',\n className,\n )}\n >\n <Text className=\"zd:whitespace-nowrap zd:text-greyScale/60\">{label}</Text>\n {info && <InfoMark info={info} />}\n <div className=\"zd:min-w-0 zd:flex-1\" />\n {children}\n </div>\n )\n}\n\n/** Itemised fee rows: provider + each fee leg */\nexport function FeeBreakdownRows({ breakdown }: { breakdown: FeeBreakdown }) {\n return (\n <div className=\"zd:flex zd:w-full zd:flex-col zd:pl-2\">\n {breakdown.provider && (\n <BreakdownRow label=\"Provider\" info={FEE_INFO.provider}>\n <ProviderValue provider={breakdown.provider} />\n </BreakdownRow>\n )}\n {breakdown.lines.map((line) => (\n <BreakdownRow\n key={line.key}\n label={line.label}\n info={FEE_INFO[line.key as keyof typeof FEE_INFO]}\n >\n <LineValue line={line} />\n </BreakdownRow>\n ))}\n </div>\n )\n}\n","import type { DepositedToken } from '@zerodev/smart-routing-address'\nimport type {\n DepositStage,\n EstimatedFee,\n SmartRoutingAddressConfig,\n} from '../types'\nimport { resolveDestChain, resolveSourceTokens } from './config'\nimport { findFeeDataByToken } from './fees'\nimport { formatTokenAmount, truncateAddress } from './format'\n\nexport const DEPOSIT_STAGE_LABELS: Record<DepositStage, string> = {\n pending: 'Deposit detected',\n bridging: 'Bridging',\n completed: 'Completed',\n failed: 'Failed',\n}\n\n/**\n * Newer SRA servers split a deposit into legs that each carry their own\n * bridge/execution status; the published SDK types don't include the\n * field yet, so it is modeled here as an optional extension.\n */\nexport type DepositSplitLeg = Pick<DepositedToken, 'bridge' | 'execution'> & {\n splitIndex: number\n amount: string\n}\n\nexport type DepositWithSplits = DepositedToken & {\n splits?: DepositSplitLeg[]\n}\n\nexport function getDepositKey(deposit: DepositedToken): string {\n return deposit.deposit.transactionHash\n}\n\nexport function getDepositStage(deposit: DepositWithSplits): DepositStage {\n if (deposit.error) return 'failed'\n // Split deposits carry bridge/execution on each leg; the top-level\n // fields stay null.\n if (deposit.splits && deposit.splits.length > 0) {\n if (deposit.splits.every((leg) => leg.execution !== null)) {\n return 'completed'\n }\n if (\n deposit.splits.some(\n (leg) => leg.bridge !== null || leg.execution !== null,\n )\n ) {\n return 'bridging'\n }\n return 'pending'\n }\n if (deposit.execution) return 'completed'\n if (deposit.bridge) return 'bridging'\n return 'pending'\n}\n\nexport function getNewDeposits(\n deposits: DepositedToken[],\n baseline: ReadonlySet<string>,\n): DepositedToken[] {\n return deposits.filter((deposit) => !baseline.has(getDepositKey(deposit)))\n}\n\nexport type DepositSummary = {\n key: string\n stage: DepositStage\n stageLabel: string\n chainName: string\n symbol: string\n amount: string\n transactionHash: string\n}\n\nfunction getChainName(\n chainId: number,\n config: SmartRoutingAddressConfig,\n): string {\n const destChain = resolveDestChain(config)\n if (destChain.id === chainId) return destChain.name\n const source = resolveSourceTokens(config).find(\n (token) => token.chain.id === chainId,\n )\n return source?.chain.name ?? `Chain ${chainId}`\n}\n\nexport function summarizeDeposit(\n deposit: DepositedToken,\n estimatedFees: EstimatedFee[],\n config: SmartRoutingAddressConfig,\n): DepositSummary {\n const { chainId, token, amount, transactionHash } = deposit.deposit\n const feeData = findFeeDataByToken(estimatedFees, chainId, token)\n const stage = getDepositStage(deposit)\n return {\n key: getDepositKey(deposit),\n stage,\n stageLabel: DEPOSIT_STAGE_LABELS[stage],\n chainName: getChainName(chainId, config),\n symbol: feeData?.name ?? truncateAddress(token),\n amount: feeData\n ? formatTokenAmount(amount, feeData.decimal)\n : String(amount),\n transactionHash,\n }\n}\n","import { cn, Icon, Text } from '@zerodev/react-ui'\n\nexport type TxnStatus =\n | 'Routing'\n | 'Detected'\n | 'Received'\n | 'Delivered'\n | 'Failed'\n\nexport interface TxnItemProps {\n /** Pre-formatted deposited amount, e.g. `\"$248.00 USD\"`. */\n amount: string\n /**\n * Pre-formatted delivered amount. Presence switches the row to the\n * detailed (past-deposits) layout — `amount → destAmount` headline plus\n * the chain-route line (Figma `20002:37771`); without it the row is the\n * compact active-deposits variant (`20002:36061`).\n */\n destAmount?: string\n /** Short address/hash display, e.g. `\"0x4d2a…ba99\"`. */\n address: string\n /** Optional block-explorer URL. Address row becomes a link when supplied. */\n href?: string\n /** Pre-formatted relative timestamp, e.g. `\"2 m ago\"`. */\n timestamp: string\n status: TxnStatus\n /** Main image in the 44px mark. */\n sourceTokenIconUrl?: string\n /** Mark badge on the compact variant; chain-route icon on the detailed. */\n sourceChainIconUrl?: string\n /** Mark badge on the detailed variant. */\n destTokenIconUrl?: string\n /** Chain-route icon on the detailed variant. */\n destChainIconUrl?: string\n /** Chain-route labels — detailed variant only. */\n sourceChainName?: string\n destChainName?: string\n className?: string\n}\n\nconst STATUS_COLOR: Record<TxnStatus, string> = {\n Routing: 'zd:text-solarOrange',\n Detected: 'zd:text-greyScale/50',\n // In-flight arrival reads in plain ink (Figma 20002:36061); the green\n // celebration is reserved for the terminal Delivered state.\n Received: 'zd:text-greyScale',\n Delivered: 'zd:text-positive',\n Failed: 'zd:text-negative',\n}\n\nexport function TxnItem({\n amount,\n destAmount,\n address,\n href,\n timestamp,\n status,\n sourceTokenIconUrl,\n sourceChainIconUrl,\n destTokenIconUrl,\n destChainIconUrl,\n sourceChainName,\n destChainName,\n className,\n}: TxnItemProps) {\n const detailed = destAmount !== undefined\n // Compact rows badge the mark with the chain; detailed rows badge it with\n // the destination token (the route line already names both chains).\n const badgeIconUrl = detailed ? destTokenIconUrl : sourceChainIconUrl\n\n return (\n <div\n className={cn(\n 'zd:relative zd:flex zd:w-full zd:items-start zd:gap-2 zd:rounded-2xl zd:p-2',\n className,\n )}\n >\n <TokenMark\n {...(sourceTokenIconUrl && { tokenIconUrl: sourceTokenIconUrl })}\n {...(badgeIconUrl && { badgeIconUrl })}\n />\n\n {/* gap-1, not the Figma node's 8px: the design measures between\n leading-trimmed text boxes (text-box-trim), while our Text renders\n 130% line-height — ~2px of leading above and below each line — so\n 4px + leading visually lands on the design's 8px. */}\n <div className=\"zd:flex zd:min-w-0 zd:flex-1 zd:flex-col zd:gap-1 zd:py-2\">\n <div className=\"zd:flex zd:min-w-0 zd:items-center zd:gap-1\">\n <Text className=\"zd:truncate zd:text-body2\">{amount}</Text>\n {detailed && (\n <>\n <RouteArrow />\n <Text className=\"zd:truncate zd:text-body2\">{destAmount}</Text>\n </>\n )}\n </div>\n\n {detailed && (sourceChainName || destChainName) && (\n <div className=\"zd:flex zd:min-w-0 zd:items-center zd:gap-1\">\n {sourceChainName && (\n <ChainTag\n name={sourceChainName}\n {...(sourceChainIconUrl && { iconUrl: sourceChainIconUrl })}\n />\n )}\n {sourceChainName && destChainName && <RouteArrow />}\n {destChainName && (\n <ChainTag\n name={destChainName}\n {...(destChainIconUrl && { iconUrl: destChainIconUrl })}\n />\n )}\n </div>\n )}\n\n <AddressLine address={address} {...(href && { href })} />\n </div>\n\n <div className=\"zd:flex zd:shrink-0 zd:flex-col zd:items-end zd:justify-between zd:self-stretch zd:py-2\">\n <span\n className={cn(\n 'zd:flex zd:items-center zd:gap-2',\n STATUS_COLOR[status],\n )}\n >\n {/* In-flight marker (Figma 20002:36058): rotating rays before the\n Routing label, inheriting its orange. */}\n {status === 'Routing' && (\n <Icon\n name=\"lineLoading\"\n className=\"zd:size-2.5 zd:shrink-0 zd:animate-spin\"\n aria-hidden\n />\n )}\n <Text className={cn('zd:text-body2', STATUS_COLOR[status])}>\n {status}\n </Text>\n </span>\n <Text className=\"zd:text-body3 zd:text-greyScale/50\">{timestamp}</Text>\n </div>\n </div>\n )\n}\n\n/** 44px mark (Figma \"CryptoPresets\"): centred 34px token image with a 12px\n * badge straddling the bottom-right corner. */\nfunction TokenMark({\n tokenIconUrl,\n badgeIconUrl,\n}: {\n tokenIconUrl?: string\n badgeIconUrl?: string\n}) {\n return (\n <div className=\"zd:relative zd:size-11 zd:shrink-0 zd:rounded-xl zd:backdrop-blur-[15px]\">\n <div className=\"zd:absolute zd:top-1/2 zd:left-1/2 zd:size-8.5 zd:-translate-x-1/2 zd:-translate-y-1/2 zd:overflow-hidden zd:rounded-full zd:border zd:border-offWhite zd:bg-greyScale/10 zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]\">\n {tokenIconUrl && (\n <img\n src={tokenIconUrl}\n alt=\"\"\n className=\"zd:size-full zd:object-cover\"\n />\n )}\n </div>\n {badgeIconUrl && (\n <div className=\"zd:absolute zd:right-1 zd:bottom-1 zd:size-3 zd:overflow-hidden zd:rounded-full zd:border zd:border-offWhite/40 zd:bg-white\">\n <img\n src={badgeIconUrl}\n alt=\"\"\n className=\"zd:size-full zd:object-contain\"\n />\n </div>\n )}\n </div>\n )\n}\n\n/** 10px `›` separating the two sides of an amount / chain route. */\nfunction RouteArrow() {\n return (\n <Icon\n name=\"chevronRight\"\n className=\"zd:size-2.5 zd:shrink-0 zd:text-greyScale\"\n aria-hidden\n />\n )\n}\n\nfunction ChainTag({ name, iconUrl }: { name: string; iconUrl?: string }) {\n return (\n <span className=\"zd:flex zd:min-w-0 zd:items-center zd:gap-1\">\n {iconUrl && (\n <span className=\"zd:size-3 zd:shrink-0 zd:overflow-hidden zd:rounded-full zd:border zd:border-offWhite/40 zd:bg-white\">\n <img\n src={iconUrl}\n alt=\"\"\n aria-hidden\n className=\"zd:size-full zd:object-contain\"\n />\n </span>\n )}\n <Text className=\"zd:truncate zd:text-body3 zd:text-greyScale/80\">\n {name}\n </Text>\n </span>\n )\n}\n\nfunction AddressLine({ address, href }: { address: string; href?: string }) {\n const inner = (\n <>\n <span className=\"zd:truncate\">{address}</span>\n {href && (\n // 8px, not the design's 10px box: our export glyph is full-bleed\n // while Figma's sits inset 10% in its box, so matching the box size\n // renders visibly bigger. 8px equals the design's effective glyph.\n <Icon name=\"export\" className=\"zd:size-2 zd:shrink-0\" aria-hidden />\n )}\n </>\n )\n\n const className =\n 'zd:flex zd:min-w-0 zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale/80'\n\n if (href) {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n aria-label={`View ${address} on block explorer`}\n className={cn(className, 'zd:hover:text-greyScale')}\n >\n {inner}\n </a>\n )\n }\n return <span className={className}>{inner}</span>\n}\n","import { cn, Text } from '@zerodev/react-ui'\nimport type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { CHAIN_ICONS, TOKEN_ICONS } from '../../iconAssets'\nimport type {\n DepositStage,\n DepositWithTimestamp,\n EstimatedFee,\n SmartRoutingAddressConfig,\n} from '../../types'\nimport { getTxUrl } from '../../utils/chains'\nimport {\n getSourceTokenSymbol,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../../utils/config'\nimport { getDepositStage } from '../../utils/deposits'\nimport { findFeeDataByToken, tokenAddressMatches } from '../../utils/fees'\nimport {\n formatDisplayAmount,\n formatRelativeTime,\n truncateAddress,\n} from '../../utils/format'\nimport { TxnItem, type TxnStatus } from '../TxnItem'\n\nexport interface PendingDepositsProps {\n deposits: DepositedToken[]\n estimatedFees: EstimatedFee[]\n config: SmartRoutingAddressConfig\n /** Fired when a row is tapped — the widget uses this to open the\n * transaction-details view for the selected deposit. When omitted, rows\n * render as static (non-interactive). */\n onSelectDeposit?: (deposit: DepositedToken) => void\n className?: string\n}\n\nconst STAGE_TO_STATUS: Record<DepositStage, TxnStatus> = {\n pending: 'Detected',\n bridging: 'Routing',\n completed: 'Received',\n failed: 'Failed',\n}\n\nexport function PendingDeposits({\n deposits,\n estimatedFees,\n config,\n onSelectDeposit,\n className,\n}: PendingDepositsProps) {\n if (deposits.length === 0) return null\n\n const destChain = resolveDestChain(config)\n const destChainLogo = CHAIN_ICONS[destChain.id]\n\n return (\n <section\n aria-label=\"Active deposits\"\n className={cn(\n // Figma 20002:36058: tighter bottom padding than top so the last\n // row's own padding doesn't double up against the card edge.\n 'zd:relative zd:flex zd:w-full zd:flex-col zd:gap-4 zd:overflow-hidden zd:rounded-2xl zd:px-4 zd:pt-4 zd:pb-2',\n 'zd:border-offWhite zd:border-[0.3px] zd:bg-white/20',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n >\n <Text className=\"zd:text-h3\">Active Deposit</Text>\n <ul className=\"zd:flex zd:w-full zd:flex-col zd:gap-1\">\n {deposits.map((raw) => {\n const deposit = raw as DepositWithTimestamp\n const { chainId, token, amount, transactionHash } = deposit.deposit\n const feeData = findFeeDataByToken(estimatedFees, chainId, token)\n\n // Source pair: reconstruct the SourceToken so we can look up its\n // symbol + chain icon the same way the trigger pill does. Matching\n // on the on-chain address (via `tokenAddressMatches`) — the\n // server's `feeData.name` is a display symbol (e.g. \"ETH\"), not the\n // TOKEN_TYPE (\"NATIVE\"), so a direct `t.tokenType === name` compare\n // misses native tokens.\n const source =\n sourceTokensFromFees(estimatedFees).find(\n (t) =>\n t.chain.id === chainId &&\n tokenAddressMatches(t.tokenType, chainId, token),\n ) ?? null\n // Prefer the reconstructed source's symbol; fall back to the\n // server's `feeData.name` so past deposits whose route dropped\n // out of the current fee estimates still get a symbol / icon.\n const sourceSymbol = source\n ? getSourceTokenSymbol(source)\n : (feeData?.name ?? '')\n const sourceTokenLogo = sourceSymbol\n ? TOKEN_ICONS[sourceSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = CHAIN_ICONS[chainId]\n\n // Destination token equals source token — widget's default\n // actions forward the deposited asset unchanged.\n const destTokenLogo = sourceTokenLogo\n\n const status = STAGE_TO_STATUS[getDepositStage(deposit)]\n const amountLabel = feeData\n ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`\n : String(amount)\n const timestamp = deposit.createdAt\n ? (formatRelativeTime(deposit.createdAt) ?? '')\n : ''\n\n // Explorer URL from the chain id alone — independent of whether\n // the deposit's token was matched in the current fee estimates.\n const href = getTxUrl(chainId, transactionHash)\n\n const row = (\n <TxnItem\n amount={amountLabel}\n address={truncateAddress(transactionHash)}\n {...(href && { href })}\n timestamp={timestamp}\n status={status}\n {...(sourceTokenLogo && {\n sourceTokenIconUrl: sourceTokenLogo,\n })}\n {...(sourceChainLogo && {\n sourceChainIconUrl: sourceChainLogo,\n })}\n {...(destTokenLogo && { destTokenIconUrl: destTokenLogo })}\n {...(destChainLogo && { destChainIconUrl: destChainLogo })}\n />\n )\n\n return (\n <li key={transactionHash}>\n {onSelectDeposit ? (\n // No padding of its own: the TxnItem's built-in p-2 (the\n // Figma Txn Row inset) doubles as the hover highlight's\n // breathing room. Radius matches the row's rounded-2xl.\n <button\n type=\"button\"\n onClick={() => onSelectDeposit(deposit)}\n className=\"zd:w-full zd:cursor-pointer zd:rounded-2xl zd:text-left zd:hover:bg-white/30\"\n >\n {row}\n </button>\n ) : (\n row\n )}\n </li>\n )\n })}\n </ul>\n </section>\n )\n}\n","import type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { getSmartRoutingAddressStatus } from '@zerodev/smart-routing-address'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { Address } from 'viem'\nimport { DEFAULT_POLLING_INTERVAL_MS } from '../constants'\n\nexport type UseDepositStatusParams = {\n address: Address | undefined\n enabled?: boolean | undefined\n pollingInterval?: number | undefined\n baseUrl?: string | undefined\n}\n\nexport type UseDepositStatusResult = {\n deposits: DepositedToken[]\n totalCount: number\n /** True once at least one status response has been received */\n hasLoaded: boolean\n isLoading: boolean\n error: Error | null\n /** Trigger an immediate poll — used by the \"Retry\" button after a fetch\n * error. No-op while no address is set. */\n refetch: () => void\n}\n\nconst INITIAL_STATE = {\n deposits: [] as DepositedToken[],\n totalCount: 0,\n hasLoaded: false,\n isLoading: false,\n error: null as Error | null,\n}\n\n/**\n * Polls the smart routing address status endpoint while enabled, returning\n * the current list of deposits.\n */\nexport function useDepositStatus({\n address,\n enabled = true,\n pollingInterval = DEFAULT_POLLING_INTERVAL_MS,\n baseUrl,\n}: UseDepositStatusParams): UseDepositStatusResult {\n const [state, setState] = useState(INITIAL_STATE)\n // Exposed via `refetch`; reassigned every time the effect runs so we always\n // point at the poller bound to the current (address, baseUrl) pair.\n const pollRef = useRef<(() => void) | null>(null)\n\n useEffect(() => {\n if (!address || !enabled) {\n pollRef.current = null\n return\n }\n\n let cancelled = false\n // Each `poll()` call bumps `gen`; only the latest generation may write\n // to state. Prevents a stale interval-driven response from clobbering a\n // fresh `refetch()` (or vice-versa) when the two overlap in flight.\n let gen = 0\n\n const poll = async () => {\n gen += 1\n const requestGen = gen\n try {\n const result = await getSmartRoutingAddressStatus({\n smartRoutingAddress: address,\n ...(baseUrl && { config: { baseUrl } }),\n })\n if (cancelled || requestGen !== gen) return\n setState({\n deposits: result.deposits,\n totalCount: result.totalCount,\n hasLoaded: true,\n isLoading: false,\n error: null,\n })\n } catch (error) {\n if (cancelled || requestGen !== gen) return\n setState((previous) => ({\n ...previous,\n isLoading: false,\n error: error instanceof Error ? error : new Error(String(error)),\n }))\n }\n }\n\n pollRef.current = () => {\n setState((previous) => ({ ...previous, isLoading: true, error: null }))\n poll().catch(() => {})\n }\n\n setState((previous) => ({ ...previous, isLoading: true }))\n poll().catch(() => {})\n const intervalId = setInterval(() => {\n poll().catch(() => {})\n }, pollingInterval)\n\n return () => {\n cancelled = true\n clearInterval(intervalId)\n pollRef.current = null\n }\n }, [address, enabled, pollingInterval, baseUrl])\n\n const refetch = useCallback(() => {\n pollRef.current?.()\n }, [])\n\n return { ...state, refetch }\n}\n","import type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { useMemo, useRef } from 'react'\nimport { getDepositKey, getNewDeposits } from '../utils/deposits'\n\n/**\n * Tracks deposits that arrived after the first loaded status snapshot.\n * The snapshot taken when `ready` first becomes true acts as the baseline,\n * so pre-existing deposits are not reported as new.\n */\nexport function useNewDeposits(\n deposits: DepositedToken[],\n ready: boolean,\n): DepositedToken[] {\n const baselineRef = useRef<ReadonlySet<string> | null>(null)\n\n if (ready && baselineRef.current === null) {\n baselineRef.current = new Set(deposits.map(getDepositKey))\n }\n\n const baseline = baselineRef.current\n return useMemo(() => {\n if (!baseline) return []\n return getNewDeposits(deposits, baseline)\n }, [deposits, baseline])\n}\n","import type { TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { useEffect, useState } from 'react'\nimport type { Address, Chain } from 'viem'\nimport { zeroAddress } from 'viem'\nimport type { EstimatedFeeData, SourceToken } from '../types'\nimport { resolveTokenAddress } from '../utils/fees'\nimport {\n AcrossSuggestedFeesSchema,\n type FeeBreakdown,\n parseAcrossFees,\n parseRelayFees,\n RelayQuoteSchema,\n} from '../utils/providerFees'\n\nconst ACROSS_API = 'https://app.across.to/api/suggested-fees'\nconst RELAY_API = 'https://api.relay.link/quote'\n// Quotes barely depend on the caller; used only when no recipient is known\nconst QUOTE_USER: Address = '0x1111111111111111111111111111111111111111'\n\ntype Route = {\n tokenType: TOKEN_TYPE\n originChainId: number\n destinationChainId: number\n amount: string\n user: Address\n symbol: string\n decimals: number\n}\n\n/** Across is keyed by ERC-20 addresses; native is quoted via its wrapped form */\nfunction acrossToken(tokenType: TOKEN_TYPE, chainId: number): Address | null {\n if (tokenType === 'NATIVE') return resolveTokenAddress('WETH', chainId)\n return resolveTokenAddress(tokenType, chainId)\n}\n\n/** Relay represents native as the zero address; ERC-20s by their address */\nfunction relayToken(tokenType: TOKEN_TYPE, chainId: number): Address | null {\n if (tokenType === 'NATIVE') return zeroAddress\n return resolveTokenAddress(tokenType, chainId)\n}\n\nasync function fetchAcross(\n route: Route,\n signal: AbortSignal,\n): Promise<FeeBreakdown | null> {\n const inputToken = acrossToken(route.tokenType, route.originChainId)\n const outputToken = acrossToken(route.tokenType, route.destinationChainId)\n if (!inputToken || !outputToken) return null\n const params = new URLSearchParams({\n inputToken,\n outputToken,\n originChainId: String(route.originChainId),\n destinationChainId: String(route.destinationChainId),\n amount: route.amount,\n })\n const res = await fetch(`${ACROSS_API}?${params}`, { signal })\n if (!res.ok) return null\n const json = await res.json()\n if (!json || json.error) return null\n // Validate the response shape before handing it to the parser — if Across\n // changes their API in a way we don't recognise, we degrade gracefully to\n // the collapsed fee view instead of computing garbage from missing fields.\n const parsed = AcrossSuggestedFeesSchema.safeParse(json)\n if (!parsed.success) {\n // biome-ignore lint/suspicious/noConsole: schema-drift signal for developers; silent failure is what we're trying to avoid.\n console.warn(\n '[useProviderFees] Across response failed schema validation',\n parsed.error.issues,\n )\n return null\n }\n return parseAcrossFees(parsed.data, route.symbol, route.decimals)\n}\n\nasync function fetchRelay(\n route: Route,\n signal: AbortSignal,\n): Promise<FeeBreakdown | null> {\n const originCurrency = relayToken(route.tokenType, route.originChainId)\n const destinationCurrency = relayToken(\n route.tokenType,\n route.destinationChainId,\n )\n if (!originCurrency || !destinationCurrency) return null\n const res = await fetch(RELAY_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n signal,\n body: JSON.stringify({\n user: route.user,\n recipient: route.user,\n originChainId: route.originChainId,\n destinationChainId: route.destinationChainId,\n originCurrency,\n destinationCurrency,\n amount: route.amount,\n tradeType: 'EXACT_INPUT',\n }),\n })\n if (!res.ok) return null\n const json = await res.json()\n if (!json || json.error) return null\n // See fetchAcross above — schema validation is the last line of defence\n // between a silently changed API and wrong fees rendered to the user.\n const parsed = RelayQuoteSchema.safeParse(json)\n if (!parsed.success) {\n // biome-ignore lint/suspicious/noConsole: schema-drift signal for developers; silent failure is what we're trying to avoid.\n console.warn(\n '[useProviderFees] Relay response failed schema validation',\n parsed.error.issues,\n )\n return null\n }\n return parseRelayFees(parsed.data)\n}\n\n/** Pick the cheaper live route by full quoted cost; else the first available */\nfunction bestRoute(routes: (FeeBreakdown | null)[]): FeeBreakdown | null {\n const available = routes.filter((r): r is FeeBreakdown => r !== null)\n if (available.length === 0) return null\n const withUsd = available.filter((r) => r.quotedTotalUsd !== null)\n if (withUsd.length === 0) return available[0] ?? null\n return withUsd.reduce((best, r) =>\n (r.quotedTotalUsd as number) < (best.quotedTotalUsd as number) ? r : best,\n )\n}\n\nexport type ProviderFeesState = {\n /** Cheapest normalised quote, or null while loading / unquotable */\n fees: FeeBreakdown | null\n /** True from the moment the route changes until the quotes resolve */\n loading: boolean\n}\n\n/**\n * Fetch live fee quotes for the selected route from every supported provider\n * (Across + Relay), normalise them, and return the cheapest. Across and Relay\n * expose the itemised bridge legs the SRA fee estimate alone does not, so this\n * enriches the breakdown with how the user is actually charged and which route\n * is currently best.\n *\n * Returns null while loading, for routes that can't be quoted (native /\n * unresolvable tokens), or when every request fails — callers fall back to\n * the SRA execution fee on their own.\n */\nexport function useProviderFees(\n source: SourceToken | null,\n destChain: Chain,\n feeData: EstimatedFeeData | null,\n recipient?: string,\n): ProviderFeesState {\n const [breakdown, setBreakdown] = useState<FeeBreakdown | null>(null)\n const [loading, setLoading] = useState(false)\n\n const sourceChainId = source?.chain.id\n const tokenType = source?.tokenType\n const destChainId = destChain.id\n const minDeposit = feeData?.minDeposit\n const symbol = feeData?.name\n const decimals = feeData?.decimal\n\n useEffect(() => {\n setBreakdown(null)\n if (\n tokenType === undefined ||\n sourceChainId === undefined ||\n !minDeposit ||\n symbol === undefined ||\n decimals === undefined\n ) {\n setLoading(false)\n return\n }\n setLoading(true)\n\n let amount: string\n try {\n amount = BigInt(minDeposit).toString()\n } catch {\n // Malformed `minDeposit` — nothing to quote. Clear loading so the\n // caller doesn't sit in a spinner forever until the route changes.\n setLoading(false)\n return\n }\n\n const route: Route = {\n tokenType,\n originChainId: sourceChainId,\n destinationChainId: destChainId,\n amount,\n user: (recipient as Address) || QUOTE_USER,\n symbol,\n decimals,\n }\n\n const controller = new AbortController()\n // Swallow provider failures so one broken provider doesn't take out the\n // other — but log everything except the expected abort so a real bug\n // (network, parser regression) doesn't disappear silently.\n const safe = (label: string, p: Promise<FeeBreakdown | null>) =>\n p.catch((err) => {\n if (err?.name !== 'AbortError') {\n // biome-ignore lint/suspicious/noConsole: surfaces network / parser regressions that would otherwise be invisible.\n console.warn(`[useProviderFees] ${label} failed`, err)\n }\n return null\n })\n Promise.all([\n safe('Across', fetchAcross(route, controller.signal)),\n safe('Relay', fetchRelay(route, controller.signal)),\n ])\n .then(([across, relay]) => {\n const chosen = bestRoute([across, relay])\n if (!controller.signal.aborted) {\n setBreakdown(chosen)\n setLoading(false)\n }\n })\n .catch(() => {\n // All providers failed → caller shows the SRA fee\n if (!controller.signal.aborted) setLoading(false)\n })\n return () => controller.abort()\n }, [\n sourceChainId,\n tokenType,\n destChainId,\n minDeposit,\n symbol,\n decimals,\n recipient,\n ])\n\n return { fees: breakdown, loading }\n}\n","import {\n ArrowCardPair,\n cn,\n DataRow,\n Icon,\n Pill,\n Select,\n SelectContent,\n SelectIcon,\n SelectItem,\n SelectTrigger,\n Text,\n TokenListItem,\n Tooltip,\n WrappedPressable,\n Wrapper,\n} from '@zerodev/react-ui'\nimport type { DepositedToken, TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { AddressDisplay } from '../components/AddressDisplay'\nimport { ErrorRetryCard } from '../components/ErrorRetryCard'\nimport {\n FeeBreakdownRows,\n FeeSummary,\n LiveValue,\n} from '../components/FeeBreakdown'\nimport { FEE_INFO } from '../components/FeeBreakdown/feeInfo'\nimport { LoadingCard } from '../components/LoadingCard'\nimport { PendingDeposits } from '../components/PendingDeposits'\nimport { DEFAULT_FILL_TIME_SECONDS } from '../constants'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { useDepositStatus } from '../hooks/useDepositStatus'\nimport { useNewDeposits } from '../hooks/useNewDeposits'\nimport { useProviderFees } from '../hooks/useProviderFees'\nimport { CHAIN_ICONS, PROVIDER_ICONS, TOKEN_ICONS } from '../iconAssets'\nimport type { SourceToken } from '../types'\nimport {\n getSourceTokenSymbol,\n resolveBaseUrl,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../utils/config'\nimport { findFeeData, resolveTokenAddress } from '../utils/fees'\nimport {\n formatDisplayAmount,\n formatDuration,\n formatSlippage,\n} from '../utils/format'\nimport { buildFeeBreakdown } from '../utils/providerFees'\n\nexport interface DepositProps {\n onQrClick?: () => void\n /** Navigate to the \"Past deposits\" view. When omitted, the row is hidden. */\n onViewPastDeposits?: () => void\n /** Fired when a pending-deposit row is tapped. Wires through to\n * `PendingDeposits` so an in-flight deposit opens the transaction-details\n * view, matching the past-deposits behaviour. */\n onSelectDeposit?: (deposit: DepositedToken) => void\n}\n\nconst SUBTITLE =\n \"Send any supported token from any network. We'll swap & bridge it directly to your account, ready to use.\"\n\n// The two picker panels span the full pill row (Figma \"Send\" layout), not\n// just the trigger cell each Select lives in. Trigger width = half the row\n// minus half the 4px gap, so full-row width = trigger * 2 + 4px.\nconst FULL_ROW_PANEL_STYLE = {\n width: 'calc(var(--radix-select-trigger-width) * 2 + 4px)',\n}\n\nexport function Deposit({\n onQrClick,\n onViewPastDeposits,\n onSelectDeposit,\n}: DepositProps) {\n const { config, addressState, recipient, retry, setActiveRoute } =\n useSmartRoutingAddressContext()\n const [feeOpen, setFeeOpen] = useState(false)\n const [retrying, setRetrying] = useState(false)\n\n const success = addressState.status === 'success' ? addressState : null\n const address = success?.address\n const estimatedFees = success?.estimatedFees ?? []\n\n // allowPartialRoutes lets the server drop source tokens it can't route, so\n // the routable set is exactly the tokens the fee estimates came back with.\n const srcTokens = useMemo(\n () => sourceTokensFromFees(estimatedFees),\n [estimatedFees],\n )\n\n // Track the user's picker selection. `null` means \"no explicit choice yet\" —\n // an effect below seeds it to the first routable option once srcTokens land.\n const [selectedTokenType, setSelectedTokenType] = useState<TOKEN_TYPE | null>(\n null,\n )\n const [selectedChainId, setSelectedChainId] = useState<number | null>(null)\n\n // Seed picker state from the first routable option as soon as srcTokens\n // arrive. Also re-seeds if a stale selection becomes unroutable.\n useEffect(() => {\n if (srcTokens.length === 0) return\n const currentValid = srcTokens.some(\n (t) =>\n t.tokenType === selectedTokenType && t.chain.id === selectedChainId,\n )\n if (currentValid) return\n // Prefer to keep the token, swap the chain to one that's available for it.\n const forSameToken = srcTokens.find(\n (t) => t.tokenType === selectedTokenType,\n )\n const fallback = forSameToken ?? srcTokens[0]\n if (!fallback) return\n setSelectedTokenType(fallback.tokenType)\n setSelectedChainId(fallback.chain.id)\n }, [srcTokens, selectedTokenType, selectedChainId])\n\n const source: SourceToken | null = useMemo(() => {\n if (!selectedTokenType || selectedChainId === null) {\n return srcTokens[0] ?? null\n }\n return (\n srcTokens.find(\n (t) =>\n t.tokenType === selectedTokenType && t.chain.id === selectedChainId,\n ) ??\n srcTokens[0] ??\n null\n )\n }, [srcTokens, selectedTokenType, selectedChainId])\n\n const {\n deposits,\n hasLoaded,\n error: depositsError,\n refetch: refetchDeposits,\n } = useDepositStatus({\n address,\n baseUrl: resolveBaseUrl(config),\n })\n const newDeposits = useNewDeposits(deposits, hasLoaded)\n const pastDepositsCount = deposits.length - newDeposits.length\n\n const destChain = resolveDestChain(config)\n // Widget's default actions forward the deposited token, so the destination\n // token equals the source token — one symbol and logo serve both cards.\n // Only the chain differs, hence the source/dest split below.\n const tokenSymbol = source ? getSourceTokenSymbol(source) : undefined\n const tokenLogo = tokenSymbol\n ? TOKEN_ICONS[tokenSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = source ? CHAIN_ICONS[source.chain.id] : undefined\n const destChainLogo = CHAIN_ICONS[destChain.id]\n const feeData = source\n ? findFeeData(estimatedFees, source.chain.id, source.tokenType)\n : null\n const fillTime = formatDuration(DEFAULT_FILL_TIME_SECONDS)\n\n // Live bridge quotes from Across / Relay, keyed off the selected route.\n // Enriches the SRA fee estimate with the itemised legs it doesn't expose.\n const providerFees = useProviderFees(source, destChain, feeData, recipient)\n const breakdown =\n feeData && tokenSymbol\n ? buildFeeBreakdown(feeData, tokenSymbol, providerFees.fees)\n : null\n\n // Publish the current picker selection so hosts (e.g. a demo \"send\" panel)\n // can mirror the widget's route. Cleared when the picker is empty so\n // downstream mocks show their fallback instead of stale state.\n useEffect(() => {\n if (!source || !feeData || !tokenSymbol) {\n setActiveRoute(null)\n return\n }\n const token = resolveTokenAddress(source.tokenType, source.chain.id)\n if (!token) {\n setActiveRoute(null)\n return\n }\n setActiveRoute({\n sourceChainId: source.chain.id,\n sourceChainName: source.chain.name,\n token,\n symbol: tokenSymbol,\n decimals: feeData.decimal,\n // `feeData.fee` is a `Hex` string from the SDK — normalise to a\n // decimal atomic-units string here so `activeRoute.feeAmount` has\n // one consistent representation across every write path (see\n // `ActiveRoute.feeAmount` — the demo's fallback uses decimals too).\n // Hosts using `BigInt()` work either way, but `Number()` /\n // `parseInt(x, 10)` would silently misread the hex form.\n feeAmount: BigInt(feeData.fee).toString(),\n })\n }, [source, feeData, tokenSymbol, setActiveRoute])\n\n // Deduped list of routable token types — the token picker's rows. Chain\n // count per token drives the subtitle. Kept as SourceToken (not a bespoke\n // dropdown-item shape) so the render below can call the same helpers used\n // for the trigger.\n const uniqueTokens = useMemo(() => {\n const seen = new Set<TOKEN_TYPE>()\n const out: SourceToken[] = []\n for (const token of srcTokens) {\n if (seen.has(token.tokenType)) continue\n seen.add(token.tokenType)\n out.push(token)\n }\n return out\n }, [srcTokens])\n\n // Chains that carry the currently-selected token — the chain picker's rows.\n const availableChains = useMemo(() => {\n if (!selectedTokenType) return []\n const seen = new Set<number>()\n const out: SourceToken[] = []\n for (const token of srcTokens) {\n if (token.tokenType !== selectedTokenType) continue\n if (seen.has(token.chain.id)) continue\n seen.add(token.chain.id)\n out.push(token)\n }\n return out\n }, [srcTokens, selectedTokenType])\n\n // Always present: config.slippage is required now that the SRA server no\n // longer supplies a default.\n const slippage = formatSlippage(config.slippage)\n\n const minDepositAmount =\n feeData && tokenSymbol\n ? `${formatDisplayAmount(feeData.minDeposit, feeData.decimal, 'up')} ${tokenSymbol}`\n : null\n\n // Flash key re-triggers the LiveValue animation on the estimated-fee row\n // when the underlying quote changes; combining every meaningful component\n // catches all updates in one dependency.\n const feeFlashKey = breakdown\n ? `${breakdown.totalText ?? ''}|${breakdown.ratePct ?? ''}|${breakdown.flatUsd ?? ''}`\n : ''\n\n const pickerDisabled = uniqueTokens.length === 0\n const sourceChainName = source?.chain.name\n\n // Error surfaces the retry card handles. Only one is shown at a time,\n // matched top-down in severity order: (1) address creation itself failed,\n // (2) creation succeeded but no routes came back, (3) deposit polling is\n // erroring after we already have an address. `hasLoaded` gates the polling\n // case so first-load latency isn't mistaken for an error.\n const addressError = addressState.status === 'error'\n const noRoutesError = !!success && srcTokens.length === 0\n const pollingError = !!address && !!depositsError && hasLoaded\n const errorMessage = addressError\n ? 'Failed to create deposit address...'\n : noRoutesError\n ? 'No routes found, try one more time...'\n : pollingError\n ? 'Failed to load deposits, try again...'\n : null\n\n const handleRetry = useCallback(async () => {\n if (retrying) return\n setRetrying(true)\n try {\n if (pollingError && !addressError && !noRoutesError) {\n refetchDeposits()\n } else {\n await retry()\n }\n } finally {\n setRetrying(false)\n }\n }, [\n retrying,\n pollingError,\n addressError,\n noRoutesError,\n refetchDeposits,\n retry,\n ])\n\n return (\n // min-h-full, not h-full: with a fixed height, overflowing content\n // scrolls past the padding box and pb-6 never lands after the last row\n // (the \"Past deposits\" row hits the bottom edge). min-h keeps short\n // content filling the viewport while letting tall content grow so the\n // bottom padding is honoured.\n <div className=\"zd:flex zd:min-h-full zd:w-full zd:flex-col zd:items-center zd:gap-4 zd:pt-4 zd:pb-6\">\n <Text className=\"zd:w-full zd:text-center\">{SUBTITLE}</Text>\n\n <div className=\"zd:relative zd:flex zd:w-full zd:flex-1 zd:flex-col zd:gap-2\">\n <ArrowCardPair\n topCard={\n <Wrapper\n variant=\"ghost\"\n className=\"zd:relative zd:flex zd:w-full zd:flex-col zd:rounded-2xl zd:p-1\"\n >\n <CardTitle>Send</CardTitle>\n <PillRow\n left={\n <Select\n value={selectedTokenType ?? ''}\n onValueChange={(id) =>\n setSelectedTokenType(id as TOKEN_TYPE)\n }\n disabled={pickerDisabled}\n >\n <SelectTrigger asChild>\n <Pill\n label={tokenSymbol ?? ''}\n {...(tokenLogo && { logoUri: tokenLogo })}\n disabled={pickerDisabled}\n loading={!tokenSymbol}\n trailingIcon={!pickerDisabled && <SelectIcon />}\n />\n </SelectTrigger>\n <SelectContent align=\"start\" style={FULL_ROW_PANEL_STYLE}>\n {uniqueTokens.map((token, i) => {\n const symbol = getSourceTokenSymbol(token)\n const chainCount = srcTokens.filter(\n (t) => t.tokenType === token.tokenType,\n ).length\n const logo = TOKEN_ICONS[symbol.toUpperCase()]\n return (\n <SelectItem\n key={token.tokenType}\n value={token.tokenType}\n textValue={symbol}\n className=\"zd:p-0\"\n >\n <TokenListItem\n symbol={symbol}\n subtitle={`${chainCount} network${chainCount === 1 ? '' : 's'}`}\n {...(logo && { imageSource: logo })}\n />\n {i === 0 && (\n <span className=\"zd:absolute zd:top-1/2 zd:right-3 zd:-translate-y-1/2 zd:inline-flex zd:items-center zd:rounded-full zd:bg-positive/15 zd:px-2 zd:py-1 zd:text-body3 zd:text-positive zd:pointer-events-none\">\n Recommended\n </span>\n )}\n </SelectItem>\n )\n })}\n </SelectContent>\n </Select>\n }\n right={\n <Select\n value={\n selectedChainId !== null ? String(selectedChainId) : ''\n }\n onValueChange={(id) => setSelectedChainId(Number(id))}\n disabled={pickerDisabled}\n >\n <SelectTrigger asChild>\n <Pill\n label={sourceChainName ?? ''}\n {...(sourceChainLogo && { logoUri: sourceChainLogo })}\n disabled={pickerDisabled}\n loading={!sourceChainName}\n trailingIcon={!pickerDisabled && <SelectIcon />}\n />\n </SelectTrigger>\n <SelectContent align=\"end\" style={FULL_ROW_PANEL_STYLE}>\n {availableChains.map((token) => {\n const logo = CHAIN_ICONS[token.chain.id]\n return (\n <SelectItem\n key={token.chain.id}\n value={String(token.chain.id)}\n textValue={token.chain.name}\n className=\"zd:p-0\"\n >\n <TokenListItem\n symbol={token.chain.name}\n iconVariant=\"network\"\n {...(logo && { imageSource: logo })}\n />\n </SelectItem>\n )\n })}\n </SelectContent>\n </Select>\n }\n />\n <div className=\"zd:flex zd:w-full zd:flex-col zd:items-start zd:gap-2 zd:px-2 zd:py-4\">\n <DataRow\n label=\"Max slippage\"\n value={slippage}\n info\n infoTooltip={FEE_INFO.maxSlippage}\n trailing={\n breakdown?.provider &&\n PROVIDER_ICONS[breakdown.provider] ? (\n <LiveValue\n loading={providerFees.loading}\n flashKey={breakdown.provider}\n >\n <Tooltip content={`Quoted via ${breakdown.provider}`}>\n <button\n type=\"button\"\n aria-label={`Quoted via ${breakdown.provider}`}\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-help zd:outline-none zd:bg-transparent\"\n >\n <img\n src={PROVIDER_ICONS[breakdown.provider]}\n alt=\"\"\n aria-hidden\n className=\"zd:size-4 zd:shrink-0 zd:rounded-[4px] zd:object-cover\"\n />\n </button>\n </Tooltip>\n </LiveValue>\n ) : null\n }\n />\n <DataRow\n label=\"Estimated fee\"\n value={\n breakdown ? (\n <LiveValue\n loading={providerFees.loading}\n flashKey={feeFlashKey}\n >\n <FeeSummary breakdown={breakdown} />\n </LiveValue>\n ) : (\n // Match Min deposit's skeleton so both loading\n // affordances share one visual language.\n <div className=\"zd:h-3.5 zd:w-20 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse\" />\n )\n }\n info\n infoTooltip={FEE_INFO.estimatedFee}\n trailing={\n breakdown ? (\n <button\n type=\"button\"\n onClick={() => setFeeOpen((prev) => !prev)}\n aria-expanded={feeOpen}\n aria-label={\n feeOpen ? 'Hide fee details' : 'Show fee details'\n }\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-pointer\"\n >\n <Icon\n name={feeOpen ? 'chevronUp' : 'chevronDown'}\n className=\"zd:w-3.5 zd:h-3.5 zd:text-greyScale\"\n />\n </button>\n ) : null\n }\n />\n {feeOpen && breakdown && (\n <FeeBreakdownRows breakdown={breakdown} />\n )}\n </div>\n </Wrapper>\n }\n bottomCard={\n <Wrapper\n variant=\"ghost\"\n className=\"zd:relative zd:flex zd:w-full zd:flex-col zd:gap-2 zd:rounded-2xl zd:p-1\"\n >\n <CardTitle>Arrives as</CardTitle>\n <PillRow\n left={\n <Pill\n label={tokenSymbol ?? ''}\n {...(tokenLogo && { logoUri: tokenLogo })}\n disabled\n loading={!tokenSymbol}\n />\n }\n right={\n <Pill\n label={destChain.name}\n {...(destChainLogo && { logoUri: destChainLogo })}\n disabled\n />\n }\n />\n <div className=\"zd:flex zd:w-full zd:flex-col zd:items-start zd:px-2\">\n <DataRow\n label=\"Ready in\"\n value={fillTime}\n info\n infoTooltip={FEE_INFO.readyIn}\n />\n </div>\n <AddressDisplay\n status={addressState.status}\n address={address}\n onQrClick={onQrClick}\n />\n {address && <CopyAddressButton address={address} />}\n {errorMessage && (\n <ErrorRetryCard\n message={errorMessage}\n onRetry={handleRetry}\n busy={retrying}\n />\n )}\n <DataRow\n label=\"Min deposit\"\n value={\n minDepositAmount ?? (\n // Match PillSkeleton's greyish pulse so all loading\n // affordances in this card share one visual language.\n // `<output>` gets an implicit `role=\"status\"` — biome's\n // `useSemanticElements` prefers it over `<div role>`.\n // `aria-busy` + `aria-label` so screen readers hear\n // \"loading\" instead of landing on an empty region.\n <output\n aria-busy=\"true\"\n aria-label=\"Loading minimum deposit\"\n className=\"zd:block zd:h-3.5 zd:w-20 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse\"\n />\n )\n }\n info\n infoTooltip={FEE_INFO.minDeposit}\n variant=\"warning\"\n />\n </Wrapper>\n }\n />\n\n {/* Deposit watching only makes sense once the address exists —\n while creation is loading (or failed) there is nothing to watch,\n so neither card renders. */}\n {address &&\n (newDeposits.length > 0 ? (\n <PendingDeposits\n deposits={newDeposits}\n estimatedFees={estimatedFees}\n config={config}\n {...(onSelectDeposit && { onSelectDeposit })}\n />\n ) : (\n <LoadingCard\n text={\n source\n ? `Watching for your deposit on ${source.chain.name}…`\n : 'Watching for your deposit…'\n }\n />\n ))}\n\n {pastDepositsCount > 0 &&\n (onViewPastDeposits ? (\n <WrappedPressable\n onClick={onViewPastDeposits}\n className={cn('zd:w-full', PAST_DEPOSITS_CARD)}\n >\n <PastDepositsRow count={pastDepositsCount} />\n </WrappedPressable>\n ) : (\n <Wrapper\n variant=\"ghost\"\n className={cn(\n 'zd:flex zd:w-full zd:items-center',\n PAST_DEPOSITS_CARD,\n )}\n >\n <PastDepositsRow count={pastDepositsCount} />\n </Wrapper>\n ))}\n </div>\n </div>\n )\n}\n\n/**\n * Full-width dark \"Copy Address\" pill under the address row (Figma\n * `20002:36049`). Not react-ui's `Button`: that primitive is locked to the\n * 64px/24px-radius spec, while this is the design system's smaller\n * 48px/14px button — worth promoting as a Button size variant if it\n * recurs. Label flips to \"Copied!\" for 2s as tap feedback (the design has\n * no pressed state).\n */\nfunction CopyAddressButton({ address }: { address: string }) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(address)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard can reject on insecure contexts / denied permission —\n // keep the label unchanged rather than claim a copy happened.\n }\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n 'zd:relative zd:flex zd:h-12 zd:w-full zd:shrink-0 zd:cursor-pointer zd:items-center zd:justify-center zd:gap-2',\n 'zd:rounded-[14px] zd:backdrop-blur-[15px] zd:transition-colors zd:hover:bg-greyScale',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n )}\n style={{ backgroundColor: 'rgba(19, 14, 11, 0.9)' }}\n >\n <Text className=\"zd:text-body1 zd:text-offWhite\">\n {copied ? 'Copied!' : 'Copy Address'}\n </Text>\n <Icon\n name=\"copy\"\n className=\"zd:size-4 zd:shrink-0 zd:text-offWhite\"\n aria-hidden\n />\n </button>\n )\n}\n\n// Past-deposits card treatment (Figma 20002:36111): 16px radius plus the\n// universal inner shadow; border/blur/tint come from the ghost Wrapper.\nconst PAST_DEPOSITS_CARD =\n 'zd:rounded-2xl zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]'\n\n/** Row content shared by the tappable and inert past-deposits variants. */\nfunction PastDepositsRow({ count }: { count: number }) {\n return (\n <div className=\"zd:flex zd:w-full zd:items-center zd:gap-3 zd:p-4\">\n <div className=\"zd:flex zd:min-w-0 zd:flex-1 zd:items-center zd:gap-2\">\n <Icon\n name=\"clockFill\"\n className=\"zd:size-4 zd:shrink-0 zd:text-solarOrange\"\n aria-hidden\n />\n <Text className=\"zd:flex-1 zd:text-left zd:text-h3\">\n Past deposits ({count})\n </Text>\n </div>\n <Icon\n name=\"chevronRight\"\n className=\"zd:size-4.5 zd:shrink-0 zd:text-greyScale\"\n aria-hidden\n />\n </div>\n )\n}\n\nfunction CardTitle({ children }: { children: string }) {\n return (\n <div className={cn('zd:flex zd:items-center zd:px-2 zd:py-3')}>\n <Text className=\"zd:whitespace-nowrap zd:text-h3\">{children}</Text>\n </div>\n )\n}\n\nfunction PillRow({\n left,\n right,\n}: {\n left: React.ReactNode\n right: React.ReactNode\n}) {\n return (\n <div className=\"zd:flex zd:w-full zd:items-start zd:gap-1\">\n <div className=\"zd:min-w-0 zd:flex-1\">{left}</div>\n <div className=\"zd:min-w-0 zd:flex-1\">{right}</div>\n </div>\n )\n}\n","import { cn, Icon, Text } from '@zerodev/react-ui'\nimport type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { useMemo } from 'react'\nimport { TxnItem, type TxnStatus } from '../components/TxnItem'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { useDepositStatus } from '../hooks/useDepositStatus'\nimport { CHAIN_ICONS, TOKEN_ICONS } from '../iconAssets'\nimport type { DepositStage, DepositWithTimestamp } from '../types'\nimport { getTxUrl } from '../utils/chains'\nimport {\n getSourceTokenSymbol,\n resolveBaseUrl,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../utils/config'\nimport { getDepositStage } from '../utils/deposits'\nimport { findFeeDataByToken, tokenAddressMatches } from '../utils/fees'\nimport {\n formatDisplayAmount,\n formatRelativeTime,\n truncateAddress,\n} from '../utils/format'\n\nconst STAGE_TO_STATUS: Record<DepositStage, TxnStatus> = {\n pending: 'Detected',\n bridging: 'Routing',\n // Past deposits use the terminal label — \"Received\" (plain ink) is the\n // active list's arrival state; \"Delivered\" renders green.\n completed: 'Delivered',\n failed: 'Failed',\n}\n\ntype Group = { label: string; sortKey: number; items: DepositWithTimestamp[] }\n\nfunction dayStart(timestamp: number): number {\n const d = new Date(timestamp)\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime()\n}\n\nfunction groupLabel(timestamp: number | undefined): {\n label: string\n sortKey: number\n} {\n if (!timestamp) return { label: 'Recent', sortKey: -1 }\n const today = dayStart(Date.now())\n const day = dayStart(timestamp)\n if (day === today) return { label: 'Today', sortKey: today }\n if (day === today - 86_400_000) return { label: 'Yesterday', sortKey: day }\n return {\n label: new Intl.DateTimeFormat('en-US', {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n }).format(new Date(timestamp)),\n sortKey: day,\n }\n}\n\nfunction groupByDay(deposits: DepositWithTimestamp[]): Group[] {\n const buckets = new Map<string, Group>()\n for (const deposit of deposits) {\n const timestamp = deposit.createdAt\n ? Date.parse(deposit.createdAt)\n : undefined\n const { label, sortKey } = groupLabel(\n timestamp && !Number.isNaN(timestamp) ? timestamp : undefined,\n )\n const existing = buckets.get(label)\n if (existing) existing.items.push(deposit)\n else buckets.set(label, { label, sortKey, items: [deposit] })\n }\n return [...buckets.values()].sort((a, b) => b.sortKey - a.sortKey)\n}\n\nexport interface PastDepositsProps {\n /** Fired when a row is tapped — the widget uses this to open the\n * transaction-details view for the selected deposit. When omitted, rows\n * render as static (non-interactive). */\n onSelectDeposit?: (deposit: DepositedToken) => void\n}\n\n/**\n * Past deposits view — full history, grouped by day, newest first. Each row\n * is a `TxnItem`; layout matches the deposit's `PendingDeposits` card so the\n * two views share one visual language.\n */\nexport function PastDeposits({ onSelectDeposit }: PastDepositsProps) {\n const { config, addressState } = useSmartRoutingAddressContext()\n\n const success = addressState.status === 'success' ? addressState : null\n const address = success?.address\n const estimatedFees = success?.estimatedFees ?? []\n\n const { deposits, hasLoaded } = useDepositStatus({\n address,\n baseUrl: resolveBaseUrl(config),\n })\n\n const destChain = resolveDestChain(config)\n const destChainLogo = CHAIN_ICONS[destChain.id]\n\n const groups = useMemo(\n () => groupByDay(deposits as DepositWithTimestamp[]),\n [deposits],\n )\n\n return (\n <div className=\"zd:flex zd:h-full zd:w-full zd:flex-col zd:gap-4 zd:pt-4 zd:pb-6\">\n <section\n aria-label=\"Past deposits\"\n className={cn(\n 'zd:relative zd:flex zd:w-full zd:flex-1 zd:min-h-0 zd:flex-col zd:overflow-hidden zd:rounded-2xl zd:p-2',\n 'zd:border-offWhite zd:border-[0.3px] zd:bg-white/20',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n )}\n >\n {!hasLoaded ? (\n <output\n aria-label=\"Loading past deposits\"\n className=\"zd:flex zd:flex-1 zd:items-center zd:justify-center zd:py-8\"\n >\n <Icon\n name=\"loading\"\n className=\"zd:size-5 zd:animate-spin zd:text-orange\"\n aria-hidden\n />\n </output>\n ) : deposits.length === 0 ? (\n <div className=\"zd:flex zd:flex-1 zd:items-center zd:justify-center zd:py-8\">\n <Text className=\"zd:text-greyScale/50\">No deposits yet</Text>\n </div>\n ) : (\n <div className=\"zd:flex zd:flex-1 zd:flex-col zd:gap-1 zd:overflow-y-auto\">\n {groups.map((group) => (\n <section key={group.label} className=\"zd:flex zd:flex-col\">\n <div className=\"zd:px-2 zd:py-2\">\n <Text className=\"zd:text-body3 zd:text-greyScale\">\n {group.label}\n </Text>\n </div>\n <ul className=\"zd:flex zd:flex-col\">\n {group.items.map((deposit) => {\n const { chainId, token, amount, transactionHash } =\n deposit.deposit\n const feeData = findFeeDataByToken(\n estimatedFees,\n chainId,\n token,\n )\n // Match on the on-chain address (via `tokenAddressMatches`)\n // — the server's `feeData.name` is a display symbol (e.g.\n // \"ETH\"), not the TOKEN_TYPE (\"NATIVE\"), so a direct\n // tokenType === name compare misses native tokens.\n const source =\n sourceTokensFromFees(estimatedFees).find(\n (t) =>\n t.chain.id === chainId &&\n tokenAddressMatches(t.tokenType, chainId, token),\n ) ?? null\n // Prefer the reconstructed source's symbol; fall back to\n // the server's `feeData.name` so past deposits whose route\n // dropped out of the current fee estimates still get a\n // symbol / icon.\n const sourceSymbol = source\n ? getSourceTokenSymbol(source)\n : (feeData?.name ?? '')\n const sourceTokenLogo = sourceSymbol\n ? TOKEN_ICONS[sourceSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = CHAIN_ICONS[chainId]\n // Destination token equals source token — widget's default\n // actions forward the deposited asset unchanged.\n const destTokenLogo = sourceTokenLogo\n const amountLabel = feeData\n ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`\n : String(amount)\n const timestamp = deposit.createdAt\n ? (formatRelativeTime(deposit.createdAt) ?? '')\n : ''\n // Explorer URL from the chain id alone — independent of\n // whether the deposit's token matched the current fees.\n const href = getTxUrl(chainId, transactionHash)\n const status = STAGE_TO_STATUS[getDepositStage(deposit)]\n // Delivered amount for the detailed row headline\n // (`amount → destAmount`). `'nearest'` rounding — the\n // server reports the actual post-fee on-chain amount and\n // users read this as \"what I received\". Falls back to the\n // deposited amount while execution details are absent so\n // the detailed layout stays stable across stages.\n const destAmountLabel =\n deposit.execution?.outputAmount && feeData\n ? `${formatDisplayAmount(deposit.execution.outputAmount, feeData.decimal, 'nearest')} ${sourceSymbol}`\n : amountLabel\n\n const row = (\n <TxnItem\n amount={amountLabel}\n destAmount={destAmountLabel}\n address={truncateAddress(transactionHash)}\n {...(href && { href })}\n timestamp={timestamp}\n status={status}\n {...(source?.chain.name && {\n sourceChainName: source.chain.name,\n })}\n destChainName={destChain.name}\n {...(sourceTokenLogo && {\n sourceTokenIconUrl: sourceTokenLogo,\n })}\n {...(sourceChainLogo && {\n sourceChainIconUrl: sourceChainLogo,\n })}\n {...(destTokenLogo && {\n destTokenIconUrl: destTokenLogo,\n })}\n {...(destChainLogo && {\n destChainIconUrl: destChainLogo,\n })}\n />\n )\n return (\n <li key={transactionHash}>\n {onSelectDeposit ? (\n // No padding of its own: the TxnItem's built-in\n // p-2 (the Figma Txn Row inset) doubles as the\n // hover highlight's breathing room. Radius matches\n // the row's rounded-2xl.\n <button\n type=\"button\"\n onClick={() => onSelectDeposit(deposit)}\n className=\"zd:w-full zd:cursor-pointer zd:rounded-2xl zd:text-left zd:hover:bg-white/30\"\n >\n {row}\n </button>\n ) : (\n row\n )}\n </li>\n )\n })}\n </ul>\n </section>\n ))}\n </div>\n )}\n </section>\n </div>\n )\n}\n","import {\n ArrowCardPair,\n cn,\n DataRow,\n Icon,\n InfoCard,\n ProgressStep,\n Section,\n Text,\n} from '@zerodev/react-ui'\nimport { useState } from 'react'\nimport { FeeBreakdownRows, FeeSummary } from '../components/FeeBreakdown'\nimport { FEE_INFO } from '../components/FeeBreakdown/feeInfo'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { useDepositStatus } from '../hooks/useDepositStatus'\nimport { useProviderFees } from '../hooks/useProviderFees'\nimport { CHAIN_ICONS, PROVIDER_ICONS, TOKEN_ICONS } from '../iconAssets'\nimport type { DepositWithTimestamp } from '../types'\nimport { getTxUrl } from '../utils/chains'\nimport {\n getSourceTokenSymbol,\n resolveBaseUrl,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../utils/config'\nimport { getDepositStage } from '../utils/deposits'\nimport { findFeeDataByToken, tokenAddressMatches } from '../utils/fees'\nimport { formatDisplayAmount, truncateAddress } from '../utils/format'\nimport { buildFeeBreakdown } from '../utils/providerFees'\n\nexport interface TransactionDetailsProps {\n deposit: DepositWithTimestamp\n}\n\n/**\n * Poll the deposits list and return the latest snapshot of the deposit\n * matching `initial.deposit.transactionHash`, falling back to `initial` until\n * the first response lands (or if the deposit falls out of the list). Keeps\n * the details view live while the same interval is already running in\n * `Deposit` / `PastDeposits`.\n */\nfunction useLiveDeposit(initial: DepositWithTimestamp): DepositWithTimestamp {\n const { config, addressState } = useSmartRoutingAddressContext()\n const address =\n addressState.status === 'success' ? addressState.address : undefined\n const { deposits } = useDepositStatus({\n address,\n baseUrl: resolveBaseUrl(config),\n })\n const targetHash = initial.deposit.transactionHash\n const live = deposits.find((d) => d.deposit.transactionHash === targetHash) as\n | DepositWithTimestamp\n | undefined\n return live ?? initial\n}\n\n/** DOM id shared by the fee-toggle button's `aria-controls` and the panel it\n * opens. Kept as a constant so both sides move together if renamed. */\nconst FEE_PANEL_ID = 'sra-tx-fee-panel'\n\nfunction formatDate(iso?: string): string | null {\n if (!iso) return null\n const ts = Date.parse(iso)\n if (Number.isNaN(ts)) return null\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date(ts))\n}\n\n/**\n * Transaction details view (Figma `17634:105049`) — token hero pair via\n * `ArrowCardPair` + `InfoCard`, a \"Transaction details\" `Section` with the\n * route metadata, and a \"Transaction Progress\" `Section` with the step trail.\n */\nexport function TransactionDetails({\n deposit: initialDeposit,\n}: TransactionDetailsProps) {\n // Re-poll and pick the latest snapshot for this deposit so the details view\n // — Transaction Progress in particular — updates live rather than staying\n // frozen at click-time state.\n const deposit = useLiveDeposit(initialDeposit)\n const { config, addressState, recipient } = useSmartRoutingAddressContext()\n const estimatedFees =\n addressState.status === 'success' ? addressState.estimatedFees : []\n\n const { chainId, token, amount, transactionHash } = deposit.deposit\n const feeData = findFeeDataByToken(estimatedFees, chainId, token)\n\n // Match on the on-chain address (via `tokenAddressMatches`) — the server's\n // `feeData.name` is a display symbol (e.g. \"ETH\"), not the TOKEN_TYPE\n // (\"NATIVE\"), so a direct name compare would miss native tokens.\n const source =\n sourceTokensFromFees(estimatedFees).find(\n (t) =>\n t.chain.id === chainId &&\n tokenAddressMatches(t.tokenType, chainId, token),\n ) ?? null\n const sourceSymbol = source ? getSourceTokenSymbol(source) : ''\n const sourceChain = source?.chain\n const sourceTokenLogo = sourceSymbol\n ? TOKEN_ICONS[sourceSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = CHAIN_ICONS[chainId]\n\n const destChain = resolveDestChain(config)\n // Widget's default actions forward the deposited token, so destination\n // token = source token — reuse the source logo.\n const destTokenLogo = sourceTokenLogo\n const destChainLogo = CHAIN_ICONS[destChain.id]\n\n const stage = getDepositStage(deposit)\n const execution = deposit.execution\n const outAmountRaw = execution?.outputAmount\n const failed = stage === 'failed'\n\n // Headline reads as \"how much you sent\" — round down so we never overstate\n // the deposit. `formatDisplayAmount` (magnitude-aware) also prevents the\n // 18-decimal fractional tail that `formatTokenAmount` produces for ETH.\n const sourceHeadline = feeData\n ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`\n : String(amount)\n\n // NOTE: `feeData.decimal` is the source token's decimals — the SRA fee\n // estimates don't include destination-token decimals, so this is an\n // approximation that only reads correctly when source and destination\n // decimals match. Fixing this properly needs a dest-decimals lookup and\n // is out of scope here.\n //\n // Destination uses `'nearest'` rounding — the server returns the actual\n // on-chain amount after fees + slippage (e.g. 249.9996), and users read\n // this as \"how much I received\", so rounding to 250.00 is intuitive.\n const destHeadline =\n outAmountRaw && feeData\n ? `${formatDisplayAmount(outAmountRaw, feeData.decimal, 'nearest')} ${sourceSymbol}`\n : '—'\n\n // `getTxUrl` looks up the chain independently of whether `source` was\n // resolved above — a deposit on a known chain still gets a link even if\n // its token wasn't matched via `sourceTokensFromFees`.\n const sourceHref = getTxUrl(chainId, transactionHash)\n const destHref = execution\n ? getTxUrl(destChain.id, execution.transactionHash)\n : undefined\n\n // Refetch current Across / Relay quotes for the same route so the \"Routing\"\n // step can show which provider was used. The historic provider isn't\n // stored server-side; the assumption is the route hasn't changed materially\n // and current quotes still name the same winning provider.\n const providerFees = useProviderFees(source, destChain, feeData, recipient)\n const breakdown =\n feeData && sourceSymbol\n ? buildFeeBreakdown(feeData, sourceSymbol, providerFees.fees)\n : null\n const [feeOpen, setFeeOpen] = useState(false)\n\n const date = formatDate(deposit.createdAt)\n\n return (\n // No `h-full` — the page takes its natural content height so the\n // Screen's scroll container can activate scrolling when the fee\n // breakdown is expanded and content exceeds the viewport.\n <div className=\"zd:flex zd:w-full zd:flex-col zd:gap-3 zd:pt-4 zd:pb-6\">\n <ArrowCardPair\n topCard={\n <InfoCard\n title={sourceHeadline}\n {...(sourceTokenLogo && { imageSource: sourceTokenLogo })}\n {...(sourceChainLogo && { chainIconUrl: sourceChainLogo })}\n />\n }\n bottomCard={\n <InfoCard\n title={destHeadline}\n {...(destTokenLogo && { imageSource: destTokenLogo })}\n {...(destChainLogo && { chainIconUrl: destChainLogo })}\n />\n }\n />\n\n <Section title=\"Transaction details\">\n <DataRow\n label=\"From network\"\n value={\n <NetworkValue\n name={sourceChain?.name ?? '—'}\n {...(sourceChainLogo && { logoUrl: sourceChainLogo })}\n />\n }\n />\n <DataRow\n label=\"To network\"\n value={\n <NetworkValue\n name={destChain.name}\n {...(destChainLogo && { logoUrl: destChainLogo })}\n />\n }\n />\n {date && <DataRow label=\"Date\" value={date} />}\n {breakdown && (\n <DataRow\n label=\"Total fee\"\n value={<FeeSummary breakdown={breakdown} />}\n info\n infoTooltip={FEE_INFO.estimatedFee}\n trailing={\n <button\n type=\"button\"\n onClick={() => setFeeOpen((prev) => !prev)}\n aria-expanded={feeOpen}\n aria-controls={FEE_PANEL_ID}\n aria-label={feeOpen ? 'Hide fee details' : 'Show fee details'}\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-pointer\"\n >\n <Icon\n name={feeOpen ? 'chevronUp' : 'chevronDown'}\n className=\"zd:w-3.5 zd:h-3.5 zd:text-greyScale\"\n />\n </button>\n }\n />\n )}\n {feeOpen && breakdown && (\n <section id={FEE_PANEL_ID} aria-label=\"Fee breakdown\">\n <FeeBreakdownRows breakdown={breakdown} />\n </section>\n )}\n </Section>\n\n <Section title=\"Transaction Progress\">\n <ProgressStep\n label=\"Deposit detected\"\n info={FEE_INFO.detected}\n status=\"done\"\n right={\n <TxLink\n label={truncateAddress(transactionHash)}\n href={sourceHref}\n />\n }\n />\n <ProgressStep\n label=\"Routing\"\n info={FEE_INFO.routing}\n // Routing was at least attempted whenever we've left the initial\n // detected stage — including the failed path (failure implies the\n // route was tried), so mark it done there too rather than showing\n // an inert pending circle above the \"Failed\" row.\n status={\n stage === 'bridging' || stage === 'completed' || failed\n ? 'done'\n : 'pending'\n }\n right={\n providerFees.loading ? (\n <ProviderChipSkeleton />\n ) : breakdown?.provider ? (\n <ProviderChip provider={breakdown.provider} />\n ) : (\n <StatusText>—</StatusText>\n )\n }\n />\n {failed ? (\n <ProgressStep\n label=\"Failed\"\n info={FEE_INFO.failed}\n status=\"failed\"\n isLast\n right={<StatusText tone=\"error\">Error</StatusText>}\n />\n ) : (\n <ProgressStep\n label=\"Completed\"\n info={FEE_INFO.completed}\n status={stage === 'completed' ? 'done' : 'pending'}\n isLast\n right={\n execution ? (\n <TxLink\n label={truncateAddress(execution.transactionHash)}\n href={destHref}\n />\n ) : (\n <StatusText>Pending</StatusText>\n )\n }\n />\n )}\n </Section>\n </div>\n )\n}\n\nfunction NetworkValue({ name, logoUrl }: { name: string; logoUrl?: string }) {\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1.5\">\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">{name}</Text>\n {logoUrl && (\n <img src={logoUrl} alt=\"\" className=\"zd:size-4 zd:rounded-full\" />\n )}\n </span>\n )\n}\n\nfunction TxLink({ label, href }: { label: string; href?: string | undefined }) {\n if (!href) {\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale\">\n {label}\n </span>\n )\n }\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale zd:hover:text-solarOrange\"\n >\n {label}\n <Icon\n name=\"export\"\n className=\"zd:size-3 zd:text-solarOrange\"\n aria-hidden\n />\n </a>\n )\n}\n\n/** Small right-aligned status text used in `ProgressStep` — dedups the\n * \"Pending\" / \"—\" / \"Error\" placeholders that all share the same size class\n * and only differ by tone. */\nfunction StatusText({\n children,\n tone = 'muted',\n}: {\n children: string\n tone?: 'muted' | 'error'\n}) {\n return (\n <Text\n className={cn(\n 'zd:text-body3',\n tone === 'error' ? 'zd:text-negative' : 'zd:text-greyScale/50',\n )}\n >\n {children}\n </Text>\n )\n}\n\nfunction ProviderChip({ provider }: { provider: string }) {\n const iconUrl = PROVIDER_ICONS[provider]\n return (\n <span\n className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale\"\n title={`Quoted via ${provider}`}\n >\n {provider}\n {iconUrl && (\n <img\n src={iconUrl}\n alt=\"\"\n aria-hidden\n className=\"zd:size-3.5 zd:shrink-0 zd:rounded-sm zd:object-cover\"\n />\n )}\n </span>\n )\n}\n\n/** Skeleton placeholder shown while `useProviderFees` is fetching quotes. */\nfunction ProviderChipSkeleton() {\n return (\n <output\n aria-busy=\"true\"\n aria-label=\"Loading provider\"\n className=\"zd:block zd:h-4 zd:w-16 zd:rounded-full zd:bg-greyScale/15 zd:animate-skel-pulse\"\n />\n )\n}\n","import { PoweredBy, Screen, TopNav } from '@zerodev/react-ui'\nimport type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { type ReactNode, useEffect, useState } from 'react'\nimport type { Address } from 'viem'\nimport { QrSheet } from '../components/QrSheet'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { Deposit } from './Deposit'\nimport { PastDeposits } from './PastDeposits'\nimport { TransactionDetails } from './TransactionDetails'\n\n/**\n * Steps rendered by `SmartRoutingAddress`. Sub-views advance/rewind local\n * step state; the widget owns navigation and the `TopNav` chrome accordingly.\n */\nexport type SmartRoutingAddressStep = 'deposit' | 'past' | 'transaction'\n\nconst TITLE_BY_STEP: Record<SmartRoutingAddressStep, string> = {\n deposit: 'Deposit funds',\n past: 'Past deposits',\n transaction: 'Transaction details',\n}\n\nfunction renderStep(\n step: SmartRoutingAddressStep,\n {\n onQrClick,\n onViewPastDeposits,\n onSelectDeposit,\n selectedDeposit,\n }: {\n onQrClick?: (() => void) | undefined\n onViewPastDeposits?: (() => void) | undefined\n onSelectDeposit?: ((deposit: DepositedToken) => void) | undefined\n selectedDeposit?: DepositedToken | undefined\n },\n): ReactNode {\n switch (step) {\n case 'deposit':\n return (\n <Deposit\n {...(onQrClick && { onQrClick })}\n {...(onViewPastDeposits && { onViewPastDeposits })}\n {...(onSelectDeposit && { onSelectDeposit })}\n />\n )\n case 'past':\n return <PastDeposits {...(onSelectDeposit && { onSelectDeposit })} />\n case 'transaction':\n // `selectedDeposit` is set by the past-deposits row-click handler\n // before advancing the step, so this branch always has a deposit.\n return selectedDeposit ? (\n <TransactionDetails deposit={selectedDeposit} />\n ) : null\n default:\n return null\n }\n}\n\n/**\n * The Figma \"Deposit funds\" flow (`17634:104268` / `18721:96092`).\n *\n * Owns the shared `Screen` + `TopNav` chrome and delegates the body to the\n * current page in this directory. Mirrors the layout of `wallet-react-ui`'s\n * `auth/index.tsx` and `signing/index.tsx`.\n *\n * Wrap the subtree with `<SmartRoutingAddressProvider config={…}>` first.\n */\nexport interface SmartRoutingAddressProps {\n /** Recipient address the smart routing address is created for. */\n recipient: Address\n /** Called when the top-right × close button is clicked. */\n onClose: () => void\n className?: string\n size?: 'sm' | 'md' | 'lg'\n}\n\nexport function SmartRoutingAddress({\n recipient,\n onClose,\n className,\n size,\n}: SmartRoutingAddressProps) {\n const { addressState, getOrCreateAddress } = useSmartRoutingAddressContext()\n const [qrOpen, setQrOpen] = useState(false)\n const [step, setStep] = useState<SmartRoutingAddressStep>('deposit')\n const [selectedDeposit, setSelectedDeposit] = useState<\n DepositedToken | undefined\n >(undefined)\n\n useEffect(() => {\n // Errors surface via `addressState.status === 'error'`; swallow rejection\n // here so React doesn't warn about an unhandled promise.\n getOrCreateAddress(recipient).catch(() => {})\n }, [recipient, getOrCreateAddress])\n\n const title = TITLE_BY_STEP[step]\n\n const address =\n addressState.status === 'success' ? addressState.address : undefined\n\n // The QR button in AddressDisplay only exists once the address has resolved,\n // but guard here too so we don't render an empty QrSheet.\n const handleQrClick = address ? () => setQrOpen(true) : undefined\n\n const handleCopy = async () => {\n if (!address) return\n try {\n await navigator.clipboard.writeText(address)\n } catch {\n // Clipboard can reject on insecure contexts / permissions; the visual\n // \"copied\" state isn't in the spec yet, so just close and swallow.\n }\n setQrOpen(false)\n }\n\n // Sub-view chrome — sub-views swap the left slot for a back chevron that\n // returns to the parent step. Root (deposit) step has no left button\n // (TopNav renders a spacer so the title stays centred).\n const goBack =\n step === 'transaction'\n ? () => setStep('past')\n : step === 'past'\n ? () => setStep('deposit')\n : undefined\n\n return (\n <Screen\n className={className}\n {...(size && { size })}\n topNav={\n <TopNav\n title={title}\n {...(goBack && {\n onLeftButtonClick: goBack,\n leftButtonIcon: 'chevronLeft' as const,\n })}\n onRightButtonClick={onClose}\n />\n }\n footer={<PoweredBy />}\n >\n {renderStep(step, {\n onQrClick: handleQrClick,\n onViewPastDeposits: () => setStep('past'),\n onSelectDeposit: (deposit) => {\n setSelectedDeposit(deposit)\n setStep('transaction')\n },\n selectedDeposit,\n })}\n {/* QrSheet renders itself via `useScreenOverlayContainer()` + portal, so\n it stays inside the card frame while composing at this level rather\n than being hoisted into `Screen`'s API. Mounted whenever an address\n exists so Radix Dialog owns the open/close animation lifecycle. */}\n {address && (\n <QrSheet\n open={qrOpen}\n onOpenChange={setQrOpen}\n address={address}\n onCopy={handleCopy}\n />\n )}\n </Screen>\n )\n}\n"],"names":["DEFAULT_POLLING_INTERVAL_MS","DEFAULT_FILL_TIME_SECONDS","SUPPORTED_CHAINS","mainnet","optimism","arbitrum","polygon","plasma","base","celo","mode","monad","blast","bsc","flowMainnet","hyperEvm","linea","ink","megaeth","scroll","soneium","tempo","unichain","worldchain","zora","CHAINS_BY_ID","chain","UNSUPPORTED_TOKEN_TYPES","DEFAULT_SOURCE_TOKENS","SUPPORTED_TOKENS","chainId","tokens","t","tokenType","getChainById","supported","c","getTxUrl","transactionHash","explorer","_b","_a","resolveTokenAddress","zeroAddress","tokenAddressMatches","token","address","isAddressEqual","findFeeDataByToken","estimatedFees","chainFees","fee","data","findFeeData","resolveVersion","config","SMART_ROUTING_ADDRESS_V0_2_1","resolveBaseUrl","SMART_ROUTING_ADDRESS_SERVER_URL","resolveDestChain","isTokenOnChain","resolveSourceTokens","destChainId","source","sourceTokensFromFees","uniqueTokenTypes","sources","resolveActions","recipient","erc20Call","createCall","FLEX","erc20Abi","nativeCall","getSourceTokenSymbol","SmartRoutingAddressContext","createContext","useSmartRoutingAddressContext","context","useContext","SmartRoutingAddressProvider","children","addressState","setAddressState","useState","setRecipient","activeRoute","setActiveRoute","pendingRef","useRef","recipientRef","genRef","configRef","getOrCreateAddress","useCallback","nextRecipient","gen","request","baseUrl","result","createSmartRoutingAddress","error","err","retry","current","value","useMemo","jsx","useCreateSmartRoutingAddress","useSmartRoutingAddress","FINDER_SIZE","MODULE_COLOR","BG_COLOR","PILL_PAD_RATIO","QrCode","size","errorCorrectionLevel","eyeRadius","qr","encode","matrix","moduleCount","cellSize","eyeRadiusPx","finders","inFinder","row","col","f","runs","length","jsxs","pad","pillHeight","isSingle","x","outerSize","innerSize","QrSheet","open","onOpenChange","onCopy","BottomSheet","BottomSheetContent","BottomSheetTitle","Text","Button","BottomSheetClose","LoadingCard","text","className","rest","Wrapper","cn","Icon","AddressDisplayUI","loadingText","onQrClick","AddressDisplay","status","ErrorRetryCard","message","onRetry","busy","retryLabel","CHAIN_ARBITRUM","CHAIN_BASE","CHAIN_BSC","CHAIN_ETHEREUM","CHAIN_HYPERLIQUID","CHAIN_LINEA","CHAIN_MONAD","CHAIN_OPTIMISM","CHAIN_POLYGON","CHAIN_SCROLL","CHAIN_SONEIUM","CHAIN_UNICHAIN","CHAIN_WORLDCHAIN","CHAIN_BLAST","CHAIN_INK","CHAIN_MODE","CHAIN_TEMPO","CHAIN_ZORA","TOKEN_ETH","TOKEN_EURC","TOKEN_WBTC","TOKEN_DAI","TOKEN_USDC","TOKEN_USDT","CHAIN_ICONS","sepolia","arbitrumSepolia","baseSepolia","optimismSepolia","TOKEN_ICONS","PROVIDER_ACROSS","PROVIDER_RELAY","PROVIDER_ICONS","displayFractionDigits","formatDisplayAmount","decimals","round","amount","formatUnits","digits","factor","truncateAddress","formatSlippage","basisPoints","formatDuration","seconds","STABLE_SYMBOLS","formatRelativeTime","iso","now","then","minutes","hours","days","months","sum","values","total","v","AcrossLegSchema","z","AcrossSuggestedFeesSchema","E18","acrossPct","raw","tokenUsd","symbol","parseAcrossFees","res","leg","key","label","kind","accent","lines","l","RelayFeeSchema","RelayQuoteSchema","usdOf","parseRelayFees","fees","push","usd","totalUsd","buildFeeBreakdown","feeData","provider","sraUsd","bridgeUsd","feeToken","executionUsd","showTokenFallback","formatFeePct","pct","formatFeeUsd","FEE_INFO","PROVIDER_URLS","LiveValue","loading","flashKey","FeeSummary","breakdown","ProviderValue","url","iconUrl","inner","Fragment","InfoMark","info","Tooltip","LineValue","line","BreakdownRow","FeeBreakdownRows","getDepositKey","deposit","getDepositStage","getNewDeposits","deposits","baseline","STATUS_COLOR","TxnItem","destAmount","href","timestamp","sourceTokenIconUrl","sourceChainIconUrl","destTokenIconUrl","destChainIconUrl","sourceChainName","destChainName","detailed","badgeIconUrl","TokenMark","RouteArrow","ChainTag","AddressLine","tokenIconUrl","name","STAGE_TO_STATUS","PendingDeposits","onSelectDeposit","destChain","destChainLogo","sourceSymbol","sourceTokenLogo","sourceChainLogo","destTokenLogo","amountLabel","INITIAL_STATE","useDepositStatus","enabled","pollingInterval","state","setState","pollRef","useEffect","cancelled","poll","requestGen","getSmartRoutingAddressStatus","previous","intervalId","refetch","useNewDeposits","ready","baselineRef","ACROSS_API","RELAY_API","QUOTE_USER","acrossToken","relayToken","fetchAcross","route","signal","inputToken","outputToken","params","json","parsed","fetchRelay","originCurrency","destinationCurrency","bestRoute","routes","available","r","withUsd","best","useProviderFees","setBreakdown","setLoading","sourceChainId","minDeposit","controller","safe","p","across","relay","chosen","SUBTITLE","FULL_ROW_PANEL_STYLE","Deposit","onViewPastDeposits","feeOpen","setFeeOpen","retrying","setRetrying","success","srcTokens","selectedTokenType","setSelectedTokenType","selectedChainId","setSelectedChainId","fallback","hasLoaded","depositsError","refetchDeposits","newDeposits","pastDepositsCount","tokenSymbol","tokenLogo","fillTime","providerFees","uniqueTokens","seen","out","availableChains","slippage","minDepositAmount","feeFlashKey","pickerDisabled","addressError","noRoutesError","pollingError","errorMessage","handleRetry","ArrowCardPair","CardTitle","PillRow","Select","id","SelectTrigger","Pill","SelectIcon","SelectContent","i","chainCount","logo","SelectItem","TokenListItem","DataRow","prev","CopyAddressButton","WrappedPressable","PAST_DEPOSITS_CARD","PastDepositsRow","copied","setCopied","handleCopy","count","left","right","dayStart","d","groupLabel","today","day","groupByDay","buckets","sortKey","existing","a","b","PastDeposits","groups","group","destAmountLabel","useLiveDeposit","initial","targetHash","FEE_PANEL_ID","formatDate","ts","TransactionDetails","initialDeposit","sourceChain","stage","execution","outAmountRaw","failed","sourceHeadline","destHeadline","sourceHref","destHref","date","InfoCard","Section","NetworkValue","ProgressStep","TxLink","ProviderChipSkeleton","ProviderChip","StatusText","logoUrl","tone","TITLE_BY_STEP","renderStep","step","selectedDeposit","SmartRoutingAddress","onClose","qrOpen","setQrOpen","setStep","setSelectedDeposit","title","handleQrClick","goBack","Screen","TopNav","PoweredBy"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/constants.ts","../src/utils/chains.ts","../src/utils/fees.ts","../src/utils/config.ts","../src/context/SmartRoutingAddressContext.ts","../src/context/SmartRoutingAddressProvider.tsx","../src/hooks/useCreateSmartRoutingAddress.ts","../src/hooks/useSmartRoutingAddress.ts","../src/components/QrSheet/index.tsx","../src/components/LoadingCard/index.tsx","../src/components/AddressDisplay/index.tsx","../src/components/ErrorRetryCard/index.tsx","../src/iconAssets.ts","../src/utils/format.ts","../src/utils/providerFees.ts","../src/components/FeeBreakdown/feeInfo.ts","../src/components/FeeBreakdown/index.tsx","../src/utils/deposits.ts","../src/components/TxnItem/index.tsx","../src/components/PendingDeposits/index.tsx","../src/hooks/useDepositStatus.ts","../src/hooks/useNewDeposits.ts","../src/hooks/useProviderFees.ts","../src/pages/Deposit.tsx","../src/pages/PastDeposits.tsx","../src/pages/TransactionDetails.tsx","../src/pages/index.tsx"],"sourcesContent":["import type { TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { SUPPORTED_TOKENS } from '@zerodev/smart-routing-address'\nimport type { Chain } from 'viem'\nimport {\n arbitrum,\n base,\n blast,\n bsc,\n celo,\n flowMainnet,\n hyperEvm,\n ink,\n linea,\n mainnet,\n megaeth,\n mode,\n monad,\n optimism,\n plasma,\n polygon,\n scroll,\n soneium,\n tempo,\n unichain,\n worldchain,\n zora,\n} from 'viem/chains'\nimport type { SourceToken } from './types'\n\nexport const DEFAULT_POLLING_INTERVAL_MS = 5_000\n\nexport const DEFAULT_FILL_TIME_SECONDS = 30\n\nexport const DEFAULT_DASHBOARD_URL = 'https://smart-routing-address.zerodev.app'\n\n/**\n * Chains supported by the smart routing address SDK; mirrors the\n * smart-account-plus core `supportedChainIds` list.\n */\nexport const SUPPORTED_CHAINS: readonly Chain[] = [\n mainnet,\n optimism,\n arbitrum,\n polygon,\n plasma,\n base,\n celo,\n mode,\n monad,\n blast,\n bsc,\n flowMainnet,\n hyperEvm,\n linea,\n ink,\n megaeth,\n scroll,\n soneium,\n tempo,\n unichain,\n worldchain,\n zora,\n]\n\nexport const CHAINS_BY_ID: ReadonlyMap<number, Chain> = new Map(\n SUPPORTED_CHAINS.map((chain) => [chain.id, chain]),\n)\n\n/**\n * Token types the SDK ships in `SUPPORTED_TOKENS` but the SRA server does not\n * yet recognize. Sending one of these as a source token makes the server\n * reject the whole `createSmartRoutingAddress` request with\n * `Invalid params: Token address … is not supported on chain N`, which breaks\n * the entire destination (e.g. Base). Remove entries here as the server\n * registry catches up.\n *\n * TODO: file/track ZeroDev SRA server bug for EURC on Base\n * (chain 8453, address 0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42) — once the\n * server accepts it, drop this filter.\n */\nconst UNSUPPORTED_TOKEN_TYPES: ReadonlySet<TOKEN_TYPE> = new Set(['EURC'])\n\n/**\n * Source tokens offered for deposits: every supported mainnet token the SDK\n * exposes (NATIVE plus each ERC-20, with wrapped native surfaced as WETH),\n * mapped to its viem chain object. Testnets are excluded from the default;\n * chains this package cannot resolve to a viem chain are skipped, and token\n * types the server can't route yet are filtered via `UNSUPPORTED_TOKEN_TYPES`.\n */\nexport const DEFAULT_SOURCE_TOKENS: SourceToken[] = Object.entries(\n SUPPORTED_TOKENS,\n).flatMap(([chainId, tokens]) => {\n // Skip chains this package cannot resolve to a viem chain object\n const chain = CHAINS_BY_ID.get(Number(chainId))\n if (!chain) return []\n return Object.keys(tokens)\n .filter((t) => !UNSUPPORTED_TOKEN_TYPES.has(t as TOKEN_TYPE))\n .map((tokenType) => ({\n chain,\n tokenType: tokenType as TOKEN_TYPE,\n }))\n})\n","import type { Chain } from 'viem'\nimport { CHAINS_BY_ID, SUPPORTED_CHAINS } from '../constants'\n\n/** Resolve a chain id to its viem chain object, throwing for unknown ids */\nexport function getChainById(chainId: number): Chain {\n const chain = CHAINS_BY_ID.get(chainId)\n if (!chain) {\n const supported = SUPPORTED_CHAINS.map((c) => `${c.name} (${c.id})`)\n throw new Error(\n `Unsupported chain id ${chainId}. Supported chains: ${supported.join(', ')}`,\n )\n }\n return chain\n}\n\n/** Block explorer URL for a transaction, or `undefined` when no explorer is\n * known. Returns `undefined` (not `null`) so the value can be passed straight\n * to optional link `href` props under `exactOptionalPropertyTypes`. */\nexport function getTxUrl(\n chainId: number,\n transactionHash: string,\n): string | undefined {\n const explorer = CHAINS_BY_ID.get(chainId)?.blockExplorers?.default\n if (!explorer) return undefined\n return `${explorer.url}/tx/${transactionHash}`\n}\n","import type { TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { SUPPORTED_TOKENS } from '@zerodev/smart-routing-address'\nimport type { Address } from 'viem'\nimport { isAddressEqual, zeroAddress } from 'viem'\nimport type { EstimatedFee, EstimatedFeeData } from '../types'\n\n/**\n * Resolve the on-chain token address used by the routing server for a given\n * token type on a chain. Returns null when the type cannot be resolved\n * (generic ERC20 or unknown token on that chain).\n */\nexport function resolveTokenAddress(\n tokenType: TOKEN_TYPE,\n chainId: number,\n): Address | null {\n if (tokenType === 'NATIVE') return zeroAddress\n if (tokenType === 'ERC20') return null\n return SUPPORTED_TOKENS[chainId]?.[tokenType] ?? null\n}\n\n/** Whether the token type resolves to the given on-chain address on a chain. */\nexport function tokenAddressMatches(\n tokenType: TOKEN_TYPE,\n chainId: number,\n token: Address,\n): boolean {\n const address = resolveTokenAddress(tokenType, chainId)\n return address !== null && isAddressEqual(address, token)\n}\n\nexport function findFeeDataByToken(\n estimatedFees: EstimatedFee[],\n chainId: number,\n token: Address,\n): EstimatedFeeData | null {\n const chainFees = estimatedFees.find((fee) => fee.chainId === chainId)\n if (!chainFees) return null\n return (\n chainFees.data.find((data) => isAddressEqual(data.token, token)) ?? null\n )\n}\n\nexport function findFeeData(\n estimatedFees: EstimatedFee[],\n chainId: number,\n tokenType: TOKEN_TYPE,\n): EstimatedFeeData | null {\n const token = resolveTokenAddress(tokenType, chainId)\n if (!token) return null\n return findFeeDataByToken(estimatedFees, chainId, token)\n}\n","import type {\n CreateSmartRoutingAddressParams,\n SmartRoutingAddressVersion,\n TOKEN_TYPE,\n} from '@zerodev/smart-routing-address'\nimport {\n createCall,\n FLEX,\n SMART_ROUTING_ADDRESS_SERVER_URL,\n SMART_ROUTING_ADDRESS_V0_2_1,\n SUPPORTED_TOKENS,\n} from '@zerodev/smart-routing-address'\nimport { type Address, type Chain, erc20Abi } from 'viem'\nimport { DEFAULT_DASHBOARD_URL, DEFAULT_SOURCE_TOKENS } from '../constants'\nimport type {\n EstimatedFee,\n SmartRoutingAddressConfig,\n SourceToken,\n} from '../types'\nimport { getChainById } from './chains'\nimport { tokenAddressMatches } from './fees'\n\nexport function resolveVersion(\n config: SmartRoutingAddressConfig,\n): SmartRoutingAddressVersion {\n return config.version ?? SMART_ROUTING_ADDRESS_V0_2_1\n}\n\n/**\n * Server URL for all smart routing address requests: the server root\n * (default or `config.baseUrl`) with the ZeroDev project id appended.\n * Without a project id the URL is only overridden when `config.baseUrl`\n * is set; undefined leaves the SDK default in place.\n */\nexport function resolveBaseUrl(\n config: SmartRoutingAddressConfig,\n): string | undefined {\n if (!config.projectId) return config.baseUrl\n const root = config.baseUrl ?? SMART_ROUTING_ADDRESS_SERVER_URL\n return `${root.replace(/\\/+$/, '')}/${config.projectId}`\n}\n\nexport function resolveDashboardUrl(address?: string): string {\n if (!address) return DEFAULT_DASHBOARD_URL\n return `${DEFAULT_DASHBOARD_URL.replace(/\\/+$/, '')}/address/${address}`\n}\n\n/** Chain where the routed funds settle */\nexport function resolveDestChain(config: SmartRoutingAddressConfig): Chain {\n return getChainById(config.targetChainId)\n}\n\n/**\n * Whether the SDK can resolve the token type to an asset on the chain:\n * generic ERC20 deposits are always accepted, every other type (including\n * NATIVE) needs a SUPPORTED_TOKENS entry for the chain.\n */\nfunction isTokenOnChain(tokenType: TOKEN_TYPE, chainId: number): boolean {\n if (tokenType === 'ERC20') return true\n return SUPPORTED_TOKENS[chainId]?.[tokenType] !== undefined\n}\n\n/**\n * The DEFAULT_SOURCE_TOKENS, excluding token types that do not exist on the\n * destination chain (the default actions deliver the deposited token type\n * there, so a missing destination token would make the deposit unfulfillable).\n */\nexport function resolveSourceTokens(\n config: SmartRoutingAddressConfig,\n): SourceToken[] {\n const destChainId = resolveDestChain(config).id\n return DEFAULT_SOURCE_TOKENS.filter((source) =>\n isTokenOnChain(source.tokenType, destChainId),\n )\n}\n\n/**\n * Source tokens the server actually returned routes for, taken straight from\n * the fee estimates. Each returned (chain, token address) pair is matched back\n * to a DEFAULT_SOURCE_TOKENS entry to recover its TOKEN_TYPE.\n */\nexport function sourceTokensFromFees(\n estimatedFees: EstimatedFee[],\n): SourceToken[] {\n return estimatedFees.flatMap((fee) =>\n fee.data.flatMap((data) => {\n const token = DEFAULT_SOURCE_TOKENS.find(\n (source) =>\n source.chain.id === fee.chainId &&\n tokenAddressMatches(source.tokenType, fee.chainId, data.token),\n )\n return token ? [token] : []\n }),\n )\n}\n\nfunction uniqueTokenTypes(sources: SourceToken[]): TOKEN_TYPE[] {\n return [...new Set(sources.map((source) => source.tokenType))]\n}\n\n/**\n * Destination actions for every resolved source token type: ERC-20 deposits\n * are transferred to the recipient and native deposits are forwarded as\n * value. FLEX placeholders are resolved by the server per deposit.\n */\nexport function resolveActions(\n config: SmartRoutingAddressConfig,\n recipient: Address,\n): CreateSmartRoutingAddressParams['actions'] {\n const erc20Call = createCall({\n target: FLEX.TOKEN_ADDRESS,\n value: 0n,\n abi: erc20Abi,\n functionName: 'transfer',\n args: [recipient, FLEX.AMOUNT],\n })\n const nativeCall = createCall({\n target: recipient,\n value: FLEX.NATIVE_AMOUNT,\n })\n\n return Object.fromEntries(\n uniqueTokenTypes(resolveSourceTokens(config)).map((tokenType) => [\n tokenType,\n {\n action: tokenType === 'NATIVE' ? [nativeCall] : [erc20Call],\n fallBack: tokenType === 'NATIVE' ? [nativeCall] : [erc20Call],\n },\n ]),\n )\n}\n\n/** Display symbol for a source token (native tokens use the chain symbol) */\nexport function getSourceTokenSymbol(source: SourceToken): string {\n if (source.tokenType === 'NATIVE') {\n return source.chain.nativeCurrency.symbol\n }\n if (source.tokenType === 'WRAPPED_NATIVE') {\n return `W${source.chain.nativeCurrency.symbol}`\n }\n return source.tokenType\n}\n","import { createContext, useContext } from 'react'\nimport type { Address } from 'viem'\nimport type {\n ActiveRoute,\n AddressState,\n SmartRoutingAddressConfig,\n} from '../types'\n\nexport type SmartRoutingAddressContextValue = {\n config: SmartRoutingAddressConfig\n addressState: AddressState\n /** Recipient of the active (or last requested) smart routing address */\n recipient?: Address | undefined\n /**\n * Return the smart routing address for the recipient, creating it if it\n * has not been created yet. Safe to call multiple times; concurrent calls\n * for the same recipient share one request, while a new recipient\n * triggers a fresh creation. Rejects when creation fails (the failure\n * also lands in `addressState`).\n */\n getOrCreateAddress: (recipient: Address) => Promise<Address>\n /**\n * Re-run address creation for the current recipient. No-op if no recipient\n * has been set yet. Wired to the \"Failed to create deposit address\" retry\n * button in the deposit UI.\n */\n retry: () => Promise<void>\n /**\n * The route currently shown in the deposit UI. `null` until the picker\n * seeds a selection. Hosts can read this to mirror the widget's state.\n */\n activeRoute: ActiveRoute | null\n /** Deposit UI internal — writes the current picker selection to context. */\n setActiveRoute: (route: ActiveRoute | null) => void\n}\n\nexport const SmartRoutingAddressContext =\n createContext<SmartRoutingAddressContextValue | null>(null)\n\nexport function useSmartRoutingAddressContext(): SmartRoutingAddressContextValue {\n const context = useContext(SmartRoutingAddressContext)\n if (!context) {\n throw new Error(\n 'Smart routing address components must be rendered inside <SmartRoutingAddressProvider>',\n )\n }\n return context\n}\n","import { createSmartRoutingAddress } from '@zerodev/smart-routing-address'\nimport { type ReactNode, useCallback, useMemo, useRef, useState } from 'react'\nimport type { Address } from 'viem'\nimport type {\n ActiveRoute,\n AddressState,\n SmartRoutingAddressConfig,\n} from '../types'\nimport {\n resolveActions,\n resolveBaseUrl,\n resolveDestChain,\n resolveSourceTokens,\n resolveVersion,\n} from '../utils/config'\nimport { SmartRoutingAddressContext } from './SmartRoutingAddressContext'\n\nexport type SmartRoutingAddressProviderProps = {\n config: SmartRoutingAddressConfig\n children: ReactNode\n}\n\n/**\n * Holds the config and the lazily created routing address. Wrap the subtree\n * that renders <SmartRoutingAddress /> with this provider — the deposit UI\n * itself is rendered inline by the consumer, not by this provider.\n */\nexport function SmartRoutingAddressProvider({\n config,\n children,\n}: SmartRoutingAddressProviderProps) {\n const [addressState, setAddressState] = useState<AddressState>({\n status: 'idle',\n })\n const [recipient, setRecipient] = useState<Address | undefined>(undefined)\n const [activeRoute, setActiveRoute] = useState<ActiveRoute | null>(null)\n const pendingRef = useRef<Promise<Address> | null>(null)\n const recipientRef = useRef<Address | null>(null)\n // Each creation request gets a generation; only the latest generation\n // may write state, so superseded requests are ignored entirely\n const genRef = useRef(0)\n const configRef = useRef(config)\n\n const getOrCreateAddress = useCallback(\n async (nextRecipient: Address): Promise<Address> => {\n // A new config invalidates any cached request\n if (configRef.current !== config) {\n configRef.current = config\n genRef.current += 1\n pendingRef.current = null\n recipientRef.current = null\n }\n\n // Reuse the pending/settled request for the same recipient\n if (pendingRef.current && recipientRef.current === nextRecipient) {\n return pendingRef.current\n }\n\n genRef.current += 1\n const gen = genRef.current\n recipientRef.current = nextRecipient\n setRecipient(nextRecipient)\n\n const request = (async () => {\n setAddressState({ status: 'loading' })\n try {\n const baseUrl = resolveBaseUrl(config)\n const result = await createSmartRoutingAddress({\n owner: nextRecipient,\n destChain: resolveDestChain(config),\n slippage: config.slippage,\n srcTokens: resolveSourceTokens(config),\n ...(resolveActions(config, nextRecipient) && {\n actions: resolveActions(config, nextRecipient),\n }),\n // Drop source tokens without an available route instead\n // of failing the whole address creation\n allowPartialRoutes: true,\n config: {\n ...(baseUrl && { baseUrl }),\n version: resolveVersion(config),\n },\n })\n // State writes are generation-gated (results superseded by a newer\n // request must not clobber the live one), but the promise still\n // resolves with the address this call created — per-call semantics\n // stay honest even after the provider has moved on.\n if (genRef.current === gen) {\n setAddressState({\n status: 'success',\n address: result.smartRoutingAddress,\n estimatedFees: result.estimatedFees,\n })\n }\n return result.smartRoutingAddress\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n // Superseded failures must not clear the live request\n if (genRef.current === gen) {\n // Allow a retry after failures\n pendingRef.current = null\n setAddressState({ status: 'error', error: err })\n }\n throw err\n }\n })()\n\n pendingRef.current = request\n return request\n },\n [config],\n )\n\n const retry = useCallback(async () => {\n const current = recipientRef.current\n if (!current) return\n // Force a fresh request even if we still have a settled one cached\n pendingRef.current = null\n recipientRef.current = null\n // Failures surface via `addressState`; swallow the rejection so retry\n // callers (e.g. the ErrorRetryCard click handler) don't need a catch.\n await getOrCreateAddress(current).catch(() => {})\n }, [getOrCreateAddress])\n\n const value = useMemo(\n () => ({\n config,\n addressState,\n recipient,\n getOrCreateAddress,\n retry,\n activeRoute,\n setActiveRoute,\n }),\n [config, addressState, recipient, getOrCreateAddress, retry, activeRoute],\n )\n\n return (\n <SmartRoutingAddressContext.Provider value={value}>\n {children}\n </SmartRoutingAddressContext.Provider>\n )\n}\n","import type { Address } from 'viem'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\n\nexport type UseCreateSmartRoutingAddressResult = {\n /**\n * Return the deposit address for the recipient, creating it if it doesn't\n * exist yet. Idempotent per recipient — concurrent and repeated calls\n * share one request, so it's safe to call on every hover/focus/mount.\n * Rejects when creation fails (the failure also lands in the read hook's\n * `addressState`). Creation params (`actions`, `slippage`, …) come from\n * the provider config so the address always matches what the widget\n * displays — there are no per-call overrides. To create addresses with\n * bespoke params, use `createSmartRoutingAddress` from\n * `@zerodev/smart-routing-address`.\n */\n getOrCreateAddress: (recipient: Address) => Promise<Address>\n}\n\n/**\n * Action counterpart to `useSmartRoutingAddress` (which is read-only): lets\n * hosts embedding the `<SmartRoutingAddress />` widget pre-create the\n * deposit address — e.g. on hover or route entry, before the modal opens —\n * so the widget renders instantly.\n */\nexport function useCreateSmartRoutingAddress(): UseCreateSmartRoutingAddressResult {\n const { getOrCreateAddress } = useSmartRoutingAddressContext()\n return { getOrCreateAddress }\n}\n","import { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport type { ActiveRoute, AddressState } from '../types'\n\nexport type UseSmartRoutingAddressResult = {\n addressState: AddressState\n /**\n * The route the widget's deposit UI is currently showing (source token +\n * chain + estimated fee). `null` until the picker has seeded a selection.\n * Read-only by design: the widget's picker owns this value; hosts mirror\n * it (e.g. to drive a companion send panel), they don't set it.\n */\n activeRoute: ActiveRoute | null\n}\n\n/**\n * Read-only companion hook for hosts embedding the `<SmartRoutingAddress />`\n * widget: observe the address state and mirror the route the widget is\n * showing, from anywhere inside the provider. Its action counterpart is\n * `useCreateSmartRoutingAddress`. Not a kit for building a custom deposit\n * UI — for that, use `@zerodev/smart-routing-address` directly.\n */\nexport function useSmartRoutingAddress(): UseSmartRoutingAddressResult {\n const { addressState, activeRoute } = useSmartRoutingAddressContext()\n return { addressState, activeRoute }\n}\n","import {\n BottomSheet,\n BottomSheetClose,\n BottomSheetContent,\n BottomSheetTitle,\n Button,\n QrCode,\n Text,\n} from '@zerodev/react-ui'\n\nexport interface QrSheetProps {\n /** Whether the modal is open. Controlled. */\n open: boolean\n /** Called when the modal requests to close (backdrop click, ESC,\n * Cancel button). */\n onOpenChange: (open: boolean) => void\n /** Address to encode in the QR code and display below it. */\n address: string\n /** Called when the user taps \"Copy address\". */\n onCopy: () => void\n}\n\n/** Bottom-anchored modal showing the deposit address as a QR code. Composes\n * `<BottomSheet>` (state) + `<BottomSheetContent>` (chrome); this file owns the\n * QR / address / copy-cancel layout inside it. */\nexport function QrSheet({ open, onOpenChange, address, onCopy }: QrSheetProps) {\n return (\n <BottomSheet open={open} onOpenChange={onOpenChange}>\n <BottomSheetContent>\n <BottomSheetTitle>Your deposit address</BottomSheetTitle>\n {/* Accent gradient is baked into `BottomSheetContent`; content sits\n above it via `zd:relative`. */}\n <div className=\"zd:relative zd:flex zd:flex-col zd:gap-6 zd:items-center zd:pt-6 zd:px-4 zd:pb-3\">\n <div className=\"zd:flex zd:flex-col zd:gap-3 zd:items-center\">\n <Text className=\"zd:text-h2 zd:text-center\">\n Your deposit address\n </Text>\n <Text className=\"zd:text-body2 zd:text-center zd:max-w-[300px]\">\n Send funds to this address to automatically bridge and swap\n desired assets.\n </Text>\n </div>\n\n {/* The white bg + `p-5` (20px) padding around the QR doubles as\n the required 4-module quiet zone — QrCode itself no longer\n reserves one internally so the code fills its declared size. */}\n <div className=\"zd:relative zd:bg-white zd:w-[240px] zd:h-[240px] zd:p-5 zd:flex zd:items-center zd:justify-center\">\n <QrCode value={address} size={200} eyeRadius={2} />\n {/* Corner brackets — viewfinder-style framing. Color/thickness\n match the Figma's `rgba(19,14,11,0.1)` 1px outline. */}\n <div className=\"zd:absolute zd:top-0 zd:left-0 zd:w-5 zd:h-5 zd:border-t zd:border-l zd:border-greyScale/10 zd:rounded-tl-lg zd:pointer-events-none\" />\n <div className=\"zd:absolute zd:top-0 zd:right-0 zd:w-5 zd:h-5 zd:border-t zd:border-r zd:border-greyScale/10 zd:rounded-tr-lg zd:pointer-events-none\" />\n <div className=\"zd:absolute zd:bottom-0 zd:left-0 zd:w-5 zd:h-5 zd:border-b zd:border-l zd:border-greyScale/10 zd:rounded-bl-lg zd:pointer-events-none\" />\n <div className=\"zd:absolute zd:bottom-0 zd:right-0 zd:w-5 zd:h-5 zd:border-b zd:border-r zd:border-greyScale/10 zd:rounded-br-lg zd:pointer-events-none\" />\n </div>\n\n <Text className=\"zd:text-body2 zd:text-center zd:break-all zd:max-w-[230px]\">\n {address}\n </Text>\n\n <div className=\"zd:flex zd:flex-col zd:gap-1 zd:w-full\">\n <Button action=\"primary\" text=\"Copy address\" onClick={onCopy} />\n <BottomSheetClose asChild>\n <Button action=\"secondary\" text=\"Cancel\" />\n </BottomSheetClose>\n </div>\n </div>\n </BottomSheetContent>\n </BottomSheet>\n )\n}\n","import { cn, Icon, Text, Wrapper } from '@zerodev/react-ui'\nimport type { HTMLAttributes } from 'react'\n\nexport interface LoadingCardProps extends HTMLAttributes<HTMLDivElement> {\n text: string\n}\n\nexport function LoadingCard({ text, className, ...rest }: LoadingCardProps) {\n return (\n <Wrapper\n variant=\"ghost\"\n className={cn(\n 'zd:relative zd:flex zd:h-[68px] zd:w-full zd:items-center zd:justify-start zd:gap-2 zd:overflow-hidden zd:rounded-2xl zd:px-4',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n {...rest}\n >\n <Icon\n name=\"loading\"\n className=\"zd:w-4 zd:h-4 zd:animate-spin zd:text-orange\"\n data-testid=\"loading-card-icon\"\n />\n <Text className=\"zd:text-body1 zd:text-greyScale/50\">{text}</Text>\n </Wrapper>\n )\n}\n","import { cn, Icon, Text, Wrapper } from '@zerodev/react-ui'\nimport type { AddressState } from '../../types'\nimport { LoadingCard } from '../LoadingCard'\n\n/**\n * The card that renders the deposit address in the SRA \"Deposit funds\" screen.\n *\n * Two visual states, each mapped 1:1 to a Figma node:\n * - Loading (Figma 17634:104343, \"Smart Funding\" card): delegates to\n * `LoadingCard`, which is the shared spinner+text pill used elsewhere in\n * the SRA flow (e.g., SmartFunding's \"Watching for deposit\" state).\n * - Ready (Figma 17762:78875, address+QR row): 14px radius, 40% offWhite\n * surface, left-aligned address text + a 52×52 white QR button on the\n * right. Rendered when `address` is supplied.\n *\n * The two states have deliberately different visuals; they share this\n * component because the parent renders the same slot in both cases.\n */\nexport interface AddressDisplayUIProps {\n /** Deposit address to render; when omitted, the loading variant is shown. */\n address?: string\n /**\n * Message rendered in the loading variant. Include chain-specific context\n * from the caller, e.g., `Watching for your deposit on Base…`.\n */\n loadingText?: string\n /** Handler for the QR icon button (ready variant). */\n onQrClick?: (() => void) | undefined\n className?: string\n}\n\nexport function AddressDisplayUI({\n address,\n loadingText = 'Watching for your deposit…',\n onQrClick,\n className,\n}: AddressDisplayUIProps) {\n if (address === undefined) {\n return (\n <LoadingCard\n text={loadingText}\n className={className}\n data-testid=\"address-display-loading\"\n />\n )\n }\n\n return (\n <Wrapper\n variant=\"ghost\"\n // Figma's 40% offWhite surface — none of Wrapper's white-only variants\n // hit this tint, so override the backgroundColor. Inline style wins\n // over Wrapper's own style prop.\n style={{ backgroundColor: 'rgba(247, 245, 240, 0.4)' }}\n className={cn(\n // Figma: rounded-[14px], pl-16 pr-8 py-8, gap-12 items-center.\n // Height pinned to 68px so the loading and ready variants swap without\n // the layout jumping.\n 'zd:relative zd:flex zd:h-[68px] zd:w-full zd:items-center zd:gap-3 zd:overflow-hidden zd:rounded-[14px] zd:pl-4 zd:pr-2 zd:py-2',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n data-testid=\"address-display-ready\"\n >\n <Text\n className=\"zd:min-w-0 zd:flex-1 zd:break-all zd:text-body2\"\n data-testid=\"address-display-address\"\n >\n {address}\n </Text>\n <button\n type=\"button\"\n onClick={onQrClick}\n aria-label=\"Show QR code\"\n className=\"zd:flex zd:w-13 zd:h-13 zd:shrink-0 zd:cursor-pointer zd:items-center zd:justify-center zd:rounded-2xl zd:bg-white\"\n data-testid=\"address-display-qr-button\"\n >\n <Icon name=\"qrCode\" className=\"zd:w-5 zd:h-5 zd:text-greyScale\" />\n </button>\n </Wrapper>\n )\n}\n\nexport interface AddressDisplayProps {\n /** Current address-generation state from the SRA context. */\n status: AddressState['status']\n /** Deposit address, present when `status === 'success'`. */\n address?: string | undefined\n /** Handler for the QR icon button (only meaningful once `address` resolves). */\n onQrClick?: (() => void) | undefined\n}\n\n/**\n * State-driven wrapper around `AddressDisplayUI`. Picks the right variant\n * (loading / ready) based on the SRA address-generation status; the parent\n * page renders `ErrorRetryCard` in the error case instead of this component.\n */\nexport function AddressDisplay({\n status,\n address,\n onQrClick,\n}: AddressDisplayProps) {\n if (status === 'error') return null\n if (status === 'success' && address !== undefined) {\n return <AddressDisplayUI address={address} onQrClick={onQrClick} />\n }\n return <AddressDisplayUI loadingText=\"Generating deposit address…\" />\n}\n","import { cn, Icon, Text } from '@zerodev/react-ui'\n\nexport interface ErrorRetryCardProps {\n /** Error copy shown on the left side, e.g. \"Failed to create deposit\n * address…\" — kept short (Figma design truncates on one line). */\n message: string\n /** Called when the user clicks the refresh affordance. */\n onRetry: () => void\n /** Marks the button as busy while a retry is in flight — disables clicks\n * and spins the icon so back-to-back taps don't stack requests. */\n busy?: boolean\n /** Accessible label for the icon-only refresh button. Defaults to \"Retry\". */\n retryLabel?: string\n className?: string\n}\n\n/**\n * Error banner with an inline retry affordance. Renders as a compact pill\n * matching the Figma spec (`bg-negative/10`, error-red text, right-hand\n * 52×52 refresh button). Used above the \"Min deposit\" row in the deposit UI\n * to surface address-creation, empty-route and polling failures.\n */\nexport function ErrorRetryCard({\n message,\n onRetry,\n busy,\n retryLabel = 'Retry',\n className,\n}: ErrorRetryCardProps) {\n return (\n <div\n role=\"alert\"\n className={cn(\n 'zd:relative zd:flex zd:w-full zd:items-center zd:justify-center zd:gap-3',\n 'zd:overflow-hidden zd:rounded-[14px] zd:border-[0.3px] zd:border-offWhite',\n 'zd:bg-negative/10 zd:backdrop-blur-[15px] zd:py-2 zd:pr-2 zd:pl-4',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n >\n <Text className=\"zd:flex-1 zd:min-w-0 zd:text-body1 zd:font-medium zd:text-negative\">\n {message}\n </Text>\n <button\n type=\"button\"\n onClick={onRetry}\n disabled={busy}\n aria-label={retryLabel}\n aria-busy={busy}\n className={cn(\n 'zd:inline-flex zd:h-[52px] zd:w-[52px] zd:shrink-0 zd:items-center zd:justify-center',\n 'zd:rounded-2xl zd:bg-negative/10 zd:text-negative zd:cursor-pointer',\n 'zd:transition-colors zd:hover:bg-negative/20',\n 'zd:disabled:cursor-not-allowed zd:disabled:opacity-50',\n )}\n >\n <Icon\n name=\"rotateRight\"\n className={cn(\n 'zd:h-6 zd:w-6 zd:text-negative',\n busy && 'zd:animate-spin',\n )}\n aria-hidden\n />\n </button>\n </div>\n )\n}\n","/**\n * Icon data URIs sourced from smart-routing-address-dashboard/public/icons\n * (raster images downscaled to 64px). Generated file - do not edit the\n * encoded strings by hand; regenerate from the dashboard assets instead.\n */\nimport {\n arbitrum,\n arbitrumSepolia,\n base,\n baseSepolia,\n blast,\n bsc,\n hyperEvm,\n ink,\n linea,\n mainnet,\n mode,\n monad,\n optimism,\n optimismSepolia,\n polygon,\n scroll,\n sepolia,\n soneium,\n tempo,\n unichain,\n worldchain,\n zora,\n} from 'viem/chains'\n\nconst CHAIN_ARBITRUM =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE2LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgd2lkdGg9IjQ3MC4yODdweCIgaGVpZ2h0PSI1MTQuMjUxcHgiIHZpZXdCb3g9IjAgMCA0NzAuMjg3IDUxNC4yNTEiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDQ3MC4yODcgNTE0LjI1MSIKCSB4bWw6c3BhY2U9InByZXNlcnZlIj4KPGcgaWQ9IkJhY2tncm91bmQiPgo8L2c+CjxnIGlkPSJMb2dvc19hbmRfc3ltYm9scyI+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8zIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzNfM18iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfNCI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl80XzFfIj4KCQk8ZyBpZD0iU1lNQk9MX1ZFUl80XzNfIj4KCQk8L2c+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl81XzFfIj4KCTwvZz4KCTxnIGlkPSJvZmZfMl8xXyI+Cgk8L2c+Cgk8ZyBpZD0iVkVSXzNfMV8iPgoJCTxnIGlkPSJTWU1CT0xfVkVSXzJfMV8iPgoJCTwvZz4KCTwvZz4KCTxnIGlkPSJWRVJfMyI+CgkJPGcgaWQ9IlNZTUJPTF9WRVJfMiI+CgkJPC9nPgoJPC9nPgoJPGcgaWQ9Im9mZl8yIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzUiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMSI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMV8zXyI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xLTFfMl8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMS0xIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMV8xXyI+CgkJPGcgaWQ9Il94MzFfLTMiPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMTRfIj4KCQkJPHBhdGggZmlsbD0iIzJEMzc0QiIgZD0iTTI5MS4xMzQsMjM3LjQ2OWwzNS42NTQtNjAuNWw5Ni4xMDMsMTQ5LjY4NGwwLjA0NiwyOC43MjdsLTAuMzEzLTE5Ny42NzIKCQkJCWMtMC4yMjgtNC44MzItMi43OTQtOS4yNTItNi44ODctMTEuODU5TDI0Mi43MTUsNDYuMzI0Yy00LjA0NS0xLjk5LTkuMTgtMS45NjctMTMuMjIsMC4wNjNjLTAuNTQ2LDAuMjcyLTEuMDYsMC41Ny0xLjU0OCwwLjg5NQoJCQkJbC0wLjYwNCwwLjM3OUw1OS4zOTksMTQ0Ljk4M2wtMC42NTEsMC4yOTZjLTAuODM4LDAuMzg1LTEuNjg2LDAuODc1LTIuNDgsMS40NDRjLTMuMTg1LDIuMjgzLTUuMjk5LDUuNjYtNS45ODMsOS40NDgKCQkJCWMtMC4xMDMsMC41NzQtMC4xNzksMS4xNTgtMC4yMTQsMS43NDlsMC4yNjQsMTYxLjA4M2w4OS41MTUtMTM4Ljc0NWMxMS4yNzEtMTguMzk3LDM1LjgyNS0yNC4zMjMsNTguNjItMjQuMDAxbDI2Ljc1MywwLjcwNgoJCQkJTDY3LjU4OCw0MDkuNzY1bDE4LjU4MiwxMC42OTdMMjQ1LjY5MiwxNTcuMjJsNzAuNTEtMC4yNTZMMTU3LjA5MSw0MjYuODQ5bDY2LjMwNiwzOC4xMzhsNy45MjIsNC41NTYKCQkJCWMzLjM1MSwxLjM2Miw3LjMwMiwxLjQzMSwxMC42ODEsMC4yMWwxNzUuNDUzLTEwMS42NzhsLTMzLjU0NCwxOS40MzhMMjkxLjEzNCwyMzcuNDY5eiBNMzA0LjczNiw0MzMuMzk1bC02Ni45NjktMTA1LjEwOAoJCQkJbDQwLjg4MS02OS4zNzFsODcuOTUyLDEzOC42MjhMMzA0LjczNiw0MzMuMzk1eiIvPgoJCQk8cG9seWdvbiBmaWxsPSIjMjhBMEYwIiBwb2ludHM9IjIzNy43NjgsMzI4LjI4NiAzMDQuNzM2LDQzMy4zOTUgMzY2LjYwMSwzOTcuNTQzIDI3OC42NDgsMjU4LjkxNSAJCQkiLz4KCQkJPHBhdGggZmlsbD0iIzI4QTBGMCIgZD0iTTQyMi45MzcsMzU1LjM3OWwtMC4wNDYtMjguNzI3bC05Ni4xMDMtMTQ5LjY4NGwtMzUuNjU0LDYwLjVsOTIuNzc0LDE1MC4wNDNsMzMuNTQ0LTE5LjQzOAoJCQkJYzMuMjktMi42NzMsNS4yODEtNi41OTQsNS40OS0xMC44MjVMNDIyLjkzNywzNTUuMzc5eiIvPgoJCQk8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMjAuMjE5LDM4Mi40NjlsNDcuMzY5LDI3LjI5NmwxNTcuNjM0LTI1Mi44MDFsLTI2Ljc1My0wLjcwNmMtMjIuNzk1LTAuMzIyLTQ3LjM1LDUuNjA0LTU4LjYyLDI0LjAwMQoJCQkJTDUwLjMzNCwzMTkuMDA0bC0zMC4xMTUsNDYuMjcxVjM4Mi40Njl6Ii8+CgkJCTxwb2x5Z29uIGZpbGw9IiNGRkZGRkYiIHBvaW50cz0iMzE2LjIwMiwxNTYuOTY0IDI0NS42OTIsMTU3LjIyIDg2LjE3LDQyMC40NjIgMTQxLjkyOCw0NTIuNTY1IDE1Ny4wOTEsNDI2Ljg0OSAJCQkiLz4KCQkJPHBhdGggZmlsbD0iIzk2QkVEQyIgZD0iTTQ1Mi42NSwxNTYuNjAxYy0wLjU5LTE0Ljc0Ni04LjU3NC0yOC4yNDUtMjEuMDgtMzYuMTA0TDI1Ni4yOCwxOS42OTIKCQkJCWMtMTIuMzcxLTYuMjI5LTI3LjgyNS02LjIzNy00MC4yMTgtMC4wMDRjLTEuNDY1LDAuNzM5LTE3MC40NjUsOTguNzUyLTE3MC40NjUsOTguNzUyYy0yLjMzOSwxLjEyMi00LjU5MiwyLjQ1OC02LjcxMSwzLjk3NQoJCQkJYy0xMS4xNjQsOC4wMDEtMTcuOTY5LDIwLjQzNS0xOC42NjgsMzQuMDk1djIwOC43NjVsMzAuMTE1LTQ2LjI3MUw1MC4wNywxNTcuOTIxYzAuMDM1LTAuNTg5LDAuMTA5LTEuMTY5LDAuMjE0LTEuNzQxCgkJCQljMC42ODEtMy43OSwyLjc5Ny03LjE3MSw1Ljk4My05LjQ1NmMwLjc5NS0wLjU2OSwxNzIuNjgyLTEwMC4wNjQsMTczLjIyOC0xMDAuMzM3YzQuMDQtMi4wMjksOS4xNzUtMi4wNTMsMTMuMjItMC4wNjMKCQkJCWwxNzMuMDIyLDk5LjUyM2M0LjA5MywyLjYwNyw2LjY1OSw3LjAyNyw2Ljg4NywxMS44NTl2MTk5LjU0MmMtMC4yMDksNC4yMzEtMS44ODIsOC4xNTItNS4xNzIsMTAuODI1bC0zMy41NDQsMTkuNDM4CgkJCQlsLTE3LjMwOCwxMC4wMzFsLTYxLjg2NCwzNS44NTJsLTYyLjczNywzNi4zNTdjLTMuMzc5LDEuMjIxLTcuMzMsMS4xNTItMTAuNjgxLTAuMjFsLTc0LjIyOC00Mi42OTNsLTE1LjE2MywyNS43MTcKCQkJCWw2Ni43MDYsMzguNDA2YzIuMjA2LDEuMjU1LDQuMTcxLDIuMzY3LDUuNzg0LDMuMjcyYzIuNDk3LDEuNCw0LjE5OSwyLjMzNyw0LjgsMi42MjljNC43NDEsMi4zMDMsMTEuNTYzLDMuNjQzLDE3LjcxLDMuNjQzCgkJCQljNS42MzYsMCwxMS4xMzItMS4wMzUsMTYuMzMyLTMuMDcybDE4Mi4yMjUtMTA1LjUzMWMxMC40NTktOC4xMDQsMTYuNjEyLTIwLjMyNSwxNy4xNjYtMzMuNTY0VjE1Ni42MDF6Ii8+CgkJPC9nPgoJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF8xM18iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfNl8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfNF8iPgoJCTwvZz4KCQk8ZyBpZD0iT25lX2NvbG9yX3ZlcnNpb25fLV9XaGl0ZV8zXyI+CgkJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF8xNV8iPgoJCQk8L2c+CgkJPC9nPgoJCTxnIGlkPSJPbmVfY29sb3JfdmVyc2lvbl8tX1doaXRlIj4KCQkJPGcgaWQ9IlN5bWJvbF8tX09yaWdpbmFsIj4KCQkJPC9nPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fTW9ub2Nocm9tYXRpY18zXyI+CgkJCTxnIGlkPSJfeDMzX183XyI+CgkJCTwvZz4KCQk8L2c+CgkJPGcgaWQ9IlN5bWJvbF8tX01vbm9jaHJvbWF0aWMiPgoJCQk8ZyBpZD0iX3gzM19fM18iPgoJCQk8L2c+CgkJPC9nPgoJCTxnIGlkPSJfeDMzX18yXyI+CgkJPC9nPgoJCTxnIGlkPSJfeDMzX18xXyI+CgkJPC9nPgoJCTxnIGlkPSJfeDMzXyI+CgkJPC9nPgoJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF8xMF8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMV8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMl8iPgoJCTwvZz4KCQk8ZyBpZD0iX3gzNF9fMV8iPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fTW9ub2Nocm9tYXRpY18yXyI+CgkJCTxnIGlkPSJfeDMzX182XyI+CgkJCTwvZz4KCQk8L2c+CgkJPGcgaWQ9Ik9uZV9jb2xvcl92ZXJzaW9uXy1fV2hpdGVfMl8iPgoJCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMTFfIj4KCQkJPC9nPgoJCTwvZz4KCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfNV8iPgoJCQk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfMTJfIj4KCQkJPC9nPgoJCTwvZz4KCQk8ZyBpZD0iT25lX2NvbG9yX3ZlcnNpb25fLV9XaGl0ZV8xXyI+CgkJCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF85XyI+CgkJCTwvZz4KCQk8L2c+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xXzJfIj4KCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yXzRfIj4KCQk8L2c+CgkJPGcgaWQ9IlNZTUJPTF9WRVJfMi0xLTFfMV8iPgoJCTwvZz4KCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yLTItMV8xXyI+CgkJPC9nPgoJCTxnIGlkPSJTWU1CT0xfVkVSXzItMy0xXzRfIj4KCQk8L2c+CgkJPGcgaWQ9Ik5ld19TeW1ib2xfMV8iPgoJCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yLTMtMV8zXyI+CgkJCTwvZz4KCQk8L2c+CgkJPGcgaWQ9Ik5ld19TeW1ib2wiPgoJCQk8ZyBpZD0iU1lNQk9MX1ZFUl8yLTMtMV8xXyI+CgkJCTwvZz4KCQk8L2c+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8yXzJfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzRfMl8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfM18yXyI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8zXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMS0xXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMS0xIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzEtMS0xXzJfMl8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMS0xLTFfMiI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl8xLTEtMV8yXzFfIj4KCTwvZz4KCTxnIGlkPSJTeW1ib2xfLV9PcmlnaW5hbF83XyI+Cgk8L2c+Cgk8ZyBpZD0iU3ltYm9sXy1fT3JpZ2luYWxfOF8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMi0xLTEiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMi0yLTEiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfMi0zLTEiPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfNS0xXzFfIj4KCTwvZz4KCTxnIGlkPSJTWU1CT0xfVkVSXzUtMSI+Cgk8L2c+Cgk8ZyBpZD0iU1lNQk9MX1ZFUl81LTJfMV8iPgoJPC9nPgoJPGcgaWQ9IlNZTUJPTF9WRVJfNS0yIj4KCTwvZz4KCTxnIGlkPSJTeW1ib2xfLV9Nb25vY2hyb21hdGljXzFfIj4KCQk8ZyBpZD0iX3gzM19fNF8iPgoJCTwvZz4KCTwvZz4KPC9nPgo8L3N2Zz4K'\nconst CHAIN_BASE =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE2IDMyQzE5LjE2NDUgMzIgMjIuMjU3OSAzMS4wNjE2IDI0Ljg4OTEgMjkuMzAzNUMyNy41MjAzIDI3LjU0NTQgMjkuNTcxMSAyNS4wNDY2IDMwLjc4MjEgMjIuMTIyOUMzMS45OTMxIDE5LjE5OTMgMzIuMzA5OSAxNS45ODIzIDMxLjY5MjYgMTIuODc4NkMzMS4wNzUyIDkuNzc0ODYgMjkuNTUxMyA2LjkyMzk0IDI3LjMxMzcgNC42ODYzQzI1LjA3NjEgMi40NDg2NiAyMi4yMjUxIDAuOTI0ODA2IDE5LjEyMTQgMC4zMDc0NDNDMTYuMDE3NyAtMC4zMDk5MjEgMTIuODAwNyAwLjAwNjkzMjY1IDkuODc3MDYgMS4yMTc5M0M2Ljk1MzQ1IDIuNDI4OTQgNC40NTQ1OSA0LjQ3OTcgMi42OTY0OSA3LjExMDg4QzAuOTM4Mzg0IDkuNzQyMDcgMCAxMi44MzU1IDAgMTZDMCAyMC4yNDM1IDEuNjg1NzEgMjQuMzEzMSA0LjY4NjI5IDI3LjMxMzdDNy42ODY4NyAzMC4zMTQzIDExLjc1NjUgMzIgMTYgMzJaIiBmaWxsPSIjMDA1MkZGIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTUuOTYyNCAyNy4yNjc2QzIyLjE4NTMgMjcuMjY3NiAyNy4yMyAyMi4yMjMgMjcuMjMgMTZDMjcuMjMgOS43NzcxIDIyLjE4NTMgNC43MzI0MiAxNS45NjI0IDQuNzMyNDJDMTAuMDU4OCA0LjczMjQyIDUuMjE1NjIgOS4yNzI2MiA0LjczNDA5IDE1LjA1MThIMjEuNDU0NFYxNi45MjgxSDQuNzMyNDJDNS4yMDQzNSAyMi43MTY5IDEwLjA1MTkgMjcuMjY3NiAxNS45NjI0IDI3LjI2NzZaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K'\nconst CHAIN_BSC =\n 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAwLjAxIDI1MDAiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojZjNiYTJmO308L3N0eWxlPjwvZGVmcz48dGl0bGU+Ymk8L3RpdGxlPjxnIGlkPSJMYXllcl8yIiBkYXRhLW5hbWU9IkxheWVyIDIiPjxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNzY0LjQ4LDEwNTAuNTIsMTI1MCw1NjVsNDg1Ljc1LDQ4NS43MywyODIuNS0yODIuNUwxMjUwLDAsNDgyLDc2OGwyODIuNDksMjgyLjVNMCwxMjUwLDI4Mi41MSw5NjcuNDUsNTY1LDEyNDkuOTQsMjgyLjQ5LDE1MzIuNDVabTc2NC40OCwxOTkuNTFMMTI1MCwxOTM1bDQ4NS43NC00ODUuNzIsMjgyLjY1LDI4Mi4zNS0uMTQuMTVMMTI1MCwyNTAwLDQ4MiwxNzMybC0uNC0uNCwyODIuOTEtMjgyLjEyTTE5MzUsMTI1MC4xMmwyODIuNTEtMjgyLjUxTDI1MDAsMTI1MC4xLDIyMTcuNSwxNTMyLjYxWiIvPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTE1MzYuNTIsMTI0OS44NWguMTJMMTI1MCw5NjMuMTksMTAzOC4xMywxMTc1aDBsLTI0LjM0LDI0LjM1LTUwLjIsNTAuMjEtLjQuMzkuNC40MUwxMjUwLDE1MzYuODFsMjg2LjY2LTI4Ni42Ni4xNC0uMTYtLjI2LS4xNCIvPjwvZz48L2c+PC9zdmc+'\nconst CHAIN_ETHEREUM =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPCEtLSBDcmVhdG9yOiBDb3JlbERSQVcgMjAxOSAoNjQtQml0KSAtLT4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIxMCUiIGhlaWdodD0iMTAlIiB2ZXJzaW9uPSIxLjEiIHNoYXBlLXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiB0ZXh0LXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiCnZpZXdCb3g9IjAgMCA3ODQuMzcgMTI3Ny4zOSIKIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIgogeG1sbnM6eG9kbT0iaHR0cDovL3d3dy5jb3JlbC5jb20vY29yZWxkcmF3L29kbS8yMDAzIj4KIDxnIGlkPSJMYXllcl94MDAyMF8xIj4KICA8bWV0YWRhdGEgaWQ9IkNvcmVsQ29ycElEXzBDb3JlbC1MYXllciIvPgogIDxnIGlkPSJfMTQyMTM5NDM0MjQwMCI+CiAgIDxnPgogICAgPHBvbHlnb24gZmlsbD0iIzM0MzQzNCIgZmlsbC1ydWxlPSJub256ZXJvIiBwb2ludHM9IjM5Mi4wNywwIDM4My41LDI5LjExIDM4My41LDg3My43NCAzOTIuMDcsODgyLjI5IDc4NC4xMyw2NTAuNTQgIi8+CiAgICA8cG9seWdvbiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHBvaW50cz0iMzkyLjA3LDAgLTAsNjUwLjU0IDM5Mi4wNyw4ODIuMjkgMzkyLjA3LDQ3Mi4zMyAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiMzQzNDM0IiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIzOTIuMDcsOTU2LjUyIDM4Ny4yNCw5NjIuNDEgMzg3LjI0LDEyNjMuMjggMzkyLjA3LDEyNzcuMzggNzg0LjM3LDcyNC44OSAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiM4QzhDOEMiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIzOTIuMDcsMTI3Ny4zOCAzOTIuMDcsOTU2LjUyIC0wLDcyNC44OSAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiMxNDE0MTQiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIzOTIuMDcsODgyLjI5IDc4NC4xMyw2NTAuNTQgMzkyLjA3LDQ3Mi4zMyAiLz4KICAgIDxwb2x5Z29uIGZpbGw9IiMzOTM5MzkiIGZpbGwtcnVsZT0ibm9uemVybyIgcG9pbnRzPSIwLDY1MC41NCAzOTIuMDcsODgyLjI5IDM5Mi4wNyw0NzIuMzMgIi8+CiAgIDwvZz4KICA8L2c+CiA8L2c+Cjwvc3ZnPgo='\nconst CHAIN_HYPERLIQUID =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQ0IiBoZWlnaHQ9IjE0NCIgdmlld0JveD0iMCAwIDE0NCAxNDQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xNDQgNzEuNjk5MUMxNDQgMTE5LjMwNiAxMTQuODY2IDEzNC41ODIgOTkuNTE1NiAxMjAuOThDODYuODgwNCAxMDkuODg5IDgzLjEyMTEgODYuNDUyMSA2NC4xMTYgODQuMDQ1NkMzOS45OTQyIDgxLjAxMTMgMzcuOTA1NyAxMTMuMTMzIDIyLjAzMzQgMTEzLjEzM0MzLjU1MDQgMTEzLjEzMyAwIDg2LjI0MjggMCA3Mi40MzE1QzAgNTguMzA2MyAzLjk2ODA5IDM5LjA1NDIgMTkuNzM2IDM5LjA1NDJDMzguMTE0NiAzOS4wNTQyIDM5LjE1ODggNjYuNTcyMiA2Mi4xMzIgNjUuMTA3M0M4NS4wMDA3IDYzLjUzNzkgODUuNDE4NCAzNC44Njg5IDEwMC4yNDcgMjIuNjI3MUMxMTMuMTk1IDEyLjA1OTMgMTQ0IDIzLjQ2NDEgMTQ0IDcxLjY5OTFaIiBmaWxsPSIjOTdGQ0U0Ii8+Cjwvc3ZnPgo='\nconst CHAIN_LINEA =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwOCIgdmlld0JveD0iMCAwIDIwMCAyMDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8yMzAzXzYzMikiPgo8cGF0aCBkPSJNMTMyLjM2OSAxNTUuOTlINDkuN1Y2OC44ODU0SDY4LjYxNDdWMTM5LjEwOUgxMzIuMzY5VjE1NS45ODFWMTU1Ljk5WiIgZmlsbD0iIzEyMTIxMiIvPgo8cGF0aCBkPSJNMTMyLjM2OSA4NS43NTc1QzE0MS42ODcgODUuNzU3NSAxNDkuMjQxIDc4LjIwMzYgMTQ5LjI0MSA2OC44ODU1QzE0OS4yNDEgNTkuNTY3MyAxNDEuNjg3IDUyLjAxMzQgMTMyLjM2OSA1Mi4wMTM0QzEyMy4wNSA1Mi4wMTM0IDExNS40OTcgNTkuNTY3MyAxMTUuNDk3IDY4Ljg4NTVDMTE1LjQ5NyA3OC4yMDM2IDEyMy4wNSA4NS43NTc1IDEzMi4zNjkgODUuNzU3NVoiIGZpbGw9IiMxMjEyMTIiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8yMzAzXzYzMiI+CjxyZWN0IHdpZHRoPSI5OS41NDA3IiBoZWlnaHQ9IjEwMy45NzciIGZpbGw9IndoaXRlIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0OS43IDUyLjAxMzQpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg=='\nconst CHAIN_MONAD =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgyIiBoZWlnaHQ9IjE4NCIgdmlld0JveD0iMCAwIDE4MiAxODQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik05MC41MzU4IDBDNjQuMzkxMSAwIDAgNjUuMjU5OCAwIDkxLjc1OTNDMCAxMTguMjU5IDY0LjM5MTEgMTgzLjUyIDkwLjUzNTggMTgzLjUyQzExNi42ODEgMTgzLjUyIDE4MS4wNzMgMTE4LjI1OCAxODEuMDczIDkxLjc1OTNDMTgxLjA3MyA2NS4yNjA5IDExNi42ODIgMCA5MC41MzU4IDBaTTc2LjQyNzMgMTQ0LjIzQzY1LjQwMjQgMTQxLjE4NSAzNS43NjA4IDg4LjYzNCAzOC43NjU1IDc3LjQ1OTlDNDEuNzcwMyA2Ni4yODU0IDkzLjYyIDM2LjI0MzkgMTA0LjY0NSAzOS4yODkyQzExNS42NyA0Mi4zMzQxIDE0NS4zMTIgOTQuODg0NiAxNDIuMzA3IDEwNi4wNTlDMTM5LjMwMiAxMTcuMjM0IDg3LjQ1MjIgMTQ3LjI3NiA3Ni40MjczIDE0NC4yM1oiIGZpbGw9IiM2RTU0RkYiLz4KPC9zdmc+Cg=='\nconst CHAIN_OPTIMISM =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTggMTZDMTIuNDE4MyAxNiAxNiAxMi40MTgzIDE2IDhDMTYgMy41ODE3MiAxMi40MTgzIDAgOCAwQzMuNTgxNzIgMCAwIDMuNTgxNzIgMCA4QzAgMTIuNDE4MyAzLjU4MTcyIDE2IDggMTZaIiBmaWxsPSIjRkYwNDIwIi8+CjxwYXRoIGQ9Ik01LjY2NTY3IDEwLjEyMTZDNS4yNDk0MyAxMC4xMzkzIDQuODM4NyAxMC4wMjE0IDQuNDk1MzEgOS43ODU0NEM0LjM0Njk3IDkuNjcyMTQgNC4yMjg0NiA5LjUyNDQgNC4xNTAwNCA5LjM1NTAxQzQuMDcxNjEgOS4xODU2MSA0LjAzNTYzIDguOTk5NjcgNC4wNDUyMiA4LjgxMzI1QzQuMDQ3MDQgOC43MDQ2MiA0LjA1NzA4IDguNTk2MjkgNC4wNzUyNSA4LjQ4OTE4QzQuMTI3MjcgOC4yMDA2NSA0LjIwMTI4IDcuODU0NTYgNC4yOTcyOCA3LjQ1MDg4QzQuNTY5MzcgNi4zNTA1NiA1LjI3MTUzIDUuODAwMzkgNi40MDM3NyA1LjgwMDM5QzYuNjg3NTYgNS43OTU3NCA2Ljk2OTMzIDUuODQ4ODQgNy4yMzE5NyA1Ljk1NjQ2QzcuNDY1MSA2LjA0NzgzIDcuNjY1NjkgNi4yMDY2NCA3LjgwODEgNi40MTI1OUM3Ljk1MTcxIDYuNjI0NzkgOC4wMjUxIDYuODc2NzIgOC4wMTc5MyA3LjEzMjg1QzguMDE1ODggNy4yMzk0NiA4LjAwNTg0IDcuMzQ1NzcgNy45ODc5IDcuNDUwODhDNy45Mjc4NCA3LjgwNjk5IDcuODU1ODQgOC4xNTMwOSA3Ljc3MTkgOC40ODkxOEM3LjYzMjAxIDkuMDM3MjkgNy4zODk5NiA5LjQ0NzM5IDcuMDQ1NzQgOS43MTk0OEM2LjcwMTg3IDkuOTg3NTQgNi4yNDE4NSAxMC4xMjE2IDUuNjY1NjcgMTAuMTIxNlpNNS43NDk3NCA5LjI1NzMxQzUuOTU3NjEgOS4yNjMwNiA2LjE2MDQxIDkuMTkyNjMgNi4zMTk5NyA5LjA1OTI4QzYuNDk2MzEgOC44OTkzNSA2LjYxNjI4IDguNjg2NzQgNi42NjIgOC40NTMxMUM2Ljc1NDA3IDguMDc3MTYgNi44MjQwMSA3Ljc0OTA3IDYuODcxODQgNy40Njg4NUM2Ljg4Nzk0IDcuMzgzNzYgNi44OTU5NyA3LjI5NzM1IDYuODk1ODQgNy4yMTA3NUM2Ljg5NTg0IDYuODQ2NiA2LjcwNTgxIDYuNjY0NTcgNi4zMjU3NCA2LjY2NDY2QzYuMTE2MTkgNi42NTk2MyA1LjkxMTc4IDYuNzI5ODkgNS43NDk2MSA2Ljg2MjY5QzUuNTc2NTMgNy4wMjQzIDUuNDU4ODkgNy4yMzY0NCA1LjQxMzQ4IDcuNDY4ODVDNS4zNDE0MyA3LjczNjkyIDUuMjY5NDMgOC4wNjUwMSA1LjE5NzQ4IDguNDUzMTFDNS4xODExOSA4LjUzNjE0IDUuMTczMTUgOC42MjA1NyA1LjE3MzQ4IDguNzA1MThDNS4xNzM0OCA5LjA3MzI3IDUuMzY1NTcgOS4yNTczMSA1Ljc0OTc0IDkuMjU3MzFaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNOC4yOTQ0IDEwLjA2MTZDOC4yNzUzNCAxMC4wNjI3IDguMjU2MjcgMTAuMDU5NSA4LjIzODYgMTAuMDUyM0M4LjIyMDk0IDEwLjA0NSA4LjIwNTE0IDEwLjAzMzkgOC4xOTIzNyAxMC4wMTk3QzguMTcyNDEgOS45ODc0IDguMTY1OTUgOS45NDg1OCA4LjE3NDQgOS45MTE1OUw5LjAwMjYgNi4wMTA0OEM5LjAwOTkzIDUuOTY3NDMgOS4wMzMzOCA1LjkyODc5IDkuMDY4MTcgNS45MDI0MUM5LjEwMDM0IDUuODc1ODcgOS4xNDA1OCA1Ljg2MTA3IDkuMTgyMjcgNS44NjA0NUgxMC43Nzg3QzExLjE1NDYgNS44NDIgMTEuNTI3MiA1LjkzODI4IDExLjg0NzEgNi4xMzY1MUMxMS45Nzg2IDYuMjIyNjYgMTIuMDg1NCA2LjM0MTU4IDEyLjE1NjkgNi40ODE1NkMxMi4yMjg1IDYuNjIxNTQgMTIuMjYyNCA2Ljc3Nzc2IDEyLjI1NTIgNi45MzQ4MUMxMi4yNTQ2IDcuMDM5ODYgMTIuMjQyNSA3LjE0NDUyIDEyLjIxOTEgNy4yNDY5NEMxMi4xNTI5IDcuNjUxMzEgMTEuOTM2NCA4LjAxNTc1IDExLjYxMyA4LjI2NzI2QzExLjMxMjkgOC40ODczMyAxMC45MDA4IDguNTk3MzYgMTAuMzc2NiA4LjU5NzM2SDkuNTY2NTRMOS4yOTA0NyA5LjkxMTcyQzkuMjgzMTMgOS45NTQ3NyA5LjI1OTY4IDkuOTkzNCA5LjIyNDkgMTAuMDE5OEM5LjE5Mjc3IDEwLjA0NjMgOS4xNTI1OCAxMC4wNjExIDkuMTEwOTMgMTAuMDYxOEw4LjI5NDQgMTAuMDYxNlpNMTAuNDE5IDcuNzY4OTFDMTAuNTc2MyA3Ljc3MjM3IDEwLjczMDMgNy43MjM4OCAxMC44NTcyIDcuNjMwOTRDMTAuOTg3NyA3LjUzNTA1IDExLjA3NzcgNy4zOTM3NSAxMS4xMDkyIDcuMjM0ODdDMTEuMTIwNCA3LjE3NTQ4IDExLjEyNjQgNy4xMTUyMyAxMS4xMjcyIDcuMDU0ODFDMTEuMTMwNiA3LjAwNTk5IDExLjEyMzIgNi45NTcwMiAxMS4xMDU2IDYuOTExMzhDMTEuMDg4IDYuODY1NzMgMTEuMDYwNSA2LjgyNDUyIDExLjAyNTIgNi43OTA2OEMxMC45MjUgNi43MTY3MSAxMC44MDEgNi42ODI1IDEwLjY3NzEgNi42OTQ2N0g5Ljk1Njk2TDkuNzI4OSA3Ljc2ODkxSDEwLjQxOVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo='\nconst CHAIN_POLYGON =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI0LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCAzOC40IDMzLjUiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDM4LjQgMzMuNTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiM4MjQ3RTU7fQo8L3N0eWxlPgo8Zz4KCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0yOSwxMC4yYy0wLjctMC40LTEuNi0wLjQtMi40LDBMMjEsMTMuNWwtMy44LDIuMWwtNS41LDMuM2MtMC43LDAuNC0xLjYsMC40LTIuNCwwTDUsMTYuMwoJCWMtMC43LTAuNC0xLjItMS4yLTEuMi0yLjF2LTVjMC0wLjgsMC40LTEuNiwxLjItMi4xbDQuMy0yLjVjMC43LTAuNCwxLjYtMC40LDIuNCwwTDE2LDcuMmMwLjcsMC40LDEuMiwxLjIsMS4yLDIuMXYzLjNsMy44LTIuMlY3CgkJYzAtMC44LTAuNC0xLjYtMS4yLTIuMWwtOC00LjdjLTAuNy0wLjQtMS42LTAuNC0yLjQsMEwxLjIsNUMwLjQsNS40LDAsNi4yLDAsN3Y5LjRjMCwwLjgsMC40LDEuNiwxLjIsMi4xbDguMSw0LjcKCQljMC43LDAuNCwxLjYsMC40LDIuNCwwbDUuNS0zLjJsMy44LTIuMmw1LjUtMy4yYzAuNy0wLjQsMS42LTAuNCwyLjQsMGw0LjMsMi41YzAuNywwLjQsMS4yLDEuMiwxLjIsMi4xdjVjMCwwLjgtMC40LDEuNi0xLjIsMi4xCgkJTDI5LDI4LjhjLTAuNywwLjQtMS42LDAuNC0yLjQsMGwtNC4zLTIuNWMtMC43LTAuNC0xLjItMS4yLTEuMi0yLjFWMjFsLTMuOCwyLjJ2My4zYzAsMC44LDAuNCwxLjYsMS4yLDIuMWw4LjEsNC43CgkJYzAuNywwLjQsMS42LDAuNCwyLjQsMGw4LjEtNC43YzAuNy0wLjQsMS4yLTEuMiwxLjItMi4xVjE3YzAtMC44LTAuNC0xLjYtMS4yLTIuMUwyOSwxMC4yeiIvPgo8L2c+Cjwvc3ZnPgo='\nconst CHAIN_SCROLL =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI4LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA0NDQgNDQ0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NDQgNDQ0OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6I0ZGRUVEQTt9Cgkuc3Qxe2ZpbGw6I0VCQzI4RTt9Cgkuc3Qye2ZpbGw6IzEwMTAxMDt9Cjwvc3R5bGU+CjxnPgoJPHJlY3QgY2xhc3M9InN0MCIgd2lkdGg9IjQ0NCIgaGVpZ2h0PSI0NDQiLz4KCTxnPgoJCTxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0zMzMuNCwyNjJWMTEwLjZjLTAuMi0xMi43LTEwLjMtMjIuOS0yMy0yMi45aC0xNThjLTM0LjEsMC41LTYxLjUsMjguNC02MS41LDYyLjZjMCwxMS41LDMuMSwyMS40LDcuOCwzMC4xCgkJCWM0LDcuMiwxMC4zLDE0LDE2LjUsMTkuMWMxLjgsMS40LDAuOSwwLjgsNi4zLDQuMWM3LjQsNC41LDE1LjksNi44LDE1LjksNi44bC0wLjEsOTAuNmMwLjIsNC4zLDAuNiw4LjQsMS44LDEyLjMKCQkJYzMuNSwxMi44LDEyLjQsMjIuNiwyNC40LDI3LjNjNSwyLDEwLjcsMy4zLDE2LjgsMy40bDEyNi4yLDAuNGMyNS4xLDAsNDUuNS0yMC40LDQ1LjUtNDUuNkMzNTIuMSwyODMuOCwzNDQuNiwyNzAuNCwzMzMuNCwyNjJ6IgoJCQkvPgoJCTxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0zMzYuNSwyOTkuOUMzMzYsMzE2LDMyMi43LDMyOSwzMDYuNCwzMjlsLTg2LjgtMC4zYzYuOS04LDExLjEtMTguNCwxMS4xLTI5LjhjMC0xNy44LTEwLjYtMzAuMS0xMC42LTMwLjEKCQkJaDg2LjRjMTYuNiwwLDMwLjEsMTMuNSwzMC4xLDMwLjFMMzM2LjUsMjk5Ljl6Ii8+CgkJPHBhdGggY2xhc3M9InN0MiIgZD0iTTEyMy41LDE4Ni43Yy0xMC05LjUtMTctMjEuNy0xNy0zNi4zdi0xLjVjMC44LTI0LjgsMjEuMi00NC44LDQ2LTQ1LjVoMTU4YzQuMSwwLjIsNy40LDMuMSw3LjQsNy4zdjEzMy43CgkJCWMzLjYsMC42LDUuNCwxLjEsOC45LDIuNGMyLjgsMSw2LjYsMy4yLDYuNiwzLjJWMTEwLjdjLTAuMi0xMi43LTEwLjMtMjIuOS0yMy0yMi45aC0xNThjLTM0LjEsMC41LTYxLjUsMjguNC02MS41LDYyLjYKCQkJYzAsMTkuOSw5LjEsMzYuOSwyMy45LDQ4LjhjMSwwLjgsMiwxLjksNC42LDEuOWM0LjYsMCw3LjktMy43LDcuNy03LjdDMTI3LjEsMTkwLDEyNS42LDE4OC44LDEyMy41LDE4Ni43eiIvPgoJCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0zMDYuNCwyNTMuMkgxODIuNWMtOC4zLDAuMS0xNSw2LjgtMTUsMTUuMXYxNy44YzAuMiw4LjIsNy4yLDE1LjIsMTUuNiwxNS4yaDkuMnYtMTUuMkgxODN2LTE3LjQKCQkJYzAsMCwyLjMsMCw1LDBjMTUuNywwLDI3LjIsMTQuNSwyNy4yLDMwLjFjMCwxMy44LTEyLjYsMzEuNC0zMy42LDMwYy0xOC42LTEuMi0yOC43LTE3LjgtMjguNy0zMHYtMTUxYzAtNi44LTUuNi0xMi40LTEyLjQtMTIuNAoJCQloLTEyLjR2MTUuNWg5LjJ2MTQ4Yy0wLjUsMzAuMSwyMS40LDQ1LjIsNDQuMyw0NS4ybDEyNC45LDAuNGMyNS4xLDAsNDUuNS0yMC40LDQ1LjUtNDUuNkMzNTIuMSwyNzMuNywzMzEuNiwyNTMuMiwzMDYuNCwyNTMuMnoKCQkJIE0zMzYuNSwyOTkuOUMzMzYsMzE2LDMyMi43LDMyOSwzMDYuNCwzMjlsLTg2LjgtMC4zYzYuOS04LDExLjEtMTguNCwxMS4xLTI5LjhjMC0xNy44LTEwLjYtMzAuMS0xMC42LTMwLjFoODYuNAoJCQljMTYuNiwwLDMwLjEsMTMuNSwzMC4xLDMwLjFMMzM2LjUsMjk5Ljl6Ii8+CgkJPHBhdGggY2xhc3M9InN0MiIgZD0iTTI3MywxNTMuN2gtOTMuNHYtMTUuNUgyNzNjNC4yLDAsNy43LDMuNCw3LjcsNy43QzI4MC44LDE1MC4yLDI3Ny40LDE1My43LDI3MywxNTMuN3oiLz4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJNMjczLDIyNi40aC05My40VjIxMUgyNzNjNC4yLDAsNy43LDMuNCw3LjcsNy43QzI4MC44LDIyMi45LDI3Ny40LDIyNi40LDI3MywyMjYuNHoiLz4KCQk8cGF0aCBjbGFzcz0ic3QyIiBkPSJNMjg5LjUsMTkwSDE3OS42di0xNS41aDEwOS44YzQuMiwwLDcuNywzLjQsNy43LDcuN0MyOTcuMywxODYuNSwyOTMuOCwxOTAsMjg5LjUsMTkweiIvPgoJPC9nPgo8L2c+Cjwvc3ZnPgo='\nconst CHAIN_SONEIUM =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgxIiBoZWlnaHQ9IjE4MSIgdmlld0JveD0iMCAwIDE4MSAxODEiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9IjAuMTI1IiB5PSIwLjE0OTY1OCIgd2lkdGg9IjE4MCIgaGVpZ2h0PSIxODAuMDAzIiByeD0iOTAiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik05OS4wMTkgMTI3LjgyNUM4Ni4zMjUyIDEzMC44NDEgNzIuNDAzOCAxMjcuNCA2Mi41MDQxIDExNy40OTVDNDkuNzA1NCAxMDQuNjk4IDQ3LjIwNzMgODUuNzA4MyA1Ni40NTMyIDcwLjY2NkM2MC4yNzEzIDY0LjQ1NTQgNjMuODk4MSA2MC43NDI3IDY3LjAzMTUgNTcuNjIyQzc5Ljk0NzQgNDQuNzU2OCAxMDMuNjcgMjEuMzM5MSAxMDMuNjcgMjEuMzM5MUM4MS41MjAyIDE2Ljk1NDEgNTcuNjYyMiAyMy4zMzc0IDQwLjUwMjYgNDAuNTAxMkMxMy4xNjU4IDY3LjgzNTIgMTMuMTY1OCAxMTIuMTYgNDAuNTAyNiAxMzkuNDk0QzQ4Ljk3NzUgMTQ3Ljk2OCA1OS4wODA4IDE1My44MDkgNjkuODEzMyAxNTcuMDM0TDk5LjAyNTIgMTI3LjgyNUg5OS4wMTlaIiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNODAuOTgyNyA1Mi4xN0M5My42NzY2IDQ5LjE1NDEgMTA3LjU5OCA1Mi41OTU1IDExNy40OTggNjIuNTAwNEMxMzAuMjk2IDc1LjI5NzcgMTMyLjc5NCA5NC4yODcyIDEyMy41NDkgMTA5LjMyOUMxMTkuNzMxIDExNS41NCAxMTYuMTA0IDExOS4yNTMgMTEyLjk3IDEyMi4zNzRDMTAwLjA1NCAxMzUuMjM5IDc2LjMzMiAxNTguNjU2IDc2LjMzMiAxNTguNjU2Qzk4LjQ4MTUgMTYzLjA0MSAxMjIuMzQgMTU2LjY1OCAxMzkuNDk5IDEzOS40OTRDMTY2LjgzNiAxMTIuMTYgMTY2LjgzNiA2Ny44MzUyIDEzOS40OTkgNDAuNTAxM0MxMzEuMDI0IDMyLjAyNzMgMTIwLjkyMSAyNi4xODY3IDExMC4xODkgMjIuOTYxMkw4MC45NzY2IDUyLjE3SDgwLjk4MjdaIiBmaWxsPSJibGFjayIvPgo8L3N2Zz4K'\nconst CHAIN_UNICHAIN =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjU3IiBoZWlnaHQ9IjI1NiIgdmlld0JveD0iMCAwIDI1NyAyNTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLjUpIiBmaWxsPSJ1cmwoI3BhaW50MF9yYWRpYWxfMTI0Nl8yNzQ3KSIvPgo8cGF0aCBkPSJNMjM0LjY4NCAxMjUuOThDMTc3LjEyOSAxMjUuOTggMTMwLjUyIDc5LjMyNDUgMTMwLjUyIDIxLjgxNTlIMTI2LjQ4VjEyNS45OEgyMi4zMTU5VjEzMC4wMkM3OS44NzE0IDEzMC4wMiAxMjYuNDggMTc2LjY3NSAxMjYuNDggMjM0LjE4NEgxMzAuNTJWMTMwLjAySDIzNC42ODRWMTI1Ljk4WiIgZmlsbD0id2hpdGUiLz4KPGRlZnM+CjxyYWRpYWxHcmFkaWVudCBpZD0icGFpbnQwX3JhZGlhbF8xMjQ2XzI3NDciIGN4PSIwIiBjeT0iMCIgcj0iMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI4IDEyOCkgcm90YXRlKDkwKSBzY2FsZSgxMjgpIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZDNzRGRSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGNTBEQjQiLz4KPC9yYWRpYWxHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K'\nconst CHAIN_WORLDCHAIN =\n 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgdmlld0JveD0iMCAwIDYwMC4xMDYzMiA2MDAuMTA2MzIiCiAgIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmcxMSIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMSI+CiAgICA8Y2xpcFBhdGgKICAgICAgIGlkPSJfX2xvdHRpZV9lbGVtZW50XzIiPgogICAgICA8cmVjdAogICAgICAgICB3aWR0aD0iODAwIgogICAgICAgICBoZWlnaHQ9IjgwMCIKICAgICAgICAgeD0iMCIKICAgICAgICAgeT0iMCIKICAgICAgICAgaWQ9InJlY3QxIiAvPgogICAgPC9jbGlwUGF0aD4KICAgIDxjbGlwUGF0aAogICAgICAgaWQ9Il9fbG90dGllX2VsZW1lbnRfNCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIEggMTcyOCBWIDE3MjggSCAwIFoiCiAgICAgICAgIGlkPSJwYXRoMSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgPC9kZWZzPgogIDxnCiAgICAgY2xpcC1wYXRoPSJ1cmwoI19fbG90dGllX2VsZW1lbnRfMikiCiAgICAgaWQ9ImcxMSIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtOTkuNjg5ODc1LC05OS45NDcwNjgpIj4KICAgIDxnCiAgICAgICBjbGlwLXBhdGg9InVybCgjX19sb3R0aWVfZWxlbWVudF80KSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjM2NzAwMSwwLDAsMS4yMzY3MDAxLC02NjguMjk5OCwtNjY4LjUwODc5KSIKICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICBzdHlsZT0iZGlzcGxheTpibG9jayIKICAgICAgIGlkPSJnMTAiPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjI5OTQ2OTksMCwwLDEuMjk5NDY5OSw3MjUuMzE0OTQsNzI3Ljg5MzY4KSIKICAgICAgICAgb3BhY2l0eT0iMSIKICAgICAgICAgc3R5bGU9ImRpc3BsYXk6YmxvY2siCiAgICAgICAgIGlkPSJnMyI+CiAgICAgICAgPGcKICAgICAgICAgICBvcGFjaXR5PSIxIgogICAgICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEzMS4xNzk5OSwxMDQuNzQpIgogICAgICAgICAgIGlkPSJnMiI+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIgogICAgICAgICAgICAgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIKICAgICAgICAgICAgIGZpbGwtb3BhY2l0eT0iMCIKICAgICAgICAgICAgIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIKICAgICAgICAgICAgIHN0cm9rZT0iIzAwMDAwMCIKICAgICAgICAgICAgIHN0cm9rZS1vcGFjaXR5PSIxIgogICAgICAgICAgICAgc3Ryb2tlLXdpZHRoPSIzNXB4IgogICAgICAgICAgICAgZD0ibSAxMTkuMDY3LC04Ny40NzAwMDEgYyAwLDAgLTE0NS41MDcwMDEsMC4yMzAwMDMgLTE0NS41MDcwMDEsMC4yMzAwMDMgQyAtNzQuNjIwMDAzLC04Ny4yMzk5OTggLTExMy42OCwtNDguMTggLTExMy42OCwwIGMgMCw0OC4xOCAzOS4wNTk5OTcsODcuMjM5OTk4IDg3LjIzOTk5OSw4Ny4yMzk5OTggMCwwIDE0MC4xMjAwMDEsMCAxNDAuMTIwMDAxLDAiCiAgICAgICAgICAgICBpZD0icGF0aDIiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICAgIDxnCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjk5NDY5OSwwLDAsMS4yOTk0Njk5LDY0My43Mzk4Nyw4NDEuMjU5MjgpIgogICAgICAgICBvcGFjaXR5PSIxIgogICAgICAgICBzdHlsZT0iZGlzcGxheTpibG9jayIKICAgICAgICAgaWQ9Imc1Ij4KICAgICAgICA8ZwogICAgICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICAgICAgaWQ9Imc0Ij4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgICAgICAgICAgICBzdHJva2UtbGluZWpvaW49Im1pdGVyIgogICAgICAgICAgICAgZmlsbC1vcGFjaXR5PSIwIgogICAgICAgICAgICAgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIgogICAgICAgICAgICAgc3Ryb2tlPSIjMDAwMDAwIgogICAgICAgICAgICAgc3Ryb2tlLW9wYWNpdHk9IjEiCiAgICAgICAgICAgICBzdHJva2Utd2lkdGg9IjM1cHgiCiAgICAgICAgICAgICBkPSJtIDIuMzA5LDE3LjUgYyAwLDAgMzM2LjExMTAxLDAgMzM2LjExMTAxLDAiCiAgICAgICAgICAgICBpZD0icGF0aDMiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICAgIDxnCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjk5NDY5OSwwLDAsMS4yOTk0Njk5LDYyMC45OTkxNSw2MjEuMzc2MSkiCiAgICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmJsb2NrIgogICAgICAgICBpZD0iZzciPgogICAgICAgIDxnCiAgICAgICAgICAgb3BhY2l0eT0iMSIKICAgICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxODYuNzEwMDEsMTg2LjcxMDAxKSIKICAgICAgICAgICBpZD0iZzYiPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIKICAgICAgICAgICAgIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiCiAgICAgICAgICAgICBmaWxsLW9wYWNpdHk9IjAiCiAgICAgICAgICAgICBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiCiAgICAgICAgICAgICBzdHJva2U9IiMwMDAwMDAiCiAgICAgICAgICAgICBzdHJva2Utb3BhY2l0eT0iMSIKICAgICAgICAgICAgIHN0cm9rZS13aWR0aD0iMzVweCIKICAgICAgICAgICAgIGQ9Ik0gMCwtMTY5LjIxMDAxIEMgOTMuNDUyMDAzLC0xNjkuMjEwMDEgMTY5LjIxMDAxLC05My40NTIwMDMgMTY5LjIxMDAxLDAgMTY5LjIxMDAxLDkzLjQ1MjAwMyA5My40NTIwMDMsMTY5LjIxMDAxIDAsMTY5LjIxMDAxIC05My40NTIwMDMsMTY5LjIxMDAxIC0xNjkuMjEwMDEsOTMuNDUyMDAzIC0xNjkuMjEwMDEsMCAtMTY5LjIxMDAxLC05My40NTIwMDMgLTkzLjQ1MjAwMywtMTY5LjIxMDAxIDAsLTE2OS4yMTAwMSBaIgogICAgICAgICAgICAgaWQ9InBhdGg1IiAvPgogICAgICAgIDwvZz4KICAgICAgPC9nPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjI5OTQ2OTksMCwwLDEuMjk5NDY5OSw2MjEuNDk5MTUsNjIxLjM3NjEpIgogICAgICAgICBvcGFjaXR5PSIxIgogICAgICAgICBzdHlsZT0iZGlzcGxheTpibG9jayIKICAgICAgICAgaWQ9Imc5Ij4KICAgICAgICA8ZwogICAgICAgICAgIG9wYWNpdHk9IjEiCiAgICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTg2LjcxMDAxLDE4Ni43MTAwMSkiCiAgICAgICAgICAgaWQ9Imc4Ij4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD0icm91bmQiCiAgICAgICAgICAgICBzdHJva2UtbGluZWpvaW49Im1pdGVyIgogICAgICAgICAgICAgZmlsbC1vcGFjaXR5PSIwIgogICAgICAgICAgICAgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIgogICAgICAgICAgICAgc3Ryb2tlPSIjMDAwMDAwIgogICAgICAgICAgICAgc3Ryb2tlLW9wYWNpdHk9IjEiCiAgICAgICAgICAgICBzdHJva2Utd2lkdGg9IjM1cHgiCiAgICAgICAgICAgICBkPSJNIDAsMCIKICAgICAgICAgICAgIGlkPSJwYXRoNyIgLz4KICAgICAgICA8L2c+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo='\nconst CHAIN_BLAST =\n 'data:image/png;base64,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'\nconst CHAIN_INK =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAeGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAEgAAAABAAAASAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAAB13naHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAO40lEQVR4AeVbCZAU1Rn+X3fPzuwux3KJXAERwVgKCxsxIhKPKFJojFZpLE2UlJXEkogcJqTKVAWjJlrFJWiiVlmiJlaiKUiCimg8IASj4VjwiIDAInLIucAec3T3y/e9ZsbdZXanew/Qytvt6Znud/z///73X+9/Sk5CmXWJThypTfXVnh6klAwQ7Y0QUeNxDRXRCiBsspS9zBf9vq1lp1Jqx/7O8V2L3lbJjgaPg3dImVGROhuIfMv3vUu10uVKq/5KWaWWimE8LZ7OiNaeGVspW2xVZL775rlfix87AVyltuy3ldYr5qyNf2wqtPNHuxLgnuH6NL8odZ3ScpMWfYGjEsW4i69dgyy+hQJfiSUkiqUcUfhzdbIe93fBK3+y0vElszeqfaE6ClGpXQgwtfzwIMsuvgOd/cBW8b4+ZtbMZAOEfeDOCecdNOE/UPviboMxLDs/xCQIOYdE8XVqN1o+i44en7O+eEf+FuGftokAQLzMshJ3i7InOyrWy9NpM9scXgNDzwXCQDoG7u7UXUnZ6cHVuaeS4s5KYnEl2tdyaJeWze96cni3FidYCc1iQK7gcnH91H4Q4jHfr3tkfmW36mYbFHjRagJMG1V7DYB5CMCc4+pUbj0TYS8jkugk0u9sS4ZcYMvA82zp+TUlJV2VQVBZjWefrHDkcy1/n5OWD970ChKBOJEbHBUXz09/pMWdOXdd6UsFcM37OjIB7hm+t9R3yh7AmpwCoWZx1lkM4pjxHv2VjLjSkfMus+W0MyzM8vF3IAy5wvC+adH4g0ugrlrL4z9OGo5objk0biWGG7T2wUd6geVW/3L2xtMpQEOXSASYdn71YOUlnnas+DjXrwcu+ANSbkqkOxAfc2NMysfb0gUsTvbnFaUUFYv89aG0rH7BlVgifEsKSscqxrJIrrTc1KTZG8u2h20NZgxXpo2s/oblF79mW0XjMn6dQZ6sTnYee7MjdzyZkHG3OFLcRUka2jsq8lkoSsogF7I/Qt45EYTJxsToWPHrM0bVVoRsCvEaokwpPzpGWYmXsO7O5MyzZIAkWfy22XG5ZnqREXJEXIfTdHlHZdt9231I/LyvCz4kbIRRK/vl6YC5YANUKEiAKaOqKxy7aLEldm/PB69jeoj8uZfbcvvCuJwFIZfBY8qASIVIHr/IRfFSkc3/9mTTO57YBTRBS+MQRsIqdmJxGE5okdZTy+uh39UbljiDPSPpAwk/5nsxmfDTmFgOEA+5zinUKOg4yyQWLyMUgU26Tst/V3ny2u8zUgtBGFYAtkQI2COwQtxtvqcvn19ZXNVc3WYJQGnvOl1ejVmJsYbtKeyw5r91a0zG3xkLEAjJ7tTtBz/TsuE1V/Zs8SV5DEgnsXJJBEBWe1hL9V5t5El7IJ9FloLR85OrLPfoVc1pB8xh/uI5nR4ssorHUriwZKDtLrrJCZDHrGdnL3/rL54S+Y8xu4t/m5YjRBKcAIfIXGYJoCp/kzvau3DiYlbJ2LTjPYi+p+brPy8HTB1ZO8G2Yku1duGcQcJijZ97mS033R83wIYVdJxNWndP/CQpNYd0hyCZD6nGz2BIq5inlfeduWsSrzR+l0cIzqzQXeHFzYNuNchT1fU+U8m19xSZtRkWeQ7EWeXaPrLvVCFPKMB1AAW20tyZFYe68knDcoIWSOm6qTGreBgtPLI5WZhqrksvFVrgZQcge9G6y7J69vnJvhMX4pTSsROWQSMCTD+/bgBm/y7a9iy08EZf5+RUXVTAYZ9Kn7Po2kZt2f71iROCLlOIY8PeGxEA7H1nTBX3YKCCaorm7bjvx4xz07BR2O8eBOfQMbYMOd+SFCz0nOCk6G/rFRaI4/WIk6OKuwPHyQ2b5ghw18hjvQDVD6nvWWjKXniDI2W9wfogRmsKEaZNf8Ov4jJqoiNFCZi5RLytBRxF+Cico/RncPP1pADXAIicGnSUdV1MlfSm2iPC9OpGXuUY9dcWeGkode6h5Mb7iuQQbIEa6Py2Fi6pZA2Mp5WerFvmGtlEa7JQYaAmZpf0Vn7d9aj7BOsbAswSbVVL7S2+BFNNyU+Xll4d7fu2liwHde+npMeA9hEIRPjrFyPWUG7Lkt+kTKQpjKwJ4pD6Zqj3J6HptKHb0RGpIQg6jfZ9BiqDYAb9+dZ6dM0RjIQgcdvjooBOwy+rmGjL8CsccYOwRHND554zGAvtP3rGiNRZfBgwju1dCrMxwaAlWZaRnNMGW+1OgBwU7fiFdskwCNows89hiSNxFeDM34YAvqhLafGxcJaGjLZNHM88+JJ/EGraKmEJQHSIK3Hmd2vSJdsTaFzO0DULOxs4AtHXQByYZ1/mDxvm9qcfgHMjwEtclfJHThq0PeF0q+3TFz7qAGxVGFeV0dueEFRehA5JIDMD7SPfCtMb087xqGJ3fujL2qVuqEBqtuNAEFr9u/Xq09fRXmYQIrslpAqpyNA1o7dh9SsdHl40dNyMsbuz43TcHcjTBti21pPXn8wY1WrnFHrhYbkAENEu8bz0IEe008+y4N+TABAoJACXQRipSmeHfvyKZzNSVekDqECOFAahbTU4+1TPNQeDGEIU5LMjc6PF8/1+jlheOcWCKbh17gnbPdAN2bp575x1xvKfmZGS3ZsgWSMKorydRnhIIrQthgDiKW+kg328CZ5QNwZkKO4cznljOOyfz2cM8vGSCJB/Sapy6w6G0HjsPqqhgVAIEHe4XVUASMOCMELI9pz5r2KhWQyMh1rYni+Eb3782Kp1LfP3dyqeYs8eIXi9GX6yGZ74uBBkWF4tFmqIIrD9wBFWKGHZYmen6CX3FjH1myxYRcuDpIVgCdQfy9qELUNGk/niW2LSF0yUQtyUfgPVaGuuKGG2lqEK/9aGFvCVftXR2l6fE3uY+mMHQIAQ4e6szXDbnLiseK4NahBjMkzO0BmlehgNFB7NlmpiYN+uhBB0d/mBUygW1B/1urEBuA4KrHF6dV0RMPnuzKLWG0IYpx4EeP8frrEnaOCcDCJQCxB3R9mxKt9z6xA8LrFs3xCg7oiW0m7hrMEsy1MbUINELiAycwm+/aMYjDBL/nI/KNDBhRkn0AJ1xN06XLpnN6TBZ0YogAMYvz/wKdgxkIuhQaFg5NKJfKEdiZiEHBlxpS2DK+wOF6zEFZJ+5+H9e3Zbi94+I6m1tZ6pJyxk/x0bvXbZnwtNPVYEISgD+p+D2QkhgyL13aQyccWEVS6qOiNpjF4YA28xyYCFxPnkPdiGISMsTfpu80/KlY4uxJU4c5zA6vfst7CPluRjOha7PvZl3zbffO9oYLL9U/Al4VFuXYPt8QieXbZ92DtxJK4CnNnGEGDOhjj2bP33qBtp5iZrIJXfbH9A6ECRzZte9Ov57s2nMrILjlVHEsB4vsC1y4b4JySAoTWjo9Ol9nkIh3HZtcit7DE3BikvYewCdtZcIXJcYQyLcyscyz1XuPCOwa1dj/A29xGdDpx9DgoeByjqj7NEGUmTGy6j/cXaq73PshxkV3hmP79yuYedIcdEX3MQR/xC5IngsoUZ2YzsjwzyApoWl9E4PO5ox4omf0bXfe5qf0kWhkAG4NfC9Z33wxJaxMwKFrLh6hcyxi4wM2ieRvvgcqJh8+Kv07LuFReEBJac8ibFwbLoaOQ5pMHNV08bXI/DkCMAf0MQPebq+kPUk0SaLLvyDxmzZo/Xj3TjWuesU6swZpCz8EiEhlekXltXmThldP1BaMDfNeyhEQHm/qdkJyykBczAZHFwe2+JK1uQvMSEx6iFpjVTYsLGF6P2H6U+cdJaLySODds1IgBfxFVmfsav38R8XLIwDaOX5qXl6H4kL+UkRsMuWv7OnOBGUq/l6h3ylrgQp7gqmd90gBMI8PDa7keQATsdqxUGqjLsv3erlr/NRiI0n5zQommXX/ymcBs2xkIOYeAuf/Hm5H2j0QO942H2pz28Vh1pOjIV1Anlnd0PbLmgz8+7F1ml36TXRIG49xMNv1+bbaiwM0r1yczwbnBytq7xjddHMzfnL4DKRsVSNkYg7AkAt/AASVI4nJFcOH99p0fzVWuWqR239l7XsSuwj2bS5JjyvvrPyOGFxxclTY5LaPgVtpw+JCEb4fIyE5SGFolpOApQ1R3VcngPqIDSWo1jGjf5YJpc2q9f5bg19zZ5lftJWdxsaT5R0kGiJJKmQD5GhsIU1iUnccaJOK+scOR+Ajlk2cK0UbvtYQm2OVEyixTTTbWKvYzdgt4mNR4TRd3OVNlrf4bkKbA4f0cuDUhPYVsEc3jbOl+emZ40mx581tpCoYdcBxg8yYkL1pWtbamfgitvzrrSta6XvJ4dIhvb6G/a7h+84clTk1OyBTo+a8u3NNAJ78jxxy9yBeOKg8otGXph2+IBhJGwipe+vhDyhKkgAVhpQWWX1Up7E7F/sJXrioVI76vy5VnsDC3FSQ8GUpjv3xZhxknvORCOaiAOzDhRPggbYdR+8uq5gDlM21AEYEfkBJWpvwLZ2CspWaleaOlRqq963jUnPVY850o9BBoJ0ap1DArUICgblfsJi5H2fnqln66/ct76sjVhkGedvGqwucarP3+o+qJed73oqVgJ/OrRiKwgtB64zYzsbvqXJx8icanmoEgpdpg7Ia7Itc31XGhS6QscQlrtcmSMMxgTVgZwvYPtcGbGfQRHZm6f+37PSEfqohI7R5vpo2qvxj7ywzhB0vKhKWSbMOGCOQfNHZoicQ7s0EioThlBSOeoUKFtbw5N6fRHQP4X89aVLi3UJt/7VhOAnQXH5kruxvxOxjmiVh+b21eFY3Nwmug2F/IKGc/jrCPz8wAW/KO+nzw1x+YaUnPGyPqBcKXvAEC3Wla8Lzdbmx6czOl/yAyuB846qW/u+MJZb06AMozF3Sv680h2xEKR53yv/nGcF6xCF20qbeKApiM3OjqrcXTW+j85OtuUEPzNw9Mah6eV712CGUMShiARO3t4Gs6RyUaHOYjC9cx4JHnCcI72a7Fp/Rk2bythG7/1lTk8bbDJ8zEJx+d7HUv1y2g9ENJ9ADT9eb7WE1B1GJAGffRmXMsRk98AG2CnslVV19L47lkn4fj8/wC0COSpjQv+wAAAAABJRU5ErkJggg=='\nconst CHAIN_MODE =\n 'data:image/png;base64,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'\nconst CHAIN_TEMPO =\n 'data:image/png;base64,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'\nconst CHAIN_ZORA =\n 'data:image/png;base64,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'\nconst TOKEN_ETH =\n 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzIgMzIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxjaXJjbGUgY3g9IjE2IiBjeT0iMTYiIHI9IjE2IiBmaWxsPSIjNjI3RUVBIi8+PGcgZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIj48cGF0aCBmaWxsLW9wYWNpdHk9Ii42MDIiIGQ9Ik0xNi40OTggNHY4Ljg3bDcuNDk3IDMuMzV6Ii8+PHBhdGggZD0iTTE2LjQ5OCA0TDkgMTYuMjJsNy40OTgtMy4zNXoiLz48cGF0aCBmaWxsLW9wYWNpdHk9Ii42MDIiIGQ9Ik0xNi40OTggMjEuOTY4djYuMDI3TDI0IDE3LjYxNnoiLz48cGF0aCBkPSJNMTYuNDk4IDI3Ljk5NXYtNi4wMjhMOSAxNy42MTZ6Ii8+PHBhdGggZmlsbC1vcGFjaXR5PSIuMiIgZD0iTTE2LjQ5OCAyMC41NzNsNy40OTctNC4zNTMtNy40OTctMy4zNDh6Ii8+PHBhdGggZmlsbC1vcGFjaXR5PSIuNjAyIiBkPSJNOSAxNi4yMmw3LjQ5OCA0LjM1M3YtNy43MDF6Ii8+PC9nPjwvZz48L3N2Zz4='\nconst TOKEN_EURC =\n 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIHZpZXdCb3g9IjAgMCA5NiA5NiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzM4NTNfMjE1NjIpIj4KPHBhdGggZD0iTTQ4IDk2Qzc0LjUwOTcgOTYgOTYgNzQuNTA5NyA5NiA0OEM5NiAyMS40OTAzIDc0LjUwOTcgMCA0OCAwQzIxLjQ5MDMgMCAwIDIxLjQ5MDMgMCA0OEMwIDc0LjUwOTcgMjEuNDkwMyA5NiA0OCA5NloiIGZpbGw9IiMwQjUzQkYiLz4KPHBhdGggZD0iTTU4LjIgNTkuNDMwNUM1Ni4xIDYwLjI3MDUgNTMuODIgNjAuNzUwNSA1MS42MyA2MC43NTA1QzQ3LjI5MjkgNjAuNzUwNSA0My4yMDM5IDU4LjkwMzQgNDEuMjUgNTQuNDUwNUg1MC43OUw1Mi42NSA0OS45NTA1SDQwLjEzOTdDNDAuMDgwNiA0OS4zMzA3IDQwLjA1IDQ4LjY4MTIgNDAuMDUgNDguMDAwNUM0MC4wNSA0Ny4zMTk4IDQwLjA4MDYgNDYuNjcwMyA0MC4xMzk3IDQ2LjA1MDVINTQuMjRMNTYuMSA0MS41NTA1SDQxLjI1QzQzLjIwMzkgMzcuMDk3NiA0Ny4yOTI5IDM1LjI1MDUgNTEuNjMgMzUuMjUwNUM1My44MiAzNS4yNTA1IDU2LjEgMzUuNzMwNSA1OC4yIDM2LjU3MDVMNjAuMTIgMzIuMDEwNUM1Ny41NCAzMC42NjA1IDU0LjYzIDMwLjAwMDUgNTEuNzIgMzAuMDAwNUM0NC42OTY0IDMwLjAwMDUgMzcuNTk2NiAzMy45MjcyIDM1LjAyNjUgNDEuNTUwNUgzMC40MlY0Ni4wNTA1SDM0LjEwMzdDMzQuMDQ4OCA0Ni42ODIzIDM0LjAyIDQ3LjMzMjQgMzQuMDIgNDguMDAwNUMzNC4wMiA0OC42Njg2IDM0LjA0ODUgNDkuMzE4NyAzNC4xMDM3IDQ5Ljk1MDVIMzAuNDJWNTQuNDUwNUgzNS4wMjY1QzM3LjU5NjYgNjIuMDczOCA0NC42OTY0IDY2LjAwMDUgNTEuNzIgNjYuMDAwNUM1NC42MyA2Ni4wMDA1IDU3LjU0IDY1LjM0MDUgNjAuMTIgNjMuOTkwNUw1OC4yIDU5LjQzMDVaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMEI1M0JGIiBzdHJva2Utd2lkdGg9IjAuMDMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNMTggNDguMDAwM0MxOCAzNC40MTAzIDI3LjAzIDIyLjk1MDMgMzkuMzYgMTkuMjMwM1YxMy4wNTAzQzIzLjY0IDE2Ljg5MDMgMTIgMzEuMDgwMyAxMiA0OC4wMDAzQzEyIDY0LjkyMDMgMjMuNjQgNzkuMTEwMyAzOS4zNiA4Mi45NTAzVjc2Ljc3MDNDMjcuMDMgNzMuMDgwMyAxOCA2MS41OTAzIDE4IDQ4LjAwMDNaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMEI1M0JGIiBzdHJva2Utd2lkdGg9IjAuMDMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8cGF0aCBkPSJNNTYuNjQgMTMuMDUwM1YxOS4yMzAzQzY4Ljk3IDIyLjk1MDMgNzggMzQuNDEwMyA3OCA0OC4wMDAzQzc4IDYxLjU5MDMgNjguOTcgNzMuMDUwMyA1Ni42NCA3Ni43NzAzVjgyLjk1MDNDNzIuMzYgNzkuMTEwMyA4NCA2NC45MjAzIDg0IDQ4LjAwMDNDODQgMzEuMDgwMyA3Mi4zNiAxNi44OTAzIDU2LjY0IDEzLjA1MDNaIiBmaWxsPSJ3aGl0ZSIgc3Ryb2tlPSIjMEI1M0JGIiBzdHJva2Utd2lkdGg9IjAuMDMiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzM4NTNfMjE1NjIiPgo8cmVjdCB3aWR0aD0iOTYiIGhlaWdodD0iOTYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg=='\nconst TOKEN_WBTC =\n 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDkuMjYgMTA5LjI2Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6IzVhNTU2NDt9LmNscy0ye2ZpbGw6I2YwOTI0Mjt9LmNscy0ze2ZpbGw6IzI4MjEzODt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPndyYXBwZWQtYml0Y29pbi13YnRjPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iTGF5ZXJfMS0yIiBkYXRhLW5hbWU9IkxheWVyIDEiPjxnIGlkPSJQYWdlLTEiPjxnIGlkPSJ3YnRjX2NvbG91ciIgZGF0YS1uYW1lPSJ3YnRjIGNvbG91ciI+PHBhdGggaWQ9IlNoYXBlIiBjbGFzcz0iY2xzLTEiIGQ9Ik04OS4wOSwyMi45M2wtMywzYTQyLjQ3LDQyLjQ3LDAsMCwxLDAsNTcuMzJsMywzYTQ2Ljc2LDQ2Ljc2LDAsMCwwLDAtNjMuMzlaIi8+PHBhdGggaWQ9IlNoYXBlLTIiIGRhdGEtbmFtZT0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTTI2LDIzLjE5YTQyLjQ3LDQyLjQ3LDAsMCwxLDU3LjMyLDBsMy0zYTQ2Ljc2LDQ2Ljc2LDAsMCwwLTYzLjM5LDBaIi8+PHBhdGggaWQ9IlNoYXBlLTMiIGRhdGEtbmFtZT0iU2hhcGUiIGNsYXNzPSJjbHMtMSIgZD0iTTIzLjE5LDgzLjI4YTQyLjQ3LDQyLjQ3LDAsMCwxLDAtNTcuMjlsLTMtM2E0Ni43Niw0Ni43NiwwLDAsMCwwLDYzLjM5WiIvPjxwYXRoIGlkPSJTaGFwZS00IiBkYXRhLW5hbWU9IlNoYXBlIiBjbGFzcz0iY2xzLTEiIGQ9Ik04My4yOCw4Ni4wNWE0Mi40Nyw0Mi40NywwLDAsMS01Ny4zMiwwbC0zLDNhNDYuNzYsNDYuNzYsMCwwLDAsNjMuMzksMFoiLz48cGF0aCBpZD0iU2hhcGUtNSIgZGF0YS1uYW1lPSJTaGFwZSIgY2xhc3M9ImNscy0yIiBkPSJNNzMuNTcsNDQuNjJjLS42LTYuMjYtNi04LjM2LTEyLjgzLTlWMjdINTUuNDZ2OC40NmMtMS4zOSwwLTIuODEsMC00LjIyLDBWMjdINDZ2OC42OEgzNS4yOXY1LjY1czMuOS0uMDcsMy44NCwwYTIuNzMsMi43MywwLDAsMSwzLDIuMzJWNjcuNDFhMS44NSwxLjg1LDAsMCwxLS42NCwxLjI5LDEuODMsMS44MywwLDAsMS0xLjM2LjQ2Yy4wNy4wNi0zLjg0LDAtMy44NCwwbC0xLDYuMzFINDUuOXY4LjgyaDUuMjhWNzUuNkg1NS40djguNjVoNS4yOVY3NS41M2M4LjkyLS41NCwxNS4xNC0yLjc0LDE1LjkyLTExLjA5LjYzLTYuNzItMi41My05LjcyLTcuNTgtMTAuOTNDNzIuMSw1Miw3NCw0OS4yLDczLjU3LDQ0LjYyWk02Ni4xNyw2My40YzAsNi41Ni0xMS4yNCw1LjgxLTE0LjgyLDUuODFWNTcuNTdDNTQuOTMsNTcuNTgsNjYuMTcsNTYuNTUsNjYuMTcsNjMuNFpNNjMuNzIsNDdjMCw2LTkuMzgsNS4yNy0xMi4zNiw1LjI3VjQxLjY5QzU0LjM0LDQxLjY5LDYzLjcyLDQwLjc1LDYzLjcyLDQ3WiIvPjxwYXRoIGlkPSJTaGFwZS02IiBkYXRhLW5hbWU9IlNoYXBlIiBjbGFzcz0iY2xzLTMiIGQ9Ik01NC42MiwxMDkuMjZhNTQuNjMsNTQuNjMsMCwxLDEsNTQuNjQtNTQuNjRBNTQuNjMsNTQuNjMsMCwwLDEsNTQuNjIsMTA5LjI2Wm0wLTEwNUE1MC4zNCw1MC4zNCwwLDEsMCwxMDUsNTQuNjIsNTAuMzQsNTAuMzQsMCwwLDAsNTQuNjIsNC4yNloiLz48L2c+PC9nPjwvZz48L2c+PC9zdmc+'\nconst TOKEN_DAI =\n 'data:image/png;base64,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'\nconst TOKEN_USDC =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAlmVYSWZNTQAqAAAACAAFARIAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSATEAAgAAABEAAABah2kABAAAAAEAAABsAAAAAAAAAEgAAAABAAAASAAAAAF3d3cuaW5rc2NhcGUub3JnAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAABpltK/AAAACXBIWXMAAAsTAAALEwEAmpwYAAADBGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+d3d3Lmlua3NjYXBlLm9yZzwveG1wOkNyZWF0b3JUb29sPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NzA8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpDb2xvclNwYWNlPjE8L2V4aWY6Q29sb3JTcGFjZT4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjcwPC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzI8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyPC90aWZmOllSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4Ks33woQAAHv9JREFUeAHNWwmAVWW9/59z7jZz7+wLM8Aw7COgoCwquKGkZG5oQpZhmaZmub18Vq/ljfUsLUvLVy+1Qk3TxxiohbtpaoKJISADAwOzwAwzMPvcfTnn/X7fuedyZwGx7L33wdx77jnf9//+2/ffvu9o8pE1S1u+uk6vW1FvidSa867Z6N4/Vtx5wdQYw9BnJ8Wao5tyvKVJFToUayJ5miVFnB73evE1iHs9YsleU5f3DEvfYpruzYOBRGdluyTefWB+AnD15atnanUrlpsiGP0RNMz5j7faWkuvrdXMxbWvug72e/NTmhwjXt9SM2Weo4l1nG54/ZrhFssC3vizzBS+U/Y3ptd0Ax9G+lsXTdPxOClmKhqyRNuKny9p8fjzhiU7ygpiA6/Vnpl05vxHsf9HGADaIARNs6be8KzX8JaM1V2eJaZpXgGkTjN8eSAiIVYiAkJBsWahobempsRY0dQ/UmCpX5RouhPvoKeuG5o7B7xxSyo6KKLLG7roj5jJ+CupWHd7432fiGEE4CiYf5dG6Jz/Q7faWo4jOda0m/88wxUYd4NmuF4Ud86Duif3NBFTUpHeZCoWTIF4kkoRu0ASvnkNUki+0+xrwjTsPpqLYziWMAiLMHUXYGMOzsU5OTdxwDhLbJwciEf9fQiJoxuC/pxPsyZf81KBu7DkbF3XajVP7ixKOxWPUL8pkqEEHh3sI/eCTuC/SR0yPLm6WlLx8DZTs2oT3d0v7Xng7H7gBvwUSUetDR+CAYeA19y0YbaWm3s19PgLYrj8qXgopSm6Qfj/RrOslKVDRTx+Q1LJENbNKisSfbDhpydvwfQZIR0NKkeFMA0OpQ6A1vSvbfy6kV/4jGYYN2Bp56SiQQtPYMFGEs8BMHtKZ44Gmew+RxwLJeCcnJs4aC73V4jT9Nv++g17OqiFwjkb4ujXH6gBy1evNupWrEgJvms2Tv6Z4cm5wkwmA1YyChwxPHstp+cg0eSsn1LCRRI34lDghD1idEzSd0m4C2B9MGwcm4IJCWG8A3PEYBpQ/NdcPk13uYJYho80zN9zowDnDO4jBh26cUQGLF9tgXgtde4Nu7x7vN2PYq1fjLWuQe1Atm16D4GyJU2AAVAQB8Y7BmAXojALXl2Kcw0Zg/vJIzDBIf4AvGT3YFI0ADFyDJmR7xI3AA+m2EOxXX0P+aCPMVwWbINlxcNrK7siK1976MyoQ8OQvlk/DsuA5csh+boVJlycx/CW1umenPPMBKRuYTkcRuqUOP1bfV9SXIYmn5sZkCXHl0g8Zco9r3RIezAl+WBCmo4sNOxLDJEBPCzL0eWmxRWSB8a9+F6PPLYtKIiCZFahSzEwqhzLiOGUAD2Tqbt9mhmPrIt1bVvR/NCVMdCigxawdWQ7DAOUwbMETKiZVP2E5sq9xITKw5XThQ1plAlv+oH9LhAYx/U3FxbJ+SeNkenjA+J16zIwGJOvP7FH1m0dkOKAS0YjgHB8YGBPKCnnzsyXuz49WQryvRJLmLK9dVCeWt8hd7/dJx4wcBps3yBUiWNGIwAhRErHkrCS4TUNTS2XiSI+TRPGZDdX9o/0NYUoU29EcOMrvUd35ywz4yBeaAiHNiideIB01DSloS8lVx2fL9csHSfTq/LFAEP4nAtFxwfVhih8UCNRbow1ABcuVnweQ+ZOK5Q5kwvkkwv75D+fa5PV9UEZl28ouElow3AuQFC6lYiaiEmW1UyceF/qhmdvafwZZGNrLqfItJEMINa3w5Hnlt9iuHNWphJRUjKq2pP4zmhKKvNc8tjFVXIepK7DcpmAwT+bXqg8kEzQEh5li0O6HG83XGOoDvbPmVYk94MRi/7cJt96oVMS8ZSMcRugzJkrM4HCGRGjiSh8JRi/FzTdBTq4RDKdeDFUqnZYadUE3zjW5fFfZyYTARi8EcQTBo1SXzgpF00LyB+ur5ELFlVmiFcSZycQ3t4VkTXvdMn69rDoWNPJNGO43p0/IoGf6hn7bNgblle29krvQMzWIDCaNpdBJRl85VlV8vK102TxuFzpgwA8nIsAshulDdxJg8ubdy1pAhDasCE9s3/w2pp962Z/TIvfrXtzrjOj4TTHDg1iJyxD6Q2l5JQpAfnNF6eLP+BRyGlENI1E8/6QrNvcIy9s6pI/7YtKjs/2AnEI1oNOIRg7SpaNEQRtCN0kn3XA+vvxvRTwPwYjunhGoZQX+1RfpRdKkJp09UTk8w/skvfaIlKYS+aqLlkfimDRfbmaGYv80mt5bt1y95wQp8Sf6j3UqMHoFRYXXaB7fN8yEzGPvYgzNKkRRLA3bMppUwNy7+WTpLgoJ61ZlJJIJJyQ3204KD9+Zq/8/K0u6UA+V51nqJiAxFNzBoAp0iTJcSG1AdMGYZ+5lHPIBDClCByOAdjbLRF5cVuftICZ+R5dJpR6lQaQzVwi/ly3LKrOlc2tQWnqjosfBpemntSlm7pEtCSgqSZpJeu7xy5pkPq6zHpM96WENWvKLW9NdXm8z8CNzDBjDD8OLRHMBwRF2iH5z8wulO9dNkny8rwKEao829adPfLNtW3y9r6weEFMEdwZx8VBHb6UdDsh3Wr49TsvmiDVpT7FvK1Q+W/8ca/0gTFlaU2gZDy45pIZCCN1xvWiSXnyw0uqpHp8HqfLML67Nyq3Ptoof2wMSQU0LcFJhzZT9/p1uPHtyXjswt33LGrEaEWz0oDly2cZA7OW+3LKK69AovEZpJ4mng6xD2CutMOQzS/zyr1XTJOiQp8inmuT5L++6aDc9N+t0nggCsINycGAGAinz7fZI5ILIpoQI3zqmDy56pwqKYNalxR6parEK+9s65G/dSWkUhFgY88lQVr88AREt7kzKm/tGpQTKjwyphRpMuZWmpDjlnkTcuX5LX0yCAYT12Es0MxUwnT58st1Xd/rqzxr09JZ9WZ9fR1dm6UxSPCMHVuGKO86ZnVwI0P5h19uTDYAJ//diydIKRBXWW6a+D9tPCA3rG6RDkR+BYj4qIYknoQ7xBMi7Ju4ocoeL6QEzjizpDBfDh7SdaJLpjljCcuLpVIE/78bDL7u0RbZtKNH9VPLAc+rKgPQqvHSieVJRmd0PA2NNJE2FFquI612YGRpKDHV6YtrLZfX7z/H8AampOKAkJXYEBCjt92Q3PfPLJX5xxTb1jht8N55v1tuW7tXBiIpCUDlY6CKhDnIO9f5QKoRRiDaGpPBvoSSnMOBJDh2EGs41oXCGQaCR86jNJHICQCINiQABu/vj8vNj7fI9t19yu7Q+FITzjqhVL66sFB29ackbzgTQBNpI42klTSTdqO+brX4T1hfiCD6B+JyVVuJmAnVygiCRqsLa3MmwtA7L58quTkMHWyD19cfky89skf29sQkL9el4n+HcGJO4ukxqBE7B5Jy8hiP3LykVC5YWCbjy/3KAEKJlI/HipIKr0j9QTAIup+HiUn08EZYXF6d/QnZui8iF80tEg9iATaot0yvzJU173apBAw8GMJIrCdTc2NwIlEUCTevfe2rSyMgVLNShlFjavopZjRE0jLEq8kA5WB/Um5cUiHF+Wl3R8CI71e9dUA2d0QkXxE/NBgh7kQgBuZBQ+UX51fIkzcfK1+6eLLMhRaxDEj0uNq8IOC8RWPlrmtmyLM3z5ApFT5pR22FzButMbPMx3J4qy0kqzZ0ZYwhl+XYshz52pnl0tyTkMAwLSBtpBESPoU0k3aDhcxgKvcqqMZiKxlBCqbKVmpeHxBoQ/5zMozOvyybKH6fHTjS+GxrGZQfPN0qERBAa00is/GFVkoSxOdivT+ycqKcf+o48bocSVGDnD+M40DoPtPf4gKfLJtVIBtBXCO0wQ8uAPSQxt8Mlbk8OzrDsnBynpQWQH3QCLcc16+83yNdWI/0XBl7gCkxUdLwFaDclmo79uzL3tR3Sh78vXmOMhBZQuQgH6WPtPTSBcVS5AQ7gBGLJWX1+gPy7v64lGLBJkB9NvFERAeWPfj7yYVjZcGxpUrSRJzEHuyLybuN/fIS7Mf6hl5pARGpFOqmeMiwuRCxxa8/NVGmFnklguVAZmY3/qRrLYHhfLM1Kqs3HJA4wmKKgLZgDMatnF8kzVgmww0iHkPlkVuCZtLuYt0ei+c4Vm+pIs5ElDX9cjGCmPkzipWFJnBSuhvu6JktvVIIf05EhuGnVD8IxOdO8MvHThyjQCqbj77Pbzwoq17bLxv3R6UZVq0cEj6u0C0rFpTKyo+NlRy4NIbsZWV+ueX0Urnq6TaphHZwDjIwuzFoIg5PI2VevrBcjqlCJRr3mIqfNKtY8l86oNJr6p0zljSSVtw5Li9ojtHhCOdo8AGIlmD9bVrYmarThBBt2eRcmYp1xUYkUOuXN7b3yubOhEyG1adlHt7oMnvBgK/MyVcWjnxjsNTcNii3PNEqz+wJiwvrfjaSqGL4/ffhFb69pk0efq19CKjTZxdLiceF8vCQ2+oHcaEtIA7vdiTk9e19CjdqGNVsekWufHxiruxG4EZaMg00klZFM2hH6qbP0XRwXa3iTDfWp8WKmXJcdQApKSM6YAHgg3B37zT0iQvqBwWxOXZomOK0C58eSKISkR6bGovv+paghNxItQvcyP1tt0YAlTBoBcWG3Lu+R/buG5Qk1DkZT0oMiU4KGoKa+Ih5CJe0EgcX8NvY0C9B4Mab1LYA7NXciQEReHXU4xVeHMNGWkkzwsvZfHa82rEZNgWLFn6vJjVQKzekpTIxdG48EJY1jUGZgHw8DD9FJEZr6v6wh0UohkgQnIF19SN54bJlPg86UW3QJQQbfN79u6QUy4BDe6OIF9BJhWujTMI+xGFCvi6/Rxh8HXCbGyhQdsADbzdlYp4k3Z1qjqHDmS1T4a0TIAdzPHyaMkBOJ/r+NqhwNYisKvKo25yMkmyF2+sFEaVIZGh2RmsprFmWsHr6WB+CUDgYbU5NsXzxxELpgGH9GwzoNsQGu6FlYIkUQtKVmDiKFLtxf1h2IQHqRmQJPh2xEYcS4NIDmMRNaRuXDCadWOKTyVhm+6EmAJ9pNLbKWFjWeOzAaMVqr87WKKUqtLphxNTjQXyxH6qSbilwm/k9auAK6SyYThclOWZ6uUgbX24YlI+fSlzIcaglsrdbLp0Er1Asmxr7pKEjLM3dCWmBrWE5DZunUhDQZRoMG/gPzbBziQzwUS4cHIhTe3cE3gS10bTbGAONmwIhvokcowyGIEtgsAP4Bdqhk5ptOqnNaWi80LDwiv0uBCmZm8pFHUQYik0ucHAUbNK3uC6LMG7tjqBcuatHZk0rVk/IhHy400/ML5WzjiuSKJgchP53D8alHdFkc0dI3tw5IE/vCEsJRF8IQzGanRk+szJPwIm40Y0yp2Cj7SoBDQIj6QhBPSGt0Hp85mGYVWRzwyEfI9kLUHMBgPm63ShF5PJQUfo5qu2RGlYBQo6UfP7xFnlsJaQ6sUAhQSBMfjxul/gQuxQisx0PLzN7Eu6nSuWzZ5nyRSQ6tz7fLg2dMZkAJkCoR2wKF+BE3IijTQCMI3D3IxBT9t0hw35sawBoP/wKAyC6Li4X1UgQLuh7M/fSj0b7giBUzH6gNy7n/6JRVj2HbBF5O6u8BKSjWOM0Is0/qm4eVHXxCeXy8pdnyCU1edIHLUkL1Ok+6jdxolFVUNM48x6ZcFht5XNoQy+2oZEKg8+ZRYA58DAB/bM5it+AjFvCaJj3eP1BjZIrhLukR7nuqf0y5y8HZem0PDlmvF/Ky3wyBmXvCoStJDoHkmJWx2XCv0Lc/wmKLmf/dIeEUCpnUVQRN8qkxIU4UdgKL3bEBe8licRwZDEFtvaQIZu9IEcGsQFfJppSNLsrAYDtg7GUytvxC80OSQtoFMGYD9ICAqLkYORVGWxemVv2YJforvW9cG09YmLmCfD/M0vcMmd8riyYXiiLjy2SEhBO2ES+pDhHbjqxSK5/sVOmYikw1R6tKaSBU0HAnQ6b2RHxA0gKUS2GawH4DJqxjs1BxCxWD05oTOaBDQInMIa8BqxDNzgfgQqqhqc0LmMKkTqQAfbdUT9tGAilMZY+hIC7YyKl0IYJIJjPaawGgNurBxPyp9Ze8b3ZLSvnFUrtp6dIaZFdKqPhmj05ILnJTuXG0ruRI+ZUDAOxYwo8tgG06VfLjTRYtHS4l4UzAiFUmZLxHshB2wfdm0+1U/6RyOGvBG6sEWlwByx0NcJKwqRBrEApKoVMhwDT84xECHewWS/zpuRhO8ujLHlrMC4bm0IqcXIEQgdTA2vvRb4RRUz9+62Dsnhml1y6eHwGZiFyNceqjzYf7xGRFGwKcVNGW90UORBMSBO4rGoLClsbLGlVaY+m7XPh+j3UP5Zlk8PFwEDnXbimnQhKTpxCC44x+JhRFZCZZR5phm5XgAL66+xGtU+Ag2Phy/9wzXTsBXCVAXo8Iaf8qF7aD0Ylj+oMxYI/gSbY/h5yEisArUNwpFpaXMQ1+3f6V+YLwSqSKlNmAKeZwE25O8KChjV2RqQJGeEcVJNxViVLAyhshPeibYKfMzdbJvxkevU4kCklKmsT8vIY1xF+k3OVKIqcPckvfQhcWPl18HPGkXnIbySIovJA1CaG9X/N45YLYdWZS8DyqjiBZSv+FUHbvJjCCIvMnui3QaUBd/XGEMoCAH6neeJMpeYmDr3A5WyMq8ASsKVLA24i+cIWAFBAlyGNtJJm2L0tLs2UzVYyFoInYEZINlHYdo4PI/XXPUEgnRQfzD/4ipIY9uqwUZH8K062gSHEMxs+f/OATyfW3mYkTWecWIE7dq+rzqpEZTcij73br+r+yjpyMNSBofDt51WoalH2cnx9e7/EQQFNUfY8GKUavWkSxM49plDhxpt0ZiEEWH9rDoqGGqKzG6UGAGXQqiuaQbtrMGB05odlK05jnWzGgiiH2xUhJFEyHQx4FQWH9/cGZTHK11RH1t1Ox2blWdU5sgkh5nhM4FSA7clBDzrShnzntQPy8uxScYN59LJlsOrfXzlNPj63V7Y2DUgX7AsN7jhUmRfUFMopIMKLErgKZ6FF+9oG5OFN/TIWARlzi+xGlnJvcjc07bQqn5w2vUDhRnisAO9oD8kfmyIyDblAhGqZblwc2PA1rERoK2l3TUclvUMreBEHC06G6A/1xABWAeh6/ry5W06ZUSRu2AVKp7rcJxchnH1jLewnmDS8gXcqhN6I5OTn61rk5k9OVobMBCKsK150UrmcO69UEcoJWcAg4bx2QtkgttQ//yQ2S1B9KkBml7YMQ6aiaocQ/V24pFwmACegppSNFar1KIlFYFiJHmx5ptxOGtUBq6TrxenSHzeaX3vYLF34hRjO2lwJDIhFZhmw2FEOg/UMqq+XHof9OWgBG1RIxiOnb24Pyq6uuAQgIXjGESqaDwm90ByWRG8ExtOvaoqOp6FlZzWXaauTvKhngNPSFpRPPbpbNkGFSxHd0CtlN9LJfYJuLJ1FkP6/nleFWiJxQ6yC+20HI/Jva1qRCwxbNKQNZw+xN2DqlvWNjXcsamV8pRmpVANu/EX3+Uk/BagaJ87B2tQRwKx9qwOBBY67cHb0GleeK59bXIkrhqBIN3k7q/E+4+xSIHH7m11yzj3bZN3bHbIbaS7X51B2aRJB0NW4Pyh1r7fJuT9tkO1NYamCNc3S3gx0wqWqR4HP8jMqZCJK4WzEjWbs2Xc6ZXt3UtUrsytWSv29KMeT1kRsJ0boxvLVs3DcYmk8ZHXCM3gvNFPYkk5jR/7RXY2Fr36iMSyXzsiTipIcO7eALk1FOLsVUtrRHkHSgeKSQsP+4Fgygd/jUbbqwf7eg2/3ypMopkZ6wjK/pgDLhMvHQpEVz9Y1y+dW7ZHfIRbIg28rTrtKdBjRuB1OL7QY1eDvXDgBQRsUF9RT+nuRUV77eIuUQvdJPOfPNIwzXDkwc8n/KPcveHvB9XWCw83LzddqNfiB0Is4lbmbhxABLZsWEAxXBVzvwQZmHGuSSRK5rYOAOy+dICdV224R2qxcCAlncyYHrhLAw0UVbkHgJ1vaoyrPYB+uN1aFdqMEjuMAcuoYt9oZyjZc7Oc0anU/6nyzKnPkjkurxEPvlJ4Qmi33PbdXulGr53EbLstMA02kjTSSVtJM2omyxQNR8fb2gziC+ktlIECg03gVAYKTwNE1O0Ly4KttuEPIUCh8VYzxyz2XT1Sbk70obHApwCSM0AYGTCjaiAlGFmLzn4aPjZ8GbIofO04MWXn2h2p/CAMbFh6p3eW+YFKmlXvlx5dVy5QJ+QoHx20+984B+a+NAzKlwFCBD5eK03BuSJ05Jo2klTSTdtWnrm65ua9uRSQRDT0FDm3HsRLez2gBkSFiY/N0uQ2l5g2wsJmIC8hOGJcn910xWU5FptcJ6fRC91iPJ414nGngo+RAMr1YDvF0kMSHKdQNugZR/8OsjjR53xnLcwNhDO6GKh1flSv3geGzphayC5qt+nv2Dsq317VJBRSYdcJs4tGJR2Uo/e2kkbSSZo7OZrTYp8KmXqy7Pb/GAYk81JnZQ/UhMgQaAiK5EMf9K6rljLnlMDrogh78S2B5PIw1/sirqPu3xbDB4ZYq6GwYzHPWI4HxvN8UHG85rQJb3CBga29CNjQNSi6AMLQlZrQOnIcxRktPUqoLDbkaBu8q/AVQVbIZhQWEMdwkvfq3e2QfwugAwvMhhlNZfhyocnsHzUT8qoamxrX2qTFMgMZ5nKbx5MS4hde3JM1Ype71LbCSDBeJcvoTF5TgIIoab6AyPBMEThxLz8EeAIY4YS7K6NyqwnEEacTRlR3Y8U1iTRSDGDKBTKSx2t8Tl604N8TjLW3IORjS4gi0WrewfxJE3z04JM7a5KePL5BvL5sgl5xUhtcQkF/imWP0djb1y42PN6sTIjxFwoBJYYxvXCnUcNyH5wZXeS33Lzp/tQSW5lCXQ33Z3zkkdevrs42csmegBdUIGW028zkaITKLGwA1+bDuv71iipxwjHrxQyFFVhFoOJKQ+taQvIQgqm5zrzRBfceDMocJXNNOIqWWCgAz2KGRawfRhWDGBTUBWTqvTBZOK5AiBFBslLwSKubZB4v/WZwR2oNcOx+wCY9zZxq4hA0QbAF4W1KRgxc23H36FodGp8+Q/uommXC7aNMj797mcud8E8fkkP+mRpwUIwG0C3Fc/PATY+XyU3BKDBqg0gk8cwIeurhNu/vl1romaUVIls+ojlxEcyZP/1Q5P88PjQsYcgckfiLC4wC340GsIhwfKt3F2PVbu+TbT+2VXdCkfESRI47FkEuGYRpuXySZiNyxM2feD+Xfcc9+v0DNz49htgJ3qPLoaIYP3JOKhX6Lt0A4iMvSwZPjFLd5Jjgfd69/Yq/cuqpBWhHkcDiJJyP450UkNxNR4GzWFCB+teOkINgAHaD8dnajjh+bK/On5KsyOu9nM3UAdYUfrd0j5/5qt2yB7SDx3J8c1hTOxJ00kJY08cO6jcYA4gUi+DpKQ3PzDTglulbD2Vu4EWU1HQiUHiVJDtbg8MSq9/rl7J/Uy2+eb5WOnqiK1BxpcQwZMwJNPhjWWE0mbKeRmfwdREb6wsYO+cy99fLd5w7IRCy/cqxFtTmbPQB9iStxNhPhp0iDerXG7jMChZEaoGa2YwNYS7y3dHClhYPHBs7eAjUWzjJACJM/eMB5Egog3Fv+8pp2uezebfLQC3tlC874hnFsrh++ux9JCxmSGazmGf0jhoAmzj/UIfZ3R+UPb3fKV+6vlwse2CNvQuVnlvG8sa2FZGymKdy0FHElzrED9StJg+PzM/2yLrKHZ922L52j5kdzXJ6E0S7wQEMrTnd04UxRYZFLrpqZpwzf8zuw6QkGgU2HZQKNIV1kPizhFfNKFLzntvbJ60jJ4X5kNphMt0jiR0iObuGjPC7vcCPz0oE6Of7BL0wwzaGuMHjphTVvQU2Ovr2iwKWixCNpgMPELgDpRikL+qbqhdNRcyB9PLk4knDyE6v2n/HChMOE2lr7vUD+5iszLk/gOry2Uw03ide6ElimQxRRDaPBoLskI2jBGZ3xHm4dsSkmoAdPp2DFqDVOibMNHwumMLe34OaQnhgtyXjwlzvvmn8n+2bjzN+Ha8NhHq4f7mfMk1Vz0+t4aSr/apin7JemgOGh80UOIBLE9iEmUv2POA6JDV6asjIvTYn2Gysc/tXf89LUh8UL/Yna/+Vrc3hjzoN4lG+i8rU5E6/N9f39r80Nr2Mo7h/hA9SDB3hJcU8t39OTJ/Hy4jZD088TM3kt3hadSn0340HwyVS1SGjJiCDqCPCHPoJVx3+cagPXdd1leLCBwB/xUCM2dO9PRQfW7br3jO1qEF+cxOu7QwF88K8PqwHZEO3FjcjKeXXW0jxLUG9dCQ093fAhVeXR1I/y1VnBq7P6/4dXZ202MNpSS/WzJecmGu4+qWmnv+8hIx69GCeTF5mJ4HdTidAGSDCE0+eG4c134SyiwYosdBgqTKdnN17zHp+xD/uqyi3GphKRDan4wPc0M7nIlYgtG+Pre4hzcU412sbBMRkOyKP+ziBx1CMO29F5fX45l8nhX5+X9Ovz2BOBYhcRAZjXUV6ft/D6vOD1eeOf+vr8/wAFwcVWZRcwYQAAAABJRU5ErkJggg=='\nconst TOKEN_USDT =\n 'data:image/png;base64,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'\n\n/** Chain icon by chain id; testnets reuse their mainnet icon */\nexport const CHAIN_ICONS: Record<number, string> = {\n [mainnet.id]: CHAIN_ETHEREUM,\n [sepolia.id]: CHAIN_ETHEREUM,\n [arbitrum.id]: CHAIN_ARBITRUM,\n [arbitrumSepolia.id]: CHAIN_ARBITRUM,\n [base.id]: CHAIN_BASE,\n [baseSepolia.id]: CHAIN_BASE,\n [blast.id]: CHAIN_BLAST,\n [bsc.id]: CHAIN_BSC,\n [hyperEvm.id]: CHAIN_HYPERLIQUID,\n [ink.id]: CHAIN_INK,\n [linea.id]: CHAIN_LINEA,\n [mode.id]: CHAIN_MODE,\n [monad.id]: CHAIN_MONAD,\n [optimism.id]: CHAIN_OPTIMISM,\n [optimismSepolia.id]: CHAIN_OPTIMISM,\n [polygon.id]: CHAIN_POLYGON,\n [scroll.id]: CHAIN_SCROLL,\n [soneium.id]: CHAIN_SONEIUM,\n [tempo.id]: CHAIN_TEMPO,\n [unichain.id]: CHAIN_UNICHAIN,\n [worldchain.id]: CHAIN_WORLDCHAIN,\n [zora.id]: CHAIN_ZORA,\n}\n\n/** Token icon by display symbol; wrapped variants reuse the base icon */\nexport const TOKEN_ICONS: Record<string, string> = {\n USDC: TOKEN_USDC,\n USDT: TOKEN_USDT,\n DAI: TOKEN_DAI,\n EURC: TOKEN_EURC,\n ETH: TOKEN_ETH,\n WETH: TOKEN_ETH,\n WBTC: TOKEN_WBTC,\n POL: CHAIN_POLYGON,\n WPOL: CHAIN_POLYGON,\n BNB: CHAIN_BSC,\n WBNB: CHAIN_BSC,\n}\n\nconst PROVIDER_ACROSS =\n 'data:image/png;base64,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'\nconst PROVIDER_RELAY =\n 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAABGUUKwAAAC52lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOklwdGM0eG1wRXh0PSJodHRwOi8vaXB0Yy5vcmcvc3RkL0lwdGM0eG1wRXh0LzIwMDgtMDItMjkvIj4KICAgICAgICAgPHBob3Rvc2hvcDpDcmVkaXQ+TWFkZSB3aXRoIEdvb2dsZSBBSTwvcGhvdG9zaG9wOkNyZWRpdD4KICAgICAgICAgPElwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWE8L0lwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VUeXBlPgogICAgICAgICA8SXB0YzR4bXBFeHQ6RGlnaXRhbFNvdXJjZUZpbGVUeXBlPmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWE8L0lwdGM0eG1wRXh0OkRpZ2l0YWxTb3VyY2VGaWxlVHlwZT4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cp6mSPIAABIISURBVGgFtVp7jF3HWZ+Z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'\n\n/** Provider brand icon by `FeeBreakdown.provider` value (\"Across\" / \"Relay\"). */\nexport const PROVIDER_ICONS: Record<string, string> = {\n Across: PROVIDER_ACROSS,\n Relay: PROVIDER_RELAY,\n}\n","import { formatUnits } from 'viem'\n\n/**\n * Format a raw token amount (decimal string, hex string or bigint) into a\n * human readable unit string. Falls back to the raw value if parsing fails.\n */\nexport function formatTokenAmount(\n value: string | bigint,\n decimals: number,\n): string {\n try {\n const amount = typeof value === 'bigint' ? value : BigInt(value)\n return formatUnits(amount, decimals)\n } catch {\n return String(value)\n }\n}\n\n/** Rounding direction for display amounts. `'up'` / `'down'` are ceil / floor\n * — use them for values where over- or under-stating is unsafe (fees, min\n * deposit). `'nearest'` is `Math.round` — use for values the user reads as a\n * final quantity (\"you received X\") so 249.9996… reads as 250.00. */\nexport type RoundDirection = 'up' | 'down' | 'nearest'\n\nfunction displayFractionDigits(value: number): number {\n if (value >= 1000) return 0\n if (value >= 1) return 2\n // Two significant digits for sub-unit amounts\n return Math.min(8, 1 - Math.floor(Math.log10(value)))\n}\n\n/**\n * Format a raw token amount for display: thousands grouping and a\n * magnitude-aware precision (whole numbers above 1000, two decimals above 1,\n * two significant digits below). Rounds in the given direction so limits and\n * fees are never overstated/understated. Falls back to the raw value if\n * parsing fails.\n */\nexport function formatDisplayAmount(\n value: string | bigint,\n decimals: number,\n round: RoundDirection,\n): string {\n let amount: number\n try {\n amount = Number(\n formatUnits(typeof value === 'bigint' ? value : BigInt(value), decimals),\n )\n } catch {\n return String(value)\n }\n if (amount === 0) return '0'\n\n const digits = displayFractionDigits(amount)\n const factor = 10 ** digits\n const roundFn =\n round === 'up' ? Math.ceil : round === 'down' ? Math.floor : Math.round\n const rounded = roundFn(amount * factor) / factor\n return rounded.toLocaleString('en-US', {\n maximumFractionDigits: digits,\n })\n}\n\nexport function truncateAddress(address: string): string {\n if (address.length <= 12) return address\n return `${address.slice(0, 6)}…${address.slice(-4)}`\n}\n\nexport function formatSlippage(basisPoints: number): string {\n return `${(basisPoints / 100).toFixed(2).replace(/\\.?0+$/, '')}%`\n}\n\nexport function formatDuration(seconds: number): string {\n if (seconds < 60) return `~${Math.max(1, Math.round(seconds))} sec`\n return `~${Math.round(seconds / 60)} min`\n}\n\n/** Symbols treated as ~$1, so a USD equivalent can be shown for their amounts */\nexport const STABLE_SYMBOLS = new Set([\n 'USDC',\n 'USDT',\n 'DAI',\n 'USDBC',\n 'USDC.E',\n])\n\n/** ISO timestamp → compact \"N unit ago\" (\"just now\", \"2 m ago\", \"3 h ago\",\n * \"5 d ago\", \"2 mo ago\", \"1 y ago\"). Returns `null` on invalid input. */\nexport function formatRelativeTime(\n iso: string,\n now: number = Date.now(),\n): string | null {\n const then = Date.parse(iso)\n if (Number.isNaN(then)) return null\n const seconds = Math.max(0, Math.round((now - then) / 1000))\n if (seconds < 30) return 'just now'\n if (seconds < 60) return `${seconds} s ago`\n const minutes = Math.round(seconds / 60)\n if (minutes < 60) return `${minutes} m ago`\n const hours = Math.round(minutes / 60)\n if (hours < 24) return `${hours} h ago`\n const days = Math.round(hours / 24)\n if (days < 30) return `${days} d ago`\n const months = Math.round(days / 30)\n if (months < 12) return `${months} mo ago`\n const years = Math.round(months / 12)\n return `${years} y ago`\n}\n","import { formatUnits } from 'viem'\nimport { z } from 'zod/mini'\nimport type { EstimatedFeeData } from '../types'\nimport { formatDisplayAmount, STABLE_SYMBOLS } from './format'\n\n/**\n * Standardised fee breakdown shared across routing providers. Each provider\n * (Across, Relay, …) exposes fees in its own shape; the parsers below map\n * them onto this single model so the fees view can render any of them\n * identically.\n *\n * A leg is either a `rate` (proportional to the deposit, e.g. capital / LP)\n * or `flat` (a fixed cost, e.g. destination gas). Because the deposit amount\n * is not known up front, each leg is shown only in its amount-invariant\n * form: a percentage for rates, a fixed USD value for flat costs.\n */\nexport type FeeKind = 'rate' | 'flat'\n\nexport type FeeLine = {\n key: string\n label: string\n kind: FeeKind\n /** Right-aligned accent: gas pump for gas legs, $ disc otherwise */\n accent: 'gas' | 'usd'\n /** Proportional rate as a percent (e.g. 0.01 for 0.01%); rate legs only */\n pct: number | null\n /** USD value at the quoted amount; the display value for flat legs */\n usd: number | null\n /** Raw fallback text (e.g. a token amount) when neither pct nor usd applies */\n text?: string\n /** True when the leg is waived (shown as \"Sponsored\") */\n sponsored?: boolean\n}\n\nexport type FeeBreakdown = {\n /** Routing provider, or null when no itemised provider data is available */\n provider: string | null\n lines: FeeLine[]\n /** Combined proportional rate as a percent, e.g. 0.013 for \"0.013%\" */\n ratePct: number | null\n /** Combined flat (fixed) cost in USD */\n flatUsd: number | null\n /** Full cost in USD at the quoted amount — used to compare routes */\n quotedTotalUsd: number | null\n /** Headline fallback when USD isn't derivable (e.g. \"0.00002 ETH\") */\n totalText: string | null\n /** Estimated fill time in seconds, when the provider reports it */\n fillTimeSec: number | null\n}\n\nfunction sum(values: (number | null)[]): number | null {\n return values.reduce<number | null>(\n (total, v) => (v === null ? total : (total ?? 0) + v),\n null,\n )\n}\n\n// ---------------------------------------------------------------------------\n// Across — GET https://app.across.to/api/suggested-fees\n// Fees are nested { pct, total } objects. `pct` is an 18-decimal fraction\n// (1e18 = 100%); `total` is in input-token units. Capital and LP fees are\n// true rates; the relayer gas fee is a fixed destination-gas cost (its pct\n// only looks like a rate because it is gas/amount). totalRelayFee = sum of\n// the three legs.\n//\n// Schemas validate the response at the fetch boundary — the API is external,\n// so a shape change (added required field, renamed leg, changed type) must\n// surface as a failed parse, not silently corrupted numbers. Unknown keys\n// are stripped (Zod default); we only assert what we actually consume.\n// ---------------------------------------------------------------------------\n\nconst AcrossLegSchema = z.object({\n pct: z.string(),\n total: z.string(),\n})\n\nexport const AcrossSuggestedFeesSchema = z.object({\n totalRelayFee: AcrossLegSchema,\n relayerCapitalFee: AcrossLegSchema,\n relayerGasFee: AcrossLegSchema,\n lpFee: AcrossLegSchema,\n estimatedFillTimeSec: z.optional(z.number()),\n})\n\ntype AcrossLeg = z.infer<typeof AcrossLegSchema>\nexport type AcrossSuggestedFees = z.infer<typeof AcrossSuggestedFeesSchema>\n\nconst E18 = 10n ** 18n\n\n/** 18-decimal Across fraction → percent (e.g. \"150298578165425\" → 0.0150) */\nfunction acrossPct(raw: string): number | null {\n try {\n // percent = raw/1e18 * 100, kept to 4-decimal percent precision via\n // BigInt before Number conversion (raw can exceed 2^53).\n return Number((BigInt(raw) * 1_000_000n) / E18) / 10_000\n } catch {\n return null\n }\n}\n\n/** Across totals are in input-token units; USD only when the token is ~$1 */\nfunction tokenUsd(\n total: string,\n decimals: number,\n symbol: string,\n): number | null {\n if (!STABLE_SYMBOLS.has(symbol.toUpperCase())) return null\n try {\n return Number(formatUnits(BigInt(total), decimals))\n } catch {\n return null\n }\n}\n\nexport function parseAcrossFees(\n res: AcrossSuggestedFees,\n symbol: string,\n decimals: number,\n): FeeBreakdown {\n const leg = (\n key: string,\n label: string,\n kind: FeeKind,\n accent: FeeLine['accent'],\n data: AcrossLeg,\n ): FeeLine => ({\n key,\n label,\n kind,\n accent,\n pct: acrossPct(data.pct),\n usd: tokenUsd(data.total, decimals, symbol),\n })\n\n const lines: FeeLine[] = [\n leg('capital', 'Capital Fee', 'rate', 'usd', res.relayerCapitalFee),\n leg('destGas', 'Destination Gas', 'flat', 'gas', res.relayerGasFee),\n leg('lp', 'LP Fee', 'rate', 'usd', res.lpFee),\n ]\n\n return {\n provider: 'Across',\n lines,\n ratePct: sum(lines.filter((l) => l.kind === 'rate').map((l) => l.pct)),\n flatUsd: sum(lines.filter((l) => l.kind === 'flat').map((l) => l.usd)),\n quotedTotalUsd: tokenUsd(res.totalRelayFee.total, decimals, symbol),\n totalText: null,\n fillTimeSec:\n typeof res.estimatedFillTimeSec === 'number'\n ? res.estimatedFillTimeSec\n : null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Relay — POST https://api.relay.link/quote\n// Each fee carries `amountUsd` only (no rate), so every leg is treated as a\n// fixed cost. `relayer` is the full relayer fee (relayerGas + relayerService);\n// `gas` is the user's origin-chain gas.\n// ---------------------------------------------------------------------------\n\nconst RelayFeeSchema = z.object({\n amountUsd: z.optional(z.string()),\n})\n\nexport const RelayQuoteSchema = z.object({\n fees: z.optional(\n z.object({\n gas: z.optional(RelayFeeSchema),\n relayer: z.optional(RelayFeeSchema),\n relayerGas: z.optional(RelayFeeSchema),\n relayerService: z.optional(RelayFeeSchema),\n app: z.optional(RelayFeeSchema),\n }),\n ),\n details: z.optional(\n z.object({\n timeEstimate: z.optional(z.number()),\n }),\n ),\n timeEstimate: z.optional(z.number()),\n})\n\ntype RelayFee = z.infer<typeof RelayFeeSchema>\nexport type RelayQuote = z.infer<typeof RelayQuoteSchema>\n\nfunction usdOf(fee?: RelayFee): number | null {\n if (!fee?.amountUsd) return null\n const value = Number(fee.amountUsd)\n return Number.isFinite(value) ? value : null\n}\n\nexport function parseRelayFees(res: RelayQuote): FeeBreakdown {\n const fees = res.fees ?? {}\n const lines: FeeLine[] = []\n const push = (\n key: string,\n label: string,\n accent: FeeLine['accent'],\n fee?: RelayFee,\n ) => {\n const usd = usdOf(fee)\n if (usd === null) return\n // Drop zero-value optional legs (e.g. app fee)\n if (usd === 0 && (key === 'app' || key === 'originGas')) return\n // Relay exposes USD only, so every leg is shown as a fixed cost\n lines.push({ key, label, kind: 'flat', accent, pct: null, usd })\n }\n\n push('service', 'Service Fee', 'usd', fees.relayerService)\n push('destGas', 'Destination Gas', 'gas', fees.relayerGas)\n push('originGas', 'Origin Gas', 'gas', fees.gas)\n push('app', 'App Fee', 'usd', fees.app)\n\n const totalUsd = usdOf(fees.relayer)\n return {\n provider: 'Relay',\n lines,\n ratePct: null,\n flatUsd: sum(lines.map((l) => l.usd)),\n quotedTotalUsd: totalUsd,\n totalText: null,\n fillTimeSec: res.details?.timeEstimate ?? res.timeEstimate ?? null,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Combine SRA fee + provider legs into the final breakdown\n// ---------------------------------------------------------------------------\n\n/**\n * Present the SRA fee as the actual all-in charge, with the provider's\n * bridge legs as a breakdown *of* it (not added on top — the SRA server fee\n * already covers bridging + execution). The execution portion is derived as\n * `SRA fee − bridge cost` so the legs sum back to the SRA fee. Without\n * provider data, the whole SRA fee is shown as a single execution line.\n */\nexport function buildFeeBreakdown(\n feeData: EstimatedFeeData,\n symbol: string,\n provider: FeeBreakdown | null = null,\n): FeeBreakdown {\n // The SRA fee is the all-in amount ZeroDev charges (bridging + execution)\n const sraUsd = feeData.isSponsored\n ? 0\n : tokenUsd(feeData.fee, feeData.decimal, symbol)\n const bridgeUsd = provider?.quotedTotalUsd ?? null\n // Token-unit fallback for non-stablecoins where USD isn't derivable\n const feeToken = `${formatDisplayAmount(feeData.fee, feeData.decimal, 'up')} ${symbol}`\n\n // Execution = the part of the SRA fee not explained by the bridge legs\n const executionUsd = feeData.isSponsored\n ? 0\n : sraUsd === null\n ? null\n : bridgeUsd === null\n ? sraUsd\n : Math.max(0, sraUsd - bridgeUsd)\n\n const showTokenFallback = !feeData.isSponsored && sraUsd === null\n const executionLine: FeeLine = {\n key: 'execution',\n label: 'Execution Fee',\n kind: 'flat',\n accent: 'usd',\n pct: null,\n usd: executionUsd,\n // Show the SRA fee in token units when we can't price it in USD\n ...(showTokenFallback && { text: feeToken }),\n sponsored: feeData.isSponsored,\n }\n\n const lines = [executionLine, ...(provider?.lines ?? [])]\n\n return {\n provider: provider?.provider ?? null,\n lines,\n ratePct: sum(lines.filter((l) => l.kind === 'rate').map((l) => l.pct)),\n flatUsd: sum(lines.filter((l) => l.kind === 'flat').map((l) => l.usd)),\n // The headline charge is the SRA fee itself, never the sum on top of it\n quotedTotalUsd: feeData.isSponsored ? 0 : sraUsd,\n // Headline fallback for non-stable tokens (e.g. \"0.00002 ETH\")\n totalText: !feeData.isSponsored && sraUsd === null ? feeToken : null,\n fillTimeSec: provider?.fillTimeSec ?? null,\n }\n}\n\n/** Format a percent number for display, trimming to a sensible precision */\nexport function formatFeePct(pct: number): string {\n const digits = pct >= 1 ? 2 : pct >= 0.1 ? 2 : 3\n return `${pct.toFixed(digits)}%`\n}\n\n/** Format a USD number for display */\nexport function formatFeeUsd(usd: number): string {\n const digits = usd > 0 && usd < 0.01 ? 4 : 2\n return `$${usd.toLocaleString('en-US', {\n minimumFractionDigits: 2,\n maximumFractionDigits: digits,\n })}`\n}\n","/**\n * Plain-language explanations for each fee/route line, surfaced as tooltips\n * on the info icons in the fee section so users understand what they're\n * charged.\n */\nexport const FEE_INFO = {\n minDeposit: 'Smallest amount this route can process after fees.',\n maxSlippage: 'Maximum price movement allowed during the swap.',\n estimatedFee: 'Estimated swap, bridge, and network costs.',\n readyIn: 'Estimated arrival after the deposit is detected.',\n // Breakdown legs\n provider: 'Bridge provider selected for this route.',\n execution: 'Cost to execute and deliver funds on the destination chain.',\n capital: 'Relayer cost for fronting capital while bridging.',\n destGas: 'Gas to complete delivery on the destination chain.',\n lp: 'Bridge liquidity-provider fee.',\n service: 'Solver fee for filling the route.',\n originGas: 'Gas to submit from the source chain.',\n app: 'Optional application fee.',\n // Transaction progress steps (transaction-details view)\n detected: 'Deposit detected on the source chain.',\n routing: 'Bridge and swap are in progress.',\n completed: 'Funds arrived in the delivery account.',\n failed: 'Deposit could not be completed.',\n} as const\n","import { cn, Icon, Text, Tooltip } from '@zerodev/react-ui'\nimport type { ReactNode } from 'react'\nimport { PROVIDER_ICONS } from '../../iconAssets'\nimport type { FeeBreakdown, FeeLine } from '../../utils/providerFees'\nimport { formatFeePct, formatFeeUsd } from '../../utils/providerFees'\nimport { FEE_INFO } from './feeInfo'\n\n/** Home pages for supported providers, so the name links out */\nconst PROVIDER_URLS: Record<string, string> = {\n Across: 'https://across.to',\n Relay: 'https://relay.link',\n}\n\nexport type LiveValueProps = {\n /** While true, the value is being re-quoted: show a spinner */\n loading: boolean\n /** Changes with the value so the flash-in animation re-triggers */\n flashKey: string | number\n children: ReactNode\n}\n\n/**\n * A value that swaps to a spinner while its route is re-quoting, then flashes\n * the fresh value in. Used so a route change visibly recalculates the min\n * deposit / estimated fee rather than silently snapping to new numbers.\n */\nexport function LiveValue({ loading, flashKey, children }: LiveValueProps) {\n if (loading) {\n return (\n <span\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:text-orange\"\n role=\"img\"\n aria-label=\"Updating estimate\"\n >\n <Icon\n name=\"loading\"\n className=\"zd:w-3.5 zd:h-3.5 zd:animate-spin zd:text-orange\"\n aria-hidden\n />\n </span>\n )\n }\n return (\n <span\n key={flashKey}\n className=\"zd:inline-flex zd:items-center zd:gap-1.5 zd:animate-fee-flash\"\n >\n {children}\n </span>\n )\n}\n\n/** Combined fee value: proportional rate (emphasised) + fixed USD cost */\nexport function FeeSummary({ breakdown }: { breakdown: FeeBreakdown }) {\n // When the SRA fee can't be priced in USD (non-stable token), show it as a\n // token amount — the partial USD bridge legs must not headline as the total.\n if (breakdown.totalText) {\n return (\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">\n {breakdown.totalText}\n </Text>\n )\n }\n const pct =\n breakdown.ratePct !== null && breakdown.ratePct > 0\n ? formatFeePct(breakdown.ratePct)\n : null\n const usd =\n breakdown.flatUsd !== null ? formatFeeUsd(breakdown.flatUsd) : null\n if (!pct && !usd) {\n return <Text className=\"zd:whitespace-nowrap\">—</Text>\n }\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1 zd:leading-none\">\n {pct && (\n <b className=\"zd:text-body2 zd:font-bold zd:text-greyScale zd:leading-none\">\n {pct}\n </b>\n )}\n {pct && usd && (\n <span className=\"zd:text-body2 zd:text-greyScale/50 zd:leading-none\">\n +\n </span>\n )}\n {usd && (\n <span className=\"zd:text-body2 zd:font-medium zd:text-greyScale/70 zd:leading-none\">\n {usd}\n </span>\n )}\n </span>\n )\n}\n\n/** Provider name + brand icon, linked to the provider's site when known */\nexport function ProviderValue({ provider }: { provider: string }) {\n const url = PROVIDER_URLS[provider]\n const iconUrl = PROVIDER_ICONS[provider]\n const inner = (\n <>\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">{provider}</Text>\n {iconUrl && (\n <img\n src={iconUrl}\n alt=\"\"\n aria-hidden\n className=\"zd:size-3.5 zd:shrink-0 zd:rounded-[4px] zd:object-cover\"\n />\n )}\n </>\n )\n if (!url) {\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1\">{inner}</span>\n )\n }\n return (\n <a\n className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-greyScale zd:hover:underline\"\n href={url}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {inner}\n </a>\n )\n}\n\nfunction InfoMark({ info }: { info: string }) {\n // Real DOM element so Radix's `Tooltip` (via `asChild`) can attach hover /\n // focus handlers and wire `aria-describedby` to its content. Focusable so\n // keyboard users can trigger the tooltip.\n return (\n <Tooltip content={info}>\n {/* button (not span+tabIndex): natively focusable, so keyboard users\n can trigger the tooltip; Radix wires aria-describedby to the\n tooltip copy on hover / focus. `type=\"button\"` keeps it inert\n inside forms. */}\n <button\n type=\"button\"\n aria-label=\"More info\"\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-help zd:outline-none zd:bg-transparent\"\n >\n <Icon\n name=\"info\"\n className=\"zd:w-3 zd:h-3 zd:text-greyScale/50\"\n aria-hidden\n />\n </button>\n </Tooltip>\n )\n}\n\nfunction LineValue({ line }: { line: FeeLine }) {\n if (line.sponsored) {\n return (\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">Sponsored</Text>\n )\n }\n // Rates are amount-invariant → show percent; flat costs → show USD; fall\n // back to a raw token amount when neither is available.\n const value =\n line.kind === 'rate' && line.pct !== null\n ? formatFeePct(line.pct)\n : line.usd !== null\n ? formatFeeUsd(line.usd)\n : line.pct !== null\n ? formatFeePct(line.pct)\n : (line.text ?? '—')\n return <Text className=\"zd:whitespace-nowrap zd:font-medium\">{value}</Text>\n}\n\nfunction BreakdownRow({\n label,\n info,\n children,\n className,\n}: {\n label: string\n info?: string\n children: ReactNode\n className?: string\n}) {\n return (\n <div\n className={cn(\n 'zd:flex zd:w-full zd:items-center zd:gap-1 zd:py-1',\n className,\n )}\n >\n <Text className=\"zd:whitespace-nowrap zd:text-greyScale/60\">{label}</Text>\n {info && <InfoMark info={info} />}\n <div className=\"zd:min-w-0 zd:flex-1\" />\n {children}\n </div>\n )\n}\n\n/** Itemised fee rows: provider + each fee leg */\nexport function FeeBreakdownRows({ breakdown }: { breakdown: FeeBreakdown }) {\n return (\n <div className=\"zd:flex zd:w-full zd:flex-col zd:pl-2\">\n {breakdown.provider && (\n <BreakdownRow label=\"Provider\" info={FEE_INFO.provider}>\n <ProviderValue provider={breakdown.provider} />\n </BreakdownRow>\n )}\n {breakdown.lines.map((line) => (\n <BreakdownRow\n key={line.key}\n label={line.label}\n info={FEE_INFO[line.key as keyof typeof FEE_INFO]}\n >\n <LineValue line={line} />\n </BreakdownRow>\n ))}\n </div>\n )\n}\n","import type { DepositedToken } from '@zerodev/smart-routing-address'\nimport type {\n DepositStage,\n EstimatedFee,\n SmartRoutingAddressConfig,\n} from '../types'\nimport { resolveDestChain, resolveSourceTokens } from './config'\nimport { findFeeDataByToken } from './fees'\nimport { formatTokenAmount, truncateAddress } from './format'\n\nexport const DEPOSIT_STAGE_LABELS: Record<DepositStage, string> = {\n pending: 'Deposit detected',\n bridging: 'Bridging',\n completed: 'Completed',\n failed: 'Failed',\n}\n\n/**\n * Newer SRA servers split a deposit into legs that each carry their own\n * bridge/execution status; the published SDK types don't include the\n * field yet, so it is modeled here as an optional extension.\n */\nexport type DepositSplitLeg = Pick<DepositedToken, 'bridge' | 'execution'> & {\n splitIndex: number\n amount: string\n}\n\nexport type DepositWithSplits = DepositedToken & {\n splits?: DepositSplitLeg[]\n}\n\nexport function getDepositKey(deposit: DepositedToken): string {\n return deposit.deposit.transactionHash\n}\n\nexport function getDepositStage(deposit: DepositWithSplits): DepositStage {\n if (deposit.error) return 'failed'\n // Split deposits carry bridge/execution on each leg; the top-level\n // fields stay null.\n if (deposit.splits && deposit.splits.length > 0) {\n if (deposit.splits.every((leg) => leg.execution !== null)) {\n return 'completed'\n }\n if (\n deposit.splits.some(\n (leg) => leg.bridge !== null || leg.execution !== null,\n )\n ) {\n return 'bridging'\n }\n return 'pending'\n }\n if (deposit.execution) return 'completed'\n if (deposit.bridge) return 'bridging'\n return 'pending'\n}\n\nexport function getNewDeposits(\n deposits: DepositedToken[],\n baseline: ReadonlySet<string>,\n): DepositedToken[] {\n return deposits.filter((deposit) => !baseline.has(getDepositKey(deposit)))\n}\n\nexport type DepositSummary = {\n key: string\n stage: DepositStage\n stageLabel: string\n chainName: string\n symbol: string\n amount: string\n transactionHash: string\n}\n\nfunction getChainName(\n chainId: number,\n config: SmartRoutingAddressConfig,\n): string {\n const destChain = resolveDestChain(config)\n if (destChain.id === chainId) return destChain.name\n const source = resolveSourceTokens(config).find(\n (token) => token.chain.id === chainId,\n )\n return source?.chain.name ?? `Chain ${chainId}`\n}\n\nexport function summarizeDeposit(\n deposit: DepositedToken,\n estimatedFees: EstimatedFee[],\n config: SmartRoutingAddressConfig,\n): DepositSummary {\n const { chainId, token, amount, transactionHash } = deposit.deposit\n const feeData = findFeeDataByToken(estimatedFees, chainId, token)\n const stage = getDepositStage(deposit)\n return {\n key: getDepositKey(deposit),\n stage,\n stageLabel: DEPOSIT_STAGE_LABELS[stage],\n chainName: getChainName(chainId, config),\n symbol: feeData?.name ?? truncateAddress(token),\n amount: feeData\n ? formatTokenAmount(amount, feeData.decimal)\n : String(amount),\n transactionHash,\n }\n}\n","import { cn, Icon, Text } from '@zerodev/react-ui'\n\nexport type TxnStatus =\n | 'Routing'\n | 'Detected'\n | 'Received'\n | 'Delivered'\n | 'Failed'\n\nexport interface TxnItemProps {\n /** Pre-formatted deposited amount, e.g. `\"$248.00 USD\"`. */\n amount: string\n /**\n * Pre-formatted delivered amount. Presence switches the row to the\n * detailed (past-deposits) layout — `amount → destAmount` headline plus\n * the chain-route line (Figma `20002:37771`); without it the row is the\n * compact active-deposits variant (`20002:36061`).\n */\n destAmount?: string\n /** Short address/hash display, e.g. `\"0x4d2a…ba99\"`. */\n address: string\n /** Optional block-explorer URL. Address row becomes a link when supplied. */\n href?: string\n /** Pre-formatted relative timestamp, e.g. `\"2 m ago\"`. */\n timestamp: string\n status: TxnStatus\n /** Main image in the 44px mark. */\n sourceTokenIconUrl?: string\n /** Mark badge on the compact variant; chain-route icon on the detailed. */\n sourceChainIconUrl?: string\n /** Mark badge on the detailed variant. */\n destTokenIconUrl?: string\n /** Chain-route icon on the detailed variant. */\n destChainIconUrl?: string\n /** Chain-route labels — detailed variant only. */\n sourceChainName?: string\n destChainName?: string\n className?: string\n}\n\nconst STATUS_COLOR: Record<TxnStatus, string> = {\n Routing: 'zd:text-solarOrange',\n Detected: 'zd:text-greyScale/50',\n // In-flight arrival reads in plain ink (Figma 20002:36061); the green\n // celebration is reserved for the terminal Delivered state.\n Received: 'zd:text-greyScale',\n Delivered: 'zd:text-positive',\n Failed: 'zd:text-negative',\n}\n\nexport function TxnItem({\n amount,\n destAmount,\n address,\n href,\n timestamp,\n status,\n sourceTokenIconUrl,\n sourceChainIconUrl,\n destTokenIconUrl,\n destChainIconUrl,\n sourceChainName,\n destChainName,\n className,\n}: TxnItemProps) {\n const detailed = destAmount !== undefined\n // Compact rows badge the mark with the chain; detailed rows badge it with\n // the destination token (the route line already names both chains).\n const badgeIconUrl = detailed ? destTokenIconUrl : sourceChainIconUrl\n\n return (\n <div\n className={cn(\n 'zd:relative zd:flex zd:w-full zd:items-start zd:gap-2 zd:rounded-2xl zd:p-2',\n className,\n )}\n >\n <TokenMark\n {...(sourceTokenIconUrl && { tokenIconUrl: sourceTokenIconUrl })}\n {...(badgeIconUrl && { badgeIconUrl })}\n />\n\n {/* gap-1, not the Figma node's 8px: the design measures between\n leading-trimmed text boxes (text-box-trim), while our Text renders\n 130% line-height — ~2px of leading above and below each line — so\n 4px + leading visually lands on the design's 8px. */}\n <div className=\"zd:flex zd:min-w-0 zd:flex-1 zd:flex-col zd:gap-1 zd:py-2\">\n <div className=\"zd:flex zd:min-w-0 zd:items-center zd:gap-1\">\n <Text className=\"zd:truncate zd:text-body2\">{amount}</Text>\n {detailed && (\n <>\n <RouteArrow />\n <Text className=\"zd:truncate zd:text-body2\">{destAmount}</Text>\n </>\n )}\n </div>\n\n {detailed && (sourceChainName || destChainName) && (\n <div className=\"zd:flex zd:min-w-0 zd:items-center zd:gap-1\">\n {sourceChainName && (\n <ChainTag\n name={sourceChainName}\n {...(sourceChainIconUrl && { iconUrl: sourceChainIconUrl })}\n />\n )}\n {sourceChainName && destChainName && <RouteArrow />}\n {destChainName && (\n <ChainTag\n name={destChainName}\n {...(destChainIconUrl && { iconUrl: destChainIconUrl })}\n />\n )}\n </div>\n )}\n\n <AddressLine address={address} {...(href && { href })} />\n </div>\n\n <div className=\"zd:flex zd:shrink-0 zd:flex-col zd:items-end zd:justify-between zd:self-stretch zd:py-2\">\n <span\n className={cn(\n 'zd:flex zd:items-center zd:gap-2',\n STATUS_COLOR[status],\n )}\n >\n {/* In-flight marker (Figma 20002:36058): rotating rays before the\n Routing label, inheriting its orange. */}\n {status === 'Routing' && (\n <Icon\n name=\"lineLoading\"\n className=\"zd:size-2.5 zd:shrink-0 zd:animate-spin\"\n aria-hidden\n />\n )}\n <Text className={cn('zd:text-body2', STATUS_COLOR[status])}>\n {status}\n </Text>\n </span>\n <Text className=\"zd:text-body3 zd:text-greyScale/50\">{timestamp}</Text>\n </div>\n </div>\n )\n}\n\n/** 44px mark (Figma \"CryptoPresets\"): centred 34px token image with a 12px\n * badge straddling the bottom-right corner. */\nfunction TokenMark({\n tokenIconUrl,\n badgeIconUrl,\n}: {\n tokenIconUrl?: string\n badgeIconUrl?: string\n}) {\n return (\n <div className=\"zd:relative zd:size-11 zd:shrink-0 zd:rounded-xl zd:backdrop-blur-[15px]\">\n <div className=\"zd:absolute zd:top-1/2 zd:left-1/2 zd:size-8.5 zd:-translate-x-1/2 zd:-translate-y-1/2 zd:overflow-hidden zd:rounded-full zd:border zd:border-offWhite zd:bg-greyScale/10 zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]\">\n {tokenIconUrl && (\n <img\n src={tokenIconUrl}\n alt=\"\"\n className=\"zd:size-full zd:object-cover\"\n />\n )}\n </div>\n {badgeIconUrl && (\n <div className=\"zd:absolute zd:right-1 zd:bottom-1 zd:size-3 zd:overflow-hidden zd:rounded-full zd:border zd:border-offWhite/40 zd:bg-white\">\n <img\n src={badgeIconUrl}\n alt=\"\"\n className=\"zd:size-full zd:object-contain\"\n />\n </div>\n )}\n </div>\n )\n}\n\n/** 10px `›` separating the two sides of an amount / chain route. */\nfunction RouteArrow() {\n return (\n <Icon\n name=\"chevronRight\"\n className=\"zd:size-2.5 zd:shrink-0 zd:text-greyScale\"\n aria-hidden\n />\n )\n}\n\nfunction ChainTag({ name, iconUrl }: { name: string; iconUrl?: string }) {\n return (\n <span className=\"zd:flex zd:min-w-0 zd:items-center zd:gap-1\">\n {iconUrl && (\n <span className=\"zd:size-3 zd:shrink-0 zd:overflow-hidden zd:rounded-full zd:border zd:border-offWhite/40 zd:bg-white\">\n <img\n src={iconUrl}\n alt=\"\"\n aria-hidden\n className=\"zd:size-full zd:object-contain\"\n />\n </span>\n )}\n <Text className=\"zd:truncate zd:text-body3 zd:text-greyScale/80\">\n {name}\n </Text>\n </span>\n )\n}\n\nfunction AddressLine({ address, href }: { address: string; href?: string }) {\n const inner = (\n <>\n <span className=\"zd:truncate\">{address}</span>\n {href && (\n // 8px, not the design's 10px box: our export glyph is full-bleed\n // while Figma's sits inset 10% in its box, so matching the box size\n // renders visibly bigger. 8px equals the design's effective glyph.\n <Icon name=\"export\" className=\"zd:size-2 zd:shrink-0\" aria-hidden />\n )}\n </>\n )\n\n const className =\n 'zd:flex zd:min-w-0 zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale/80'\n\n if (href) {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n aria-label={`View ${address} on block explorer`}\n className={cn(className, 'zd:hover:text-greyScale')}\n >\n {inner}\n </a>\n )\n }\n return <span className={className}>{inner}</span>\n}\n","import { cn, Text } from '@zerodev/react-ui'\nimport type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { CHAIN_ICONS, TOKEN_ICONS } from '../../iconAssets'\nimport type {\n DepositStage,\n DepositWithTimestamp,\n EstimatedFee,\n SmartRoutingAddressConfig,\n} from '../../types'\nimport { getTxUrl } from '../../utils/chains'\nimport {\n getSourceTokenSymbol,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../../utils/config'\nimport { getDepositStage } from '../../utils/deposits'\nimport { findFeeDataByToken, tokenAddressMatches } from '../../utils/fees'\nimport {\n formatDisplayAmount,\n formatRelativeTime,\n truncateAddress,\n} from '../../utils/format'\nimport { TxnItem, type TxnStatus } from '../TxnItem'\n\nexport interface PendingDepositsProps {\n deposits: DepositedToken[]\n estimatedFees: EstimatedFee[]\n config: SmartRoutingAddressConfig\n /** Fired when a row is tapped — the widget uses this to open the\n * transaction-details view for the selected deposit. When omitted, rows\n * render as static (non-interactive). */\n onSelectDeposit?: (deposit: DepositedToken) => void\n className?: string\n}\n\nconst STAGE_TO_STATUS: Record<DepositStage, TxnStatus> = {\n pending: 'Detected',\n bridging: 'Routing',\n completed: 'Received',\n failed: 'Failed',\n}\n\nexport function PendingDeposits({\n deposits,\n estimatedFees,\n config,\n onSelectDeposit,\n className,\n}: PendingDepositsProps) {\n if (deposits.length === 0) return null\n\n const destChain = resolveDestChain(config)\n const destChainLogo = CHAIN_ICONS[destChain.id]\n\n return (\n <section\n aria-label=\"Active deposits\"\n className={cn(\n // Figma 20002:36058: tighter bottom padding than top so the last\n // row's own padding doesn't double up against the card edge.\n 'zd:relative zd:flex zd:w-full zd:flex-col zd:gap-4 zd:overflow-hidden zd:rounded-2xl zd:px-4 zd:pt-4 zd:pb-2',\n 'zd:border-offWhite zd:border-[0.3px] zd:bg-white/20',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n className,\n )}\n >\n <Text className=\"zd:text-h3\">Active Deposit</Text>\n <ul className=\"zd:flex zd:w-full zd:flex-col zd:gap-1\">\n {deposits.map((raw) => {\n const deposit = raw as DepositWithTimestamp\n const { chainId, token, amount, transactionHash } = deposit.deposit\n const feeData = findFeeDataByToken(estimatedFees, chainId, token)\n\n // Source pair: reconstruct the SourceToken so we can look up its\n // symbol + chain icon the same way the trigger pill does. Matching\n // on the on-chain address (via `tokenAddressMatches`) — the\n // server's `feeData.name` is a display symbol (e.g. \"ETH\"), not the\n // TOKEN_TYPE (\"NATIVE\"), so a direct `t.tokenType === name` compare\n // misses native tokens.\n const source =\n sourceTokensFromFees(estimatedFees).find(\n (t) =>\n t.chain.id === chainId &&\n tokenAddressMatches(t.tokenType, chainId, token),\n ) ?? null\n // Prefer the reconstructed source's symbol; fall back to the\n // server's `feeData.name` so past deposits whose route dropped\n // out of the current fee estimates still get a symbol / icon.\n const sourceSymbol = source\n ? getSourceTokenSymbol(source)\n : (feeData?.name ?? '')\n const sourceTokenLogo = sourceSymbol\n ? TOKEN_ICONS[sourceSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = CHAIN_ICONS[chainId]\n\n // Destination token equals source token — widget's default\n // actions forward the deposited asset unchanged.\n const destTokenLogo = sourceTokenLogo\n\n const status = STAGE_TO_STATUS[getDepositStage(deposit)]\n const amountLabel = feeData\n ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`\n : String(amount)\n const timestamp = deposit.createdAt\n ? (formatRelativeTime(deposit.createdAt) ?? '')\n : ''\n\n // Explorer URL from the chain id alone — independent of whether\n // the deposit's token was matched in the current fee estimates.\n const href = getTxUrl(chainId, transactionHash)\n\n const row = (\n <TxnItem\n amount={amountLabel}\n address={truncateAddress(transactionHash)}\n {...(href && { href })}\n timestamp={timestamp}\n status={status}\n {...(sourceTokenLogo && {\n sourceTokenIconUrl: sourceTokenLogo,\n })}\n {...(sourceChainLogo && {\n sourceChainIconUrl: sourceChainLogo,\n })}\n {...(destTokenLogo && { destTokenIconUrl: destTokenLogo })}\n {...(destChainLogo && { destChainIconUrl: destChainLogo })}\n />\n )\n\n return (\n <li key={transactionHash}>\n {onSelectDeposit ? (\n // No padding of its own: the TxnItem's built-in p-2 (the\n // Figma Txn Row inset) doubles as the hover highlight's\n // breathing room. Radius matches the row's rounded-2xl.\n <button\n type=\"button\"\n onClick={() => onSelectDeposit(deposit)}\n className=\"zd:w-full zd:cursor-pointer zd:rounded-2xl zd:text-left zd:hover:bg-white/30\"\n >\n {row}\n </button>\n ) : (\n row\n )}\n </li>\n )\n })}\n </ul>\n </section>\n )\n}\n","import type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { getSmartRoutingAddressStatus } from '@zerodev/smart-routing-address'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { Address } from 'viem'\nimport { DEFAULT_POLLING_INTERVAL_MS } from '../constants'\n\nexport type UseDepositStatusParams = {\n address: Address | undefined\n enabled?: boolean | undefined\n pollingInterval?: number | undefined\n baseUrl?: string | undefined\n}\n\nexport type UseDepositStatusResult = {\n deposits: DepositedToken[]\n totalCount: number\n /** True once at least one status response has been received */\n hasLoaded: boolean\n isLoading: boolean\n error: Error | null\n /** Trigger an immediate poll — used by the \"Retry\" button after a fetch\n * error. No-op while no address is set. */\n refetch: () => void\n}\n\nconst INITIAL_STATE = {\n deposits: [] as DepositedToken[],\n totalCount: 0,\n hasLoaded: false,\n isLoading: false,\n error: null as Error | null,\n}\n\n/**\n * Polls the smart routing address status endpoint while enabled, returning\n * the current list of deposits.\n */\nexport function useDepositStatus({\n address,\n enabled = true,\n pollingInterval = DEFAULT_POLLING_INTERVAL_MS,\n baseUrl,\n}: UseDepositStatusParams): UseDepositStatusResult {\n const [state, setState] = useState(INITIAL_STATE)\n // Exposed via `refetch`; reassigned every time the effect runs so we always\n // point at the poller bound to the current (address, baseUrl) pair.\n const pollRef = useRef<(() => void) | null>(null)\n\n useEffect(() => {\n if (!address || !enabled) {\n pollRef.current = null\n return\n }\n\n let cancelled = false\n // Each `poll()` call bumps `gen`; only the latest generation may write\n // to state. Prevents a stale interval-driven response from clobbering a\n // fresh `refetch()` (or vice-versa) when the two overlap in flight.\n let gen = 0\n\n const poll = async () => {\n gen += 1\n const requestGen = gen\n try {\n const result = await getSmartRoutingAddressStatus({\n smartRoutingAddress: address,\n ...(baseUrl && { config: { baseUrl } }),\n })\n if (cancelled || requestGen !== gen) return\n setState({\n deposits: result.deposits,\n totalCount: result.totalCount,\n hasLoaded: true,\n isLoading: false,\n error: null,\n })\n } catch (error) {\n if (cancelled || requestGen !== gen) return\n setState((previous) => ({\n ...previous,\n isLoading: false,\n error: error instanceof Error ? error : new Error(String(error)),\n }))\n }\n }\n\n pollRef.current = () => {\n setState((previous) => ({ ...previous, isLoading: true, error: null }))\n poll().catch(() => {})\n }\n\n setState((previous) => ({ ...previous, isLoading: true }))\n poll().catch(() => {})\n const intervalId = setInterval(() => {\n poll().catch(() => {})\n }, pollingInterval)\n\n return () => {\n cancelled = true\n clearInterval(intervalId)\n pollRef.current = null\n }\n }, [address, enabled, pollingInterval, baseUrl])\n\n const refetch = useCallback(() => {\n pollRef.current?.()\n }, [])\n\n return { ...state, refetch }\n}\n","import type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { useMemo, useRef } from 'react'\nimport { getDepositKey, getNewDeposits } from '../utils/deposits'\n\n/**\n * Tracks deposits that arrived after the first loaded status snapshot.\n * The snapshot taken when `ready` first becomes true acts as the baseline,\n * so pre-existing deposits are not reported as new.\n */\nexport function useNewDeposits(\n deposits: DepositedToken[],\n ready: boolean,\n): DepositedToken[] {\n const baselineRef = useRef<ReadonlySet<string> | null>(null)\n\n if (ready && baselineRef.current === null) {\n baselineRef.current = new Set(deposits.map(getDepositKey))\n }\n\n const baseline = baselineRef.current\n return useMemo(() => {\n if (!baseline) return []\n return getNewDeposits(deposits, baseline)\n }, [deposits, baseline])\n}\n","import type { TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { useEffect, useState } from 'react'\nimport type { Address, Chain } from 'viem'\nimport { zeroAddress } from 'viem'\nimport type { EstimatedFeeData, SourceToken } from '../types'\nimport { resolveTokenAddress } from '../utils/fees'\nimport {\n AcrossSuggestedFeesSchema,\n type FeeBreakdown,\n parseAcrossFees,\n parseRelayFees,\n RelayQuoteSchema,\n} from '../utils/providerFees'\n\nconst ACROSS_API = 'https://app.across.to/api/suggested-fees'\nconst RELAY_API = 'https://api.relay.link/quote'\n// Quotes barely depend on the caller; used only when no recipient is known\nconst QUOTE_USER: Address = '0x1111111111111111111111111111111111111111'\n\ntype Route = {\n tokenType: TOKEN_TYPE\n originChainId: number\n destinationChainId: number\n amount: string\n user: Address\n symbol: string\n decimals: number\n}\n\n/** Across is keyed by ERC-20 addresses; native is quoted via its wrapped form */\nfunction acrossToken(tokenType: TOKEN_TYPE, chainId: number): Address | null {\n if (tokenType === 'NATIVE') return resolveTokenAddress('WETH', chainId)\n return resolveTokenAddress(tokenType, chainId)\n}\n\n/** Relay represents native as the zero address; ERC-20s by their address */\nfunction relayToken(tokenType: TOKEN_TYPE, chainId: number): Address | null {\n if (tokenType === 'NATIVE') return zeroAddress\n return resolveTokenAddress(tokenType, chainId)\n}\n\nasync function fetchAcross(\n route: Route,\n signal: AbortSignal,\n): Promise<FeeBreakdown | null> {\n const inputToken = acrossToken(route.tokenType, route.originChainId)\n const outputToken = acrossToken(route.tokenType, route.destinationChainId)\n if (!inputToken || !outputToken) return null\n const params = new URLSearchParams({\n inputToken,\n outputToken,\n originChainId: String(route.originChainId),\n destinationChainId: String(route.destinationChainId),\n amount: route.amount,\n })\n const res = await fetch(`${ACROSS_API}?${params}`, { signal })\n if (!res.ok) return null\n const json = await res.json()\n if (!json || json.error) return null\n // Validate the response shape before handing it to the parser — if Across\n // changes their API in a way we don't recognise, we degrade gracefully to\n // the collapsed fee view instead of computing garbage from missing fields.\n const parsed = AcrossSuggestedFeesSchema.safeParse(json)\n if (!parsed.success) {\n // biome-ignore lint/suspicious/noConsole: schema-drift signal for developers; silent failure is what we're trying to avoid.\n console.warn(\n '[useProviderFees] Across response failed schema validation',\n parsed.error.issues,\n )\n return null\n }\n return parseAcrossFees(parsed.data, route.symbol, route.decimals)\n}\n\nasync function fetchRelay(\n route: Route,\n signal: AbortSignal,\n): Promise<FeeBreakdown | null> {\n const originCurrency = relayToken(route.tokenType, route.originChainId)\n const destinationCurrency = relayToken(\n route.tokenType,\n route.destinationChainId,\n )\n if (!originCurrency || !destinationCurrency) return null\n const res = await fetch(RELAY_API, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n signal,\n body: JSON.stringify({\n user: route.user,\n recipient: route.user,\n originChainId: route.originChainId,\n destinationChainId: route.destinationChainId,\n originCurrency,\n destinationCurrency,\n amount: route.amount,\n tradeType: 'EXACT_INPUT',\n }),\n })\n if (!res.ok) return null\n const json = await res.json()\n if (!json || json.error) return null\n // See fetchAcross above — schema validation is the last line of defence\n // between a silently changed API and wrong fees rendered to the user.\n const parsed = RelayQuoteSchema.safeParse(json)\n if (!parsed.success) {\n // biome-ignore lint/suspicious/noConsole: schema-drift signal for developers; silent failure is what we're trying to avoid.\n console.warn(\n '[useProviderFees] Relay response failed schema validation',\n parsed.error.issues,\n )\n return null\n }\n return parseRelayFees(parsed.data)\n}\n\n/** Pick the cheaper live route by full quoted cost; else the first available */\nfunction bestRoute(routes: (FeeBreakdown | null)[]): FeeBreakdown | null {\n const available = routes.filter((r): r is FeeBreakdown => r !== null)\n if (available.length === 0) return null\n const withUsd = available.filter((r) => r.quotedTotalUsd !== null)\n if (withUsd.length === 0) return available[0] ?? null\n return withUsd.reduce((best, r) =>\n (r.quotedTotalUsd as number) < (best.quotedTotalUsd as number) ? r : best,\n )\n}\n\nexport type ProviderFeesState = {\n /** Cheapest normalised quote, or null while loading / unquotable */\n fees: FeeBreakdown | null\n /** True from the moment the route changes until the quotes resolve */\n loading: boolean\n}\n\n/**\n * Fetch live fee quotes for the selected route from every supported provider\n * (Across + Relay), normalise them, and return the cheapest. Across and Relay\n * expose the itemised bridge legs the SRA fee estimate alone does not, so this\n * enriches the breakdown with how the user is actually charged and which route\n * is currently best.\n *\n * Returns null while loading, for routes that can't be quoted (native /\n * unresolvable tokens), or when every request fails — callers fall back to\n * the SRA execution fee on their own.\n */\nexport function useProviderFees(\n source: SourceToken | null,\n destChain: Chain,\n feeData: EstimatedFeeData | null,\n recipient?: string,\n): ProviderFeesState {\n const [breakdown, setBreakdown] = useState<FeeBreakdown | null>(null)\n const [loading, setLoading] = useState(false)\n\n const sourceChainId = source?.chain.id\n const tokenType = source?.tokenType\n const destChainId = destChain.id\n const minDeposit = feeData?.minDeposit\n const symbol = feeData?.name\n const decimals = feeData?.decimal\n\n useEffect(() => {\n setBreakdown(null)\n if (\n tokenType === undefined ||\n sourceChainId === undefined ||\n !minDeposit ||\n symbol === undefined ||\n decimals === undefined\n ) {\n setLoading(false)\n return\n }\n setLoading(true)\n\n let amount: string\n try {\n amount = BigInt(minDeposit).toString()\n } catch {\n // Malformed `minDeposit` — nothing to quote. Clear loading so the\n // caller doesn't sit in a spinner forever until the route changes.\n setLoading(false)\n return\n }\n\n const route: Route = {\n tokenType,\n originChainId: sourceChainId,\n destinationChainId: destChainId,\n amount,\n user: (recipient as Address) || QUOTE_USER,\n symbol,\n decimals,\n }\n\n const controller = new AbortController()\n // Swallow provider failures so one broken provider doesn't take out the\n // other — but log everything except the expected abort so a real bug\n // (network, parser regression) doesn't disappear silently.\n const safe = (label: string, p: Promise<FeeBreakdown | null>) =>\n p.catch((err) => {\n if (err?.name !== 'AbortError') {\n // biome-ignore lint/suspicious/noConsole: surfaces network / parser regressions that would otherwise be invisible.\n console.warn(`[useProviderFees] ${label} failed`, err)\n }\n return null\n })\n Promise.all([\n safe('Across', fetchAcross(route, controller.signal)),\n safe('Relay', fetchRelay(route, controller.signal)),\n ])\n .then(([across, relay]) => {\n const chosen = bestRoute([across, relay])\n if (!controller.signal.aborted) {\n setBreakdown(chosen)\n setLoading(false)\n }\n })\n .catch(() => {\n // All providers failed → caller shows the SRA fee\n if (!controller.signal.aborted) setLoading(false)\n })\n return () => controller.abort()\n }, [\n sourceChainId,\n tokenType,\n destChainId,\n minDeposit,\n symbol,\n decimals,\n recipient,\n ])\n\n return { fees: breakdown, loading }\n}\n","import {\n ArrowCardPair,\n cn,\n DataRow,\n Icon,\n Pill,\n Select,\n SelectContent,\n SelectIcon,\n SelectItem,\n SelectTrigger,\n Text,\n TokenListItem,\n Tooltip,\n WrappedPressable,\n Wrapper,\n} from '@zerodev/react-ui'\nimport type { DepositedToken, TOKEN_TYPE } from '@zerodev/smart-routing-address'\nimport { useCallback, useEffect, useMemo, useState } from 'react'\nimport { AddressDisplay } from '../components/AddressDisplay'\nimport { ErrorRetryCard } from '../components/ErrorRetryCard'\nimport {\n FeeBreakdownRows,\n FeeSummary,\n LiveValue,\n} from '../components/FeeBreakdown'\nimport { FEE_INFO } from '../components/FeeBreakdown/feeInfo'\nimport { LoadingCard } from '../components/LoadingCard'\nimport { PendingDeposits } from '../components/PendingDeposits'\nimport { DEFAULT_FILL_TIME_SECONDS } from '../constants'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { useDepositStatus } from '../hooks/useDepositStatus'\nimport { useNewDeposits } from '../hooks/useNewDeposits'\nimport { useProviderFees } from '../hooks/useProviderFees'\nimport { CHAIN_ICONS, PROVIDER_ICONS, TOKEN_ICONS } from '../iconAssets'\nimport type { SourceToken } from '../types'\nimport {\n getSourceTokenSymbol,\n resolveBaseUrl,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../utils/config'\nimport { findFeeData, resolveTokenAddress } from '../utils/fees'\nimport {\n formatDisplayAmount,\n formatDuration,\n formatSlippage,\n} from '../utils/format'\nimport { buildFeeBreakdown } from '../utils/providerFees'\n\nexport interface DepositProps {\n onQrClick?: () => void\n /** Navigate to the \"Past deposits\" view. When omitted, the row is hidden. */\n onViewPastDeposits?: () => void\n /** Fired when a pending-deposit row is tapped. Wires through to\n * `PendingDeposits` so an in-flight deposit opens the transaction-details\n * view, matching the past-deposits behaviour. */\n onSelectDeposit?: (deposit: DepositedToken) => void\n}\n\nconst SUBTITLE =\n \"Send any supported token from any network. We'll swap & bridge it directly to your account, ready to use.\"\n\n// The two picker panels span the full pill row (Figma \"Send\" layout), not\n// just the trigger cell each Select lives in. Trigger width = half the row\n// minus half the 4px gap, so full-row width = trigger * 2 + 4px.\nconst FULL_ROW_PANEL_STYLE = {\n width: 'calc(var(--radix-select-trigger-width) * 2 + 4px)',\n}\n\nexport function Deposit({\n onQrClick,\n onViewPastDeposits,\n onSelectDeposit,\n}: DepositProps) {\n const { config, addressState, recipient, retry, setActiveRoute } =\n useSmartRoutingAddressContext()\n const [feeOpen, setFeeOpen] = useState(false)\n const [retrying, setRetrying] = useState(false)\n\n const success = addressState.status === 'success' ? addressState : null\n const address = success?.address\n const estimatedFees = success?.estimatedFees ?? []\n\n // allowPartialRoutes lets the server drop source tokens it can't route, so\n // the routable set is exactly the tokens the fee estimates came back with.\n const srcTokens = useMemo(\n () => sourceTokensFromFees(estimatedFees),\n [estimatedFees],\n )\n\n // Track the user's picker selection. `null` means \"no explicit choice yet\" —\n // an effect below seeds it to the first routable option once srcTokens land.\n const [selectedTokenType, setSelectedTokenType] = useState<TOKEN_TYPE | null>(\n null,\n )\n const [selectedChainId, setSelectedChainId] = useState<number | null>(null)\n\n // Seed picker state from the first routable option as soon as srcTokens\n // arrive. Also re-seeds if a stale selection becomes unroutable.\n useEffect(() => {\n if (srcTokens.length === 0) return\n const currentValid = srcTokens.some(\n (t) =>\n t.tokenType === selectedTokenType && t.chain.id === selectedChainId,\n )\n if (currentValid) return\n // Prefer to keep the token, swap the chain to one that's available for it.\n const forSameToken = srcTokens.find(\n (t) => t.tokenType === selectedTokenType,\n )\n const fallback = forSameToken ?? srcTokens[0]\n if (!fallback) return\n setSelectedTokenType(fallback.tokenType)\n setSelectedChainId(fallback.chain.id)\n }, [srcTokens, selectedTokenType, selectedChainId])\n\n const source: SourceToken | null = useMemo(() => {\n if (!selectedTokenType || selectedChainId === null) {\n return srcTokens[0] ?? null\n }\n return (\n srcTokens.find(\n (t) =>\n t.tokenType === selectedTokenType && t.chain.id === selectedChainId,\n ) ??\n srcTokens[0] ??\n null\n )\n }, [srcTokens, selectedTokenType, selectedChainId])\n\n const {\n deposits,\n hasLoaded,\n error: depositsError,\n refetch: refetchDeposits,\n } = useDepositStatus({\n address,\n baseUrl: resolveBaseUrl(config),\n })\n const newDeposits = useNewDeposits(deposits, hasLoaded)\n const pastDepositsCount = deposits.length - newDeposits.length\n\n const destChain = resolveDestChain(config)\n // Widget's default actions forward the deposited token, so the destination\n // token equals the source token — one symbol and logo serve both cards.\n // Only the chain differs, hence the source/dest split below.\n const tokenSymbol = source ? getSourceTokenSymbol(source) : undefined\n const tokenLogo = tokenSymbol\n ? TOKEN_ICONS[tokenSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = source ? CHAIN_ICONS[source.chain.id] : undefined\n const destChainLogo = CHAIN_ICONS[destChain.id]\n const feeData = source\n ? findFeeData(estimatedFees, source.chain.id, source.tokenType)\n : null\n const fillTime = formatDuration(DEFAULT_FILL_TIME_SECONDS)\n\n // Live bridge quotes from Across / Relay, keyed off the selected route.\n // Enriches the SRA fee estimate with the itemised legs it doesn't expose.\n const providerFees = useProviderFees(source, destChain, feeData, recipient)\n const breakdown =\n feeData && tokenSymbol\n ? buildFeeBreakdown(feeData, tokenSymbol, providerFees.fees)\n : null\n\n // Publish the current picker selection so hosts (e.g. a demo \"send\" panel)\n // can mirror the widget's route. Cleared when the picker is empty so\n // downstream mocks show their fallback instead of stale state.\n useEffect(() => {\n if (!source || !feeData || !tokenSymbol) {\n setActiveRoute(null)\n return\n }\n const token = resolveTokenAddress(source.tokenType, source.chain.id)\n if (!token) {\n setActiveRoute(null)\n return\n }\n setActiveRoute({\n sourceChainId: source.chain.id,\n sourceChainName: source.chain.name,\n token,\n symbol: tokenSymbol,\n decimals: feeData.decimal,\n // `feeData.fee` is a `Hex` string from the SDK — normalise to a\n // decimal atomic-units string here so `activeRoute.feeAmount` has\n // one consistent representation across every write path (see\n // `ActiveRoute.feeAmount` — the demo's fallback uses decimals too).\n // Hosts using `BigInt()` work either way, but `Number()` /\n // `parseInt(x, 10)` would silently misread the hex form.\n feeAmount: BigInt(feeData.fee).toString(),\n })\n }, [source, feeData, tokenSymbol, setActiveRoute])\n\n // Deduped list of routable token types — the token picker's rows. Chain\n // count per token drives the subtitle. Kept as SourceToken (not a bespoke\n // dropdown-item shape) so the render below can call the same helpers used\n // for the trigger.\n const uniqueTokens = useMemo(() => {\n const seen = new Set<TOKEN_TYPE>()\n const out: SourceToken[] = []\n for (const token of srcTokens) {\n if (seen.has(token.tokenType)) continue\n seen.add(token.tokenType)\n out.push(token)\n }\n return out\n }, [srcTokens])\n\n // Chains that carry the currently-selected token — the chain picker's rows.\n const availableChains = useMemo(() => {\n if (!selectedTokenType) return []\n const seen = new Set<number>()\n const out: SourceToken[] = []\n for (const token of srcTokens) {\n if (token.tokenType !== selectedTokenType) continue\n if (seen.has(token.chain.id)) continue\n seen.add(token.chain.id)\n out.push(token)\n }\n return out\n }, [srcTokens, selectedTokenType])\n\n // Always present: config.slippage is required now that the SRA server no\n // longer supplies a default.\n const slippage = formatSlippage(config.slippage)\n\n const minDepositAmount =\n feeData && tokenSymbol\n ? `${formatDisplayAmount(feeData.minDeposit, feeData.decimal, 'up')} ${tokenSymbol}`\n : null\n\n // Flash key re-triggers the LiveValue animation on the estimated-fee row\n // when the underlying quote changes; combining every meaningful component\n // catches all updates in one dependency.\n const feeFlashKey = breakdown\n ? `${breakdown.totalText ?? ''}|${breakdown.ratePct ?? ''}|${breakdown.flatUsd ?? ''}`\n : ''\n\n const pickerDisabled = uniqueTokens.length === 0\n const sourceChainName = source?.chain.name\n\n // Error surfaces the retry card handles. Only one is shown at a time,\n // matched top-down in severity order: (1) address creation itself failed,\n // (2) creation succeeded but no routes came back, (3) deposit polling is\n // erroring after we already have an address. `hasLoaded` gates the polling\n // case so first-load latency isn't mistaken for an error.\n const addressError = addressState.status === 'error'\n const noRoutesError = !!success && srcTokens.length === 0\n const pollingError = !!address && !!depositsError && hasLoaded\n const errorMessage = addressError\n ? 'Failed to create deposit address...'\n : noRoutesError\n ? 'No routes found, try one more time...'\n : pollingError\n ? 'Failed to load deposits, try again...'\n : null\n\n const handleRetry = useCallback(async () => {\n if (retrying) return\n setRetrying(true)\n try {\n if (pollingError && !addressError && !noRoutesError) {\n refetchDeposits()\n } else {\n await retry()\n }\n } finally {\n setRetrying(false)\n }\n }, [\n retrying,\n pollingError,\n addressError,\n noRoutesError,\n refetchDeposits,\n retry,\n ])\n\n return (\n // min-h-full, not h-full: with a fixed height, overflowing content\n // scrolls past the padding box and pb-6 never lands after the last row\n // (the \"Past deposits\" row hits the bottom edge). min-h keeps short\n // content filling the viewport while letting tall content grow so the\n // bottom padding is honoured.\n <div className=\"zd:flex zd:min-h-full zd:w-full zd:flex-col zd:items-center zd:gap-4 zd:pt-4 zd:pb-6\">\n <Text className=\"zd:w-full zd:text-center\">{SUBTITLE}</Text>\n\n <div className=\"zd:relative zd:flex zd:w-full zd:flex-1 zd:flex-col zd:gap-2\">\n <ArrowCardPair\n topCard={\n <Wrapper\n variant=\"ghost\"\n className=\"zd:relative zd:flex zd:w-full zd:flex-col zd:rounded-2xl zd:p-1\"\n >\n <CardTitle>Send</CardTitle>\n <PillRow\n left={\n <Select\n value={selectedTokenType ?? ''}\n onValueChange={(id) =>\n setSelectedTokenType(id as TOKEN_TYPE)\n }\n disabled={pickerDisabled}\n >\n <SelectTrigger asChild>\n <Pill\n label={tokenSymbol ?? ''}\n {...(tokenLogo && { logoUri: tokenLogo })}\n disabled={pickerDisabled}\n loading={!tokenSymbol}\n trailingIcon={!pickerDisabled && <SelectIcon />}\n />\n </SelectTrigger>\n <SelectContent align=\"start\" style={FULL_ROW_PANEL_STYLE}>\n {uniqueTokens.map((token, i) => {\n const symbol = getSourceTokenSymbol(token)\n const chainCount = srcTokens.filter(\n (t) => t.tokenType === token.tokenType,\n ).length\n const logo = TOKEN_ICONS[symbol.toUpperCase()]\n return (\n <SelectItem\n key={token.tokenType}\n value={token.tokenType}\n textValue={symbol}\n className=\"zd:p-0\"\n >\n <TokenListItem\n symbol={symbol}\n subtitle={`${chainCount} network${chainCount === 1 ? '' : 's'}`}\n {...(logo && { imageSource: logo })}\n />\n {i === 0 && (\n <span className=\"zd:absolute zd:top-1/2 zd:right-3 zd:-translate-y-1/2 zd:inline-flex zd:items-center zd:rounded-full zd:bg-positive/15 zd:px-2 zd:py-1 zd:text-body3 zd:text-positive zd:pointer-events-none\">\n Recommended\n </span>\n )}\n </SelectItem>\n )\n })}\n </SelectContent>\n </Select>\n }\n right={\n <Select\n value={\n selectedChainId !== null ? String(selectedChainId) : ''\n }\n onValueChange={(id) => setSelectedChainId(Number(id))}\n disabled={pickerDisabled}\n >\n <SelectTrigger asChild>\n <Pill\n label={sourceChainName ?? ''}\n {...(sourceChainLogo && { logoUri: sourceChainLogo })}\n disabled={pickerDisabled}\n loading={!sourceChainName}\n trailingIcon={!pickerDisabled && <SelectIcon />}\n />\n </SelectTrigger>\n <SelectContent align=\"end\" style={FULL_ROW_PANEL_STYLE}>\n {availableChains.map((token) => {\n const logo = CHAIN_ICONS[token.chain.id]\n return (\n <SelectItem\n key={token.chain.id}\n value={String(token.chain.id)}\n textValue={token.chain.name}\n className=\"zd:p-0\"\n >\n <TokenListItem\n symbol={token.chain.name}\n iconVariant=\"network\"\n {...(logo && { imageSource: logo })}\n />\n </SelectItem>\n )\n })}\n </SelectContent>\n </Select>\n }\n />\n <div className=\"zd:flex zd:w-full zd:flex-col zd:items-start zd:gap-2 zd:px-2 zd:py-4\">\n <DataRow\n label=\"Max slippage\"\n value={slippage}\n info\n infoTooltip={FEE_INFO.maxSlippage}\n trailing={\n breakdown?.provider &&\n PROVIDER_ICONS[breakdown.provider] ? (\n <LiveValue\n loading={providerFees.loading}\n flashKey={breakdown.provider}\n >\n <Tooltip content={`Quoted via ${breakdown.provider}`}>\n <button\n type=\"button\"\n aria-label={`Quoted via ${breakdown.provider}`}\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-help zd:outline-none zd:bg-transparent\"\n >\n <img\n src={PROVIDER_ICONS[breakdown.provider]}\n alt=\"\"\n aria-hidden\n className=\"zd:size-4 zd:shrink-0 zd:rounded-[4px] zd:object-cover\"\n />\n </button>\n </Tooltip>\n </LiveValue>\n ) : null\n }\n />\n <DataRow\n label=\"Estimated fee\"\n value={\n breakdown ? (\n <LiveValue\n loading={providerFees.loading}\n flashKey={feeFlashKey}\n >\n <FeeSummary breakdown={breakdown} />\n </LiveValue>\n ) : (\n // Match Min deposit's skeleton so both loading\n // affordances share one visual language.\n <div className=\"zd:h-3.5 zd:w-20 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse\" />\n )\n }\n info\n infoTooltip={FEE_INFO.estimatedFee}\n trailing={\n breakdown ? (\n <button\n type=\"button\"\n onClick={() => setFeeOpen((prev) => !prev)}\n aria-expanded={feeOpen}\n aria-label={\n feeOpen ? 'Hide fee details' : 'Show fee details'\n }\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-pointer\"\n >\n <Icon\n name={feeOpen ? 'chevronUp' : 'chevronDown'}\n className=\"zd:w-3.5 zd:h-3.5 zd:text-greyScale\"\n />\n </button>\n ) : null\n }\n />\n {feeOpen && breakdown && (\n <FeeBreakdownRows breakdown={breakdown} />\n )}\n </div>\n </Wrapper>\n }\n bottomCard={\n <Wrapper\n variant=\"ghost\"\n className=\"zd:relative zd:flex zd:w-full zd:flex-col zd:gap-2 zd:rounded-2xl zd:p-1\"\n >\n <CardTitle>Arrives as</CardTitle>\n <PillRow\n left={\n <Pill\n label={tokenSymbol ?? ''}\n {...(tokenLogo && { logoUri: tokenLogo })}\n disabled\n loading={!tokenSymbol}\n />\n }\n right={\n <Pill\n label={destChain.name}\n {...(destChainLogo && { logoUri: destChainLogo })}\n disabled\n />\n }\n />\n <div className=\"zd:flex zd:w-full zd:flex-col zd:items-start zd:px-2\">\n <DataRow\n label=\"Ready in\"\n value={fillTime}\n info\n infoTooltip={FEE_INFO.readyIn}\n />\n </div>\n <AddressDisplay\n status={addressState.status}\n address={address}\n onQrClick={onQrClick}\n />\n {address && <CopyAddressButton address={address} />}\n {errorMessage && (\n <ErrorRetryCard\n message={errorMessage}\n onRetry={handleRetry}\n busy={retrying}\n />\n )}\n <DataRow\n label=\"Min deposit\"\n value={\n minDepositAmount ?? (\n // Match PillSkeleton's greyish pulse so all loading\n // affordances in this card share one visual language.\n // `<output>` gets an implicit `role=\"status\"` — biome's\n // `useSemanticElements` prefers it over `<div role>`.\n // `aria-busy` + `aria-label` so screen readers hear\n // \"loading\" instead of landing on an empty region.\n <output\n aria-busy=\"true\"\n aria-label=\"Loading minimum deposit\"\n className=\"zd:block zd:h-3.5 zd:w-20 zd:rounded-md zd:bg-greyScale/15 zd:animate-skel-pulse\"\n />\n )\n }\n info\n infoTooltip={FEE_INFO.minDeposit}\n variant=\"warning\"\n />\n </Wrapper>\n }\n />\n\n {/* Deposit watching only makes sense once the address exists —\n while creation is loading (or failed) there is nothing to watch,\n so neither card renders. */}\n {address &&\n (newDeposits.length > 0 ? (\n <PendingDeposits\n deposits={newDeposits}\n estimatedFees={estimatedFees}\n config={config}\n {...(onSelectDeposit && { onSelectDeposit })}\n />\n ) : (\n <LoadingCard\n text={\n source\n ? `Watching for your deposit on ${source.chain.name}…`\n : 'Watching for your deposit…'\n }\n />\n ))}\n\n {pastDepositsCount > 0 &&\n (onViewPastDeposits ? (\n <WrappedPressable\n onClick={onViewPastDeposits}\n className={cn('zd:w-full', PAST_DEPOSITS_CARD)}\n >\n <PastDepositsRow count={pastDepositsCount} />\n </WrappedPressable>\n ) : (\n <Wrapper\n variant=\"ghost\"\n className={cn(\n 'zd:flex zd:w-full zd:items-center',\n PAST_DEPOSITS_CARD,\n )}\n >\n <PastDepositsRow count={pastDepositsCount} />\n </Wrapper>\n ))}\n </div>\n </div>\n )\n}\n\n/**\n * Full-width dark \"Copy Address\" pill under the address row (Figma\n * `20002:36049`). Not react-ui's `Button`: that primitive is locked to the\n * 64px/24px-radius spec, while this is the design system's smaller\n * 48px/14px button — worth promoting as a Button size variant if it\n * recurs. Label flips to \"Copied!\" for 2s as tap feedback (the design has\n * no pressed state).\n */\nfunction CopyAddressButton({ address }: { address: string }) {\n const [copied, setCopied] = useState(false)\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(address)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard can reject on insecure contexts / denied permission —\n // keep the label unchanged rather than claim a copy happened.\n }\n }\n\n return (\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n 'zd:relative zd:flex zd:h-12 zd:w-full zd:shrink-0 zd:cursor-pointer zd:items-center zd:justify-center zd:gap-2',\n 'zd:rounded-[14px] zd:backdrop-blur-[15px] zd:transition-colors zd:hover:bg-greyScale',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n )}\n style={{ backgroundColor: 'rgba(19, 14, 11, 0.9)' }}\n >\n <Text className=\"zd:text-body1 zd:text-offWhite\">\n {copied ? 'Copied!' : 'Copy Address'}\n </Text>\n <Icon\n name=\"copy\"\n className=\"zd:size-4 zd:shrink-0 zd:text-offWhite\"\n aria-hidden\n />\n </button>\n )\n}\n\n// Past-deposits card treatment (Figma 20002:36111): 16px radius plus the\n// universal inner shadow; border/blur/tint come from the ghost Wrapper.\nconst PAST_DEPOSITS_CARD =\n 'zd:rounded-2xl zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]'\n\n/** Row content shared by the tappable and inert past-deposits variants. */\nfunction PastDepositsRow({ count }: { count: number }) {\n return (\n <div className=\"zd:flex zd:w-full zd:items-center zd:gap-3 zd:p-4\">\n <div className=\"zd:flex zd:min-w-0 zd:flex-1 zd:items-center zd:gap-2\">\n <Icon\n name=\"clockFill\"\n className=\"zd:size-4 zd:shrink-0 zd:text-solarOrange\"\n aria-hidden\n />\n <Text className=\"zd:flex-1 zd:text-left zd:text-h3\">\n Past deposits ({count})\n </Text>\n </div>\n <Icon\n name=\"chevronRight\"\n className=\"zd:size-4.5 zd:shrink-0 zd:text-greyScale\"\n aria-hidden\n />\n </div>\n )\n}\n\nfunction CardTitle({ children }: { children: string }) {\n return (\n <div className={cn('zd:flex zd:items-center zd:px-2 zd:py-3')}>\n <Text className=\"zd:whitespace-nowrap zd:text-h3\">{children}</Text>\n </div>\n )\n}\n\nfunction PillRow({\n left,\n right,\n}: {\n left: React.ReactNode\n right: React.ReactNode\n}) {\n return (\n <div className=\"zd:flex zd:w-full zd:items-start zd:gap-1\">\n <div className=\"zd:min-w-0 zd:flex-1\">{left}</div>\n <div className=\"zd:min-w-0 zd:flex-1\">{right}</div>\n </div>\n )\n}\n","import { cn, Icon, Text } from '@zerodev/react-ui'\nimport type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { useMemo } from 'react'\nimport { TxnItem, type TxnStatus } from '../components/TxnItem'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { useDepositStatus } from '../hooks/useDepositStatus'\nimport { CHAIN_ICONS, TOKEN_ICONS } from '../iconAssets'\nimport type { DepositStage, DepositWithTimestamp } from '../types'\nimport { getTxUrl } from '../utils/chains'\nimport {\n getSourceTokenSymbol,\n resolveBaseUrl,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../utils/config'\nimport { getDepositStage } from '../utils/deposits'\nimport { findFeeDataByToken, tokenAddressMatches } from '../utils/fees'\nimport {\n formatDisplayAmount,\n formatRelativeTime,\n truncateAddress,\n} from '../utils/format'\n\nconst STAGE_TO_STATUS: Record<DepositStage, TxnStatus> = {\n pending: 'Detected',\n bridging: 'Routing',\n // Past deposits use the terminal label — \"Received\" (plain ink) is the\n // active list's arrival state; \"Delivered\" renders green.\n completed: 'Delivered',\n failed: 'Failed',\n}\n\ntype Group = { label: string; sortKey: number; items: DepositWithTimestamp[] }\n\nfunction dayStart(timestamp: number): number {\n const d = new Date(timestamp)\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime()\n}\n\nfunction groupLabel(timestamp: number | undefined): {\n label: string\n sortKey: number\n} {\n if (!timestamp) return { label: 'Recent', sortKey: -1 }\n const today = dayStart(Date.now())\n const day = dayStart(timestamp)\n if (day === today) return { label: 'Today', sortKey: today }\n if (day === today - 86_400_000) return { label: 'Yesterday', sortKey: day }\n return {\n label: new Intl.DateTimeFormat('en-US', {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n }).format(new Date(timestamp)),\n sortKey: day,\n }\n}\n\nfunction groupByDay(deposits: DepositWithTimestamp[]): Group[] {\n const buckets = new Map<string, Group>()\n for (const deposit of deposits) {\n const timestamp = deposit.createdAt\n ? Date.parse(deposit.createdAt)\n : undefined\n const { label, sortKey } = groupLabel(\n timestamp && !Number.isNaN(timestamp) ? timestamp : undefined,\n )\n const existing = buckets.get(label)\n if (existing) existing.items.push(deposit)\n else buckets.set(label, { label, sortKey, items: [deposit] })\n }\n return [...buckets.values()].sort((a, b) => b.sortKey - a.sortKey)\n}\n\nexport interface PastDepositsProps {\n /** Fired when a row is tapped — the widget uses this to open the\n * transaction-details view for the selected deposit. When omitted, rows\n * render as static (non-interactive). */\n onSelectDeposit?: (deposit: DepositedToken) => void\n}\n\n/**\n * Past deposits view — full history, grouped by day, newest first. Each row\n * is a `TxnItem`; layout matches the deposit's `PendingDeposits` card so the\n * two views share one visual language.\n */\nexport function PastDeposits({ onSelectDeposit }: PastDepositsProps) {\n const { config, addressState } = useSmartRoutingAddressContext()\n\n const success = addressState.status === 'success' ? addressState : null\n const address = success?.address\n const estimatedFees = success?.estimatedFees ?? []\n\n const { deposits, hasLoaded } = useDepositStatus({\n address,\n baseUrl: resolveBaseUrl(config),\n })\n\n const destChain = resolveDestChain(config)\n const destChainLogo = CHAIN_ICONS[destChain.id]\n\n const groups = useMemo(\n () => groupByDay(deposits as DepositWithTimestamp[]),\n [deposits],\n )\n\n return (\n <div className=\"zd:flex zd:h-full zd:w-full zd:flex-col zd:gap-4 zd:pt-4 zd:pb-6\">\n <section\n aria-label=\"Past deposits\"\n className={cn(\n 'zd:relative zd:flex zd:w-full zd:flex-1 zd:min-h-0 zd:flex-col zd:overflow-hidden zd:rounded-2xl zd:p-2',\n 'zd:border-offWhite zd:border-[0.3px] zd:bg-white/20',\n 'zd:shadow-[inset_0_-4px_4px_0_rgba(255,255,255,0.1),inset_0_3px_4px_0_rgba(0,0,0,0.02)]',\n )}\n >\n {!hasLoaded ? (\n <output\n aria-label=\"Loading past deposits\"\n className=\"zd:flex zd:flex-1 zd:items-center zd:justify-center zd:py-8\"\n >\n <Icon\n name=\"loading\"\n className=\"zd:size-5 zd:animate-spin zd:text-orange\"\n aria-hidden\n />\n </output>\n ) : deposits.length === 0 ? (\n <div className=\"zd:flex zd:flex-1 zd:items-center zd:justify-center zd:py-8\">\n <Text className=\"zd:text-greyScale/50\">No deposits yet</Text>\n </div>\n ) : (\n <div className=\"zd:flex zd:flex-1 zd:flex-col zd:gap-1 zd:overflow-y-auto\">\n {groups.map((group) => (\n <section key={group.label} className=\"zd:flex zd:flex-col\">\n <div className=\"zd:px-2 zd:py-2\">\n <Text className=\"zd:text-body3 zd:text-greyScale\">\n {group.label}\n </Text>\n </div>\n <ul className=\"zd:flex zd:flex-col\">\n {group.items.map((deposit) => {\n const { chainId, token, amount, transactionHash } =\n deposit.deposit\n const feeData = findFeeDataByToken(\n estimatedFees,\n chainId,\n token,\n )\n // Match on the on-chain address (via `tokenAddressMatches`)\n // — the server's `feeData.name` is a display symbol (e.g.\n // \"ETH\"), not the TOKEN_TYPE (\"NATIVE\"), so a direct\n // tokenType === name compare misses native tokens.\n const source =\n sourceTokensFromFees(estimatedFees).find(\n (t) =>\n t.chain.id === chainId &&\n tokenAddressMatches(t.tokenType, chainId, token),\n ) ?? null\n // Prefer the reconstructed source's symbol; fall back to\n // the server's `feeData.name` so past deposits whose route\n // dropped out of the current fee estimates still get a\n // symbol / icon.\n const sourceSymbol = source\n ? getSourceTokenSymbol(source)\n : (feeData?.name ?? '')\n const sourceTokenLogo = sourceSymbol\n ? TOKEN_ICONS[sourceSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = CHAIN_ICONS[chainId]\n // Destination token equals source token — widget's default\n // actions forward the deposited asset unchanged.\n const destTokenLogo = sourceTokenLogo\n const amountLabel = feeData\n ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`\n : String(amount)\n const timestamp = deposit.createdAt\n ? (formatRelativeTime(deposit.createdAt) ?? '')\n : ''\n // Explorer URL from the chain id alone — independent of\n // whether the deposit's token matched the current fees.\n const href = getTxUrl(chainId, transactionHash)\n const status = STAGE_TO_STATUS[getDepositStage(deposit)]\n // Delivered amount for the detailed row headline\n // (`amount → destAmount`). `'nearest'` rounding — the\n // server reports the actual post-fee on-chain amount and\n // users read this as \"what I received\". Falls back to the\n // deposited amount while execution details are absent so\n // the detailed layout stays stable across stages.\n const destAmountLabel =\n deposit.execution?.outputAmount && feeData\n ? `${formatDisplayAmount(deposit.execution.outputAmount, feeData.decimal, 'nearest')} ${sourceSymbol}`\n : amountLabel\n\n const row = (\n <TxnItem\n amount={amountLabel}\n destAmount={destAmountLabel}\n address={truncateAddress(transactionHash)}\n {...(href && { href })}\n timestamp={timestamp}\n status={status}\n {...(source?.chain.name && {\n sourceChainName: source.chain.name,\n })}\n destChainName={destChain.name}\n {...(sourceTokenLogo && {\n sourceTokenIconUrl: sourceTokenLogo,\n })}\n {...(sourceChainLogo && {\n sourceChainIconUrl: sourceChainLogo,\n })}\n {...(destTokenLogo && {\n destTokenIconUrl: destTokenLogo,\n })}\n {...(destChainLogo && {\n destChainIconUrl: destChainLogo,\n })}\n />\n )\n return (\n <li key={transactionHash}>\n {onSelectDeposit ? (\n // No padding of its own: the TxnItem's built-in\n // p-2 (the Figma Txn Row inset) doubles as the\n // hover highlight's breathing room. Radius matches\n // the row's rounded-2xl.\n <button\n type=\"button\"\n onClick={() => onSelectDeposit(deposit)}\n className=\"zd:w-full zd:cursor-pointer zd:rounded-2xl zd:text-left zd:hover:bg-white/30\"\n >\n {row}\n </button>\n ) : (\n row\n )}\n </li>\n )\n })}\n </ul>\n </section>\n ))}\n </div>\n )}\n </section>\n </div>\n )\n}\n","import {\n ArrowCardPair,\n cn,\n DataRow,\n Icon,\n InfoCard,\n ProgressStep,\n Section,\n Text,\n} from '@zerodev/react-ui'\nimport { useState } from 'react'\nimport { FeeBreakdownRows, FeeSummary } from '../components/FeeBreakdown'\nimport { FEE_INFO } from '../components/FeeBreakdown/feeInfo'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { useDepositStatus } from '../hooks/useDepositStatus'\nimport { useProviderFees } from '../hooks/useProviderFees'\nimport { CHAIN_ICONS, PROVIDER_ICONS, TOKEN_ICONS } from '../iconAssets'\nimport type { DepositWithTimestamp } from '../types'\nimport { getTxUrl } from '../utils/chains'\nimport {\n getSourceTokenSymbol,\n resolveBaseUrl,\n resolveDestChain,\n sourceTokensFromFees,\n} from '../utils/config'\nimport { getDepositStage } from '../utils/deposits'\nimport { findFeeDataByToken, tokenAddressMatches } from '../utils/fees'\nimport { formatDisplayAmount, truncateAddress } from '../utils/format'\nimport { buildFeeBreakdown } from '../utils/providerFees'\n\nexport interface TransactionDetailsProps {\n deposit: DepositWithTimestamp\n}\n\n/**\n * Poll the deposits list and return the latest snapshot of the deposit\n * matching `initial.deposit.transactionHash`, falling back to `initial` until\n * the first response lands (or if the deposit falls out of the list). Keeps\n * the details view live while the same interval is already running in\n * `Deposit` / `PastDeposits`.\n */\nfunction useLiveDeposit(initial: DepositWithTimestamp): DepositWithTimestamp {\n const { config, addressState } = useSmartRoutingAddressContext()\n const address =\n addressState.status === 'success' ? addressState.address : undefined\n const { deposits } = useDepositStatus({\n address,\n baseUrl: resolveBaseUrl(config),\n })\n const targetHash = initial.deposit.transactionHash\n const live = deposits.find((d) => d.deposit.transactionHash === targetHash) as\n | DepositWithTimestamp\n | undefined\n return live ?? initial\n}\n\n/** DOM id shared by the fee-toggle button's `aria-controls` and the panel it\n * opens. Kept as a constant so both sides move together if renamed. */\nconst FEE_PANEL_ID = 'sra-tx-fee-panel'\n\nfunction formatDate(iso?: string): string | null {\n if (!iso) return null\n const ts = Date.parse(iso)\n if (Number.isNaN(ts)) return null\n return new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n }).format(new Date(ts))\n}\n\n/**\n * Transaction details view (Figma `17634:105049`) — token hero pair via\n * `ArrowCardPair` + `InfoCard`, a \"Transaction details\" `Section` with the\n * route metadata, and a \"Transaction Progress\" `Section` with the step trail.\n */\nexport function TransactionDetails({\n deposit: initialDeposit,\n}: TransactionDetailsProps) {\n // Re-poll and pick the latest snapshot for this deposit so the details view\n // — Transaction Progress in particular — updates live rather than staying\n // frozen at click-time state.\n const deposit = useLiveDeposit(initialDeposit)\n const { config, addressState, recipient } = useSmartRoutingAddressContext()\n const estimatedFees =\n addressState.status === 'success' ? addressState.estimatedFees : []\n\n const { chainId, token, amount, transactionHash } = deposit.deposit\n const feeData = findFeeDataByToken(estimatedFees, chainId, token)\n\n // Match on the on-chain address (via `tokenAddressMatches`) — the server's\n // `feeData.name` is a display symbol (e.g. \"ETH\"), not the TOKEN_TYPE\n // (\"NATIVE\"), so a direct name compare would miss native tokens.\n const source =\n sourceTokensFromFees(estimatedFees).find(\n (t) =>\n t.chain.id === chainId &&\n tokenAddressMatches(t.tokenType, chainId, token),\n ) ?? null\n const sourceSymbol = source ? getSourceTokenSymbol(source) : ''\n const sourceChain = source?.chain\n const sourceTokenLogo = sourceSymbol\n ? TOKEN_ICONS[sourceSymbol.toUpperCase()]\n : undefined\n const sourceChainLogo = CHAIN_ICONS[chainId]\n\n const destChain = resolveDestChain(config)\n // Widget's default actions forward the deposited token, so destination\n // token = source token — reuse the source logo.\n const destTokenLogo = sourceTokenLogo\n const destChainLogo = CHAIN_ICONS[destChain.id]\n\n const stage = getDepositStage(deposit)\n const execution = deposit.execution\n const outAmountRaw = execution?.outputAmount\n const failed = stage === 'failed'\n\n // Headline reads as \"how much you sent\" — round down so we never overstate\n // the deposit. `formatDisplayAmount` (magnitude-aware) also prevents the\n // 18-decimal fractional tail that `formatTokenAmount` produces for ETH.\n const sourceHeadline = feeData\n ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`\n : String(amount)\n\n // NOTE: `feeData.decimal` is the source token's decimals — the SRA fee\n // estimates don't include destination-token decimals, so this is an\n // approximation that only reads correctly when source and destination\n // decimals match. Fixing this properly needs a dest-decimals lookup and\n // is out of scope here.\n //\n // Destination uses `'nearest'` rounding — the server returns the actual\n // on-chain amount after fees + slippage (e.g. 249.9996), and users read\n // this as \"how much I received\", so rounding to 250.00 is intuitive.\n const destHeadline =\n outAmountRaw && feeData\n ? `${formatDisplayAmount(outAmountRaw, feeData.decimal, 'nearest')} ${sourceSymbol}`\n : '—'\n\n // `getTxUrl` looks up the chain independently of whether `source` was\n // resolved above — a deposit on a known chain still gets a link even if\n // its token wasn't matched via `sourceTokensFromFees`.\n const sourceHref = getTxUrl(chainId, transactionHash)\n const destHref = execution\n ? getTxUrl(destChain.id, execution.transactionHash)\n : undefined\n\n // Refetch current Across / Relay quotes for the same route so the \"Routing\"\n // step can show which provider was used. The historic provider isn't\n // stored server-side; the assumption is the route hasn't changed materially\n // and current quotes still name the same winning provider.\n const providerFees = useProviderFees(source, destChain, feeData, recipient)\n const breakdown =\n feeData && sourceSymbol\n ? buildFeeBreakdown(feeData, sourceSymbol, providerFees.fees)\n : null\n const [feeOpen, setFeeOpen] = useState(false)\n\n const date = formatDate(deposit.createdAt)\n\n return (\n // No `h-full` — the page takes its natural content height so the\n // Screen's scroll container can activate scrolling when the fee\n // breakdown is expanded and content exceeds the viewport.\n <div className=\"zd:flex zd:w-full zd:flex-col zd:gap-3 zd:pt-4 zd:pb-6\">\n <ArrowCardPair\n topCard={\n <InfoCard\n title={sourceHeadline}\n {...(sourceTokenLogo && { imageSource: sourceTokenLogo })}\n {...(sourceChainLogo && { chainIconUrl: sourceChainLogo })}\n />\n }\n bottomCard={\n <InfoCard\n title={destHeadline}\n {...(destTokenLogo && { imageSource: destTokenLogo })}\n {...(destChainLogo && { chainIconUrl: destChainLogo })}\n />\n }\n />\n\n <Section title=\"Transaction details\">\n <DataRow\n label=\"From network\"\n value={\n <NetworkValue\n name={sourceChain?.name ?? '—'}\n {...(sourceChainLogo && { logoUrl: sourceChainLogo })}\n />\n }\n />\n <DataRow\n label=\"To network\"\n value={\n <NetworkValue\n name={destChain.name}\n {...(destChainLogo && { logoUrl: destChainLogo })}\n />\n }\n />\n {date && <DataRow label=\"Date\" value={date} />}\n {breakdown && (\n <DataRow\n label=\"Total fee\"\n value={<FeeSummary breakdown={breakdown} />}\n info\n infoTooltip={FEE_INFO.estimatedFee}\n trailing={\n <button\n type=\"button\"\n onClick={() => setFeeOpen((prev) => !prev)}\n aria-expanded={feeOpen}\n aria-controls={FEE_PANEL_ID}\n aria-label={feeOpen ? 'Hide fee details' : 'Show fee details'}\n className=\"zd:inline-flex zd:items-center zd:justify-center zd:cursor-pointer\"\n >\n <Icon\n name={feeOpen ? 'chevronUp' : 'chevronDown'}\n className=\"zd:w-3.5 zd:h-3.5 zd:text-greyScale\"\n />\n </button>\n }\n />\n )}\n {feeOpen && breakdown && (\n <section id={FEE_PANEL_ID} aria-label=\"Fee breakdown\">\n <FeeBreakdownRows breakdown={breakdown} />\n </section>\n )}\n </Section>\n\n <Section title=\"Transaction Progress\">\n <ProgressStep\n label=\"Deposit detected\"\n info={FEE_INFO.detected}\n status=\"done\"\n right={\n <TxLink\n label={truncateAddress(transactionHash)}\n href={sourceHref}\n />\n }\n />\n <ProgressStep\n label=\"Routing\"\n info={FEE_INFO.routing}\n // Routing was at least attempted whenever we've left the initial\n // detected stage — including the failed path (failure implies the\n // route was tried), so mark it done there too rather than showing\n // an inert pending circle above the \"Failed\" row.\n status={\n stage === 'bridging' || stage === 'completed' || failed\n ? 'done'\n : 'pending'\n }\n right={\n providerFees.loading ? (\n <ProviderChipSkeleton />\n ) : breakdown?.provider ? (\n <ProviderChip provider={breakdown.provider} />\n ) : (\n <StatusText>—</StatusText>\n )\n }\n />\n {failed ? (\n <ProgressStep\n label=\"Failed\"\n info={FEE_INFO.failed}\n status=\"failed\"\n isLast\n right={<StatusText tone=\"error\">Error</StatusText>}\n />\n ) : (\n <ProgressStep\n label=\"Completed\"\n info={FEE_INFO.completed}\n status={stage === 'completed' ? 'done' : 'pending'}\n isLast\n right={\n execution ? (\n <TxLink\n label={truncateAddress(execution.transactionHash)}\n href={destHref}\n />\n ) : (\n <StatusText>Pending</StatusText>\n )\n }\n />\n )}\n </Section>\n </div>\n )\n}\n\nfunction NetworkValue({ name, logoUrl }: { name: string; logoUrl?: string }) {\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1.5\">\n <Text className=\"zd:whitespace-nowrap zd:font-medium\">{name}</Text>\n {logoUrl && (\n <img src={logoUrl} alt=\"\" className=\"zd:size-4 zd:rounded-full\" />\n )}\n </span>\n )\n}\n\nfunction TxLink({ label, href }: { label: string; href?: string | undefined }) {\n if (!href) {\n return (\n <span className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale\">\n {label}\n </span>\n )\n }\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale zd:hover:text-solarOrange\"\n >\n {label}\n <Icon\n name=\"export\"\n className=\"zd:size-3 zd:text-solarOrange\"\n aria-hidden\n />\n </a>\n )\n}\n\n/** Small right-aligned status text used in `ProgressStep` — dedups the\n * \"Pending\" / \"—\" / \"Error\" placeholders that all share the same size class\n * and only differ by tone. */\nfunction StatusText({\n children,\n tone = 'muted',\n}: {\n children: string\n tone?: 'muted' | 'error'\n}) {\n return (\n <Text\n className={cn(\n 'zd:text-body3',\n tone === 'error' ? 'zd:text-negative' : 'zd:text-greyScale/50',\n )}\n >\n {children}\n </Text>\n )\n}\n\nfunction ProviderChip({ provider }: { provider: string }) {\n const iconUrl = PROVIDER_ICONS[provider]\n return (\n <span\n className=\"zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale\"\n title={`Quoted via ${provider}`}\n >\n {provider}\n {iconUrl && (\n <img\n src={iconUrl}\n alt=\"\"\n aria-hidden\n className=\"zd:size-3.5 zd:shrink-0 zd:rounded-sm zd:object-cover\"\n />\n )}\n </span>\n )\n}\n\n/** Skeleton placeholder shown while `useProviderFees` is fetching quotes. */\nfunction ProviderChipSkeleton() {\n return (\n <output\n aria-busy=\"true\"\n aria-label=\"Loading provider\"\n className=\"zd:block zd:h-4 zd:w-16 zd:rounded-full zd:bg-greyScale/15 zd:animate-skel-pulse\"\n />\n )\n}\n","import { PoweredBy, Screen, TopNav } from '@zerodev/react-ui'\nimport type { DepositedToken } from '@zerodev/smart-routing-address'\nimport { type ReactNode, useEffect, useState } from 'react'\nimport type { Address } from 'viem'\nimport { QrSheet } from '../components/QrSheet'\nimport { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'\nimport { Deposit } from './Deposit'\nimport { PastDeposits } from './PastDeposits'\nimport { TransactionDetails } from './TransactionDetails'\n\n/**\n * Steps rendered by `SmartRoutingAddress`. Sub-views advance/rewind local\n * step state; the widget owns navigation and the `TopNav` chrome accordingly.\n */\nexport type SmartRoutingAddressStep = 'deposit' | 'past' | 'transaction'\n\nconst TITLE_BY_STEP: Record<SmartRoutingAddressStep, string> = {\n deposit: 'Deposit funds',\n past: 'Past deposits',\n transaction: 'Transaction details',\n}\n\nfunction renderStep(\n step: SmartRoutingAddressStep,\n {\n onQrClick,\n onViewPastDeposits,\n onSelectDeposit,\n selectedDeposit,\n }: {\n onQrClick?: (() => void) | undefined\n onViewPastDeposits?: (() => void) | undefined\n onSelectDeposit?: ((deposit: DepositedToken) => void) | undefined\n selectedDeposit?: DepositedToken | undefined\n },\n): ReactNode {\n switch (step) {\n case 'deposit':\n return (\n <Deposit\n {...(onQrClick && { onQrClick })}\n {...(onViewPastDeposits && { onViewPastDeposits })}\n {...(onSelectDeposit && { onSelectDeposit })}\n />\n )\n case 'past':\n return <PastDeposits {...(onSelectDeposit && { onSelectDeposit })} />\n case 'transaction':\n // `selectedDeposit` is set by the past-deposits row-click handler\n // before advancing the step, so this branch always has a deposit.\n return selectedDeposit ? (\n <TransactionDetails deposit={selectedDeposit} />\n ) : null\n default:\n return null\n }\n}\n\n/**\n * The Figma \"Deposit funds\" flow (`17634:104268` / `18721:96092`).\n *\n * Owns the shared `Screen` + `TopNav` chrome and delegates the body to the\n * current page in this directory. Mirrors the layout of `wallet-react-ui`'s\n * `auth/index.tsx` and `signing/index.tsx`.\n *\n * Wrap the subtree with `<SmartRoutingAddressProvider config={…}>` first.\n */\nexport interface SmartRoutingAddressProps {\n /** Recipient address the smart routing address is created for. */\n recipient: Address\n /** Called when the top-right × close button is clicked. */\n onClose: () => void\n className?: string\n size?: 'sm' | 'md' | 'lg'\n}\n\nexport function SmartRoutingAddress({\n recipient,\n onClose,\n className,\n size,\n}: SmartRoutingAddressProps) {\n const { addressState, getOrCreateAddress } = useSmartRoutingAddressContext()\n const [qrOpen, setQrOpen] = useState(false)\n const [step, setStep] = useState<SmartRoutingAddressStep>('deposit')\n const [selectedDeposit, setSelectedDeposit] = useState<\n DepositedToken | undefined\n >(undefined)\n\n useEffect(() => {\n // Errors surface via `addressState.status === 'error'`; swallow rejection\n // here so React doesn't warn about an unhandled promise.\n getOrCreateAddress(recipient).catch(() => {})\n }, [recipient, getOrCreateAddress])\n\n const title = TITLE_BY_STEP[step]\n\n const address =\n addressState.status === 'success' ? addressState.address : undefined\n\n // The QR button in AddressDisplay only exists once the address has resolved,\n // but guard here too so we don't render an empty QrSheet.\n const handleQrClick = address ? () => setQrOpen(true) : undefined\n\n const handleCopy = async () => {\n if (!address) return\n try {\n await navigator.clipboard.writeText(address)\n } catch {\n // Clipboard can reject on insecure contexts / permissions; the visual\n // \"copied\" state isn't in the spec yet, so just close and swallow.\n }\n setQrOpen(false)\n }\n\n // Sub-view chrome — sub-views swap the left slot for a back chevron that\n // returns to the parent step. Root (deposit) step has no left button\n // (TopNav renders a spacer so the title stays centred).\n const goBack =\n step === 'transaction'\n ? () => setStep('past')\n : step === 'past'\n ? () => setStep('deposit')\n : undefined\n\n return (\n <Screen\n className={className}\n {...(size && { size })}\n topNav={\n <TopNav\n title={title}\n {...(goBack && {\n onLeftButtonClick: goBack,\n leftButtonIcon: 'chevronLeft' as const,\n })}\n onRightButtonClick={onClose}\n />\n }\n footer={<PoweredBy />}\n >\n {renderStep(step, {\n onQrClick: handleQrClick,\n onViewPastDeposits: () => setStep('past'),\n onSelectDeposit: (deposit) => {\n setSelectedDeposit(deposit)\n setStep('transaction')\n },\n selectedDeposit,\n })}\n {/* QrSheet renders itself via `useScreenOverlayContainer()` + portal, so\n it stays inside the card frame while composing at this level rather\n than being hoisted into `Screen`'s API. Mounted whenever an address\n exists so Radix Dialog owns the open/close animation lifecycle. */}\n {address && (\n <QrSheet\n open={qrOpen}\n onOpenChange={setQrOpen}\n address={address}\n onCopy={handleCopy}\n />\n )}\n </Screen>\n )\n}\n"],"names":["DEFAULT_POLLING_INTERVAL_MS","DEFAULT_FILL_TIME_SECONDS","SUPPORTED_CHAINS","mainnet","optimism","arbitrum","polygon","plasma","base","celo","mode","monad","blast","bsc","flowMainnet","hyperEvm","linea","ink","megaeth","scroll","soneium","tempo","unichain","worldchain","zora","CHAINS_BY_ID","chain","UNSUPPORTED_TOKEN_TYPES","DEFAULT_SOURCE_TOKENS","SUPPORTED_TOKENS","chainId","tokens","t","tokenType","getChainById","supported","c","getTxUrl","transactionHash","explorer","_b","_a","resolveTokenAddress","zeroAddress","tokenAddressMatches","token","address","isAddressEqual","findFeeDataByToken","estimatedFees","chainFees","fee","data","findFeeData","resolveVersion","config","SMART_ROUTING_ADDRESS_V0_2_1","resolveBaseUrl","SMART_ROUTING_ADDRESS_SERVER_URL","resolveDestChain","isTokenOnChain","resolveSourceTokens","destChainId","source","sourceTokensFromFees","uniqueTokenTypes","sources","resolveActions","recipient","erc20Call","createCall","FLEX","erc20Abi","nativeCall","getSourceTokenSymbol","SmartRoutingAddressContext","createContext","useSmartRoutingAddressContext","context","useContext","SmartRoutingAddressProvider","children","addressState","setAddressState","useState","setRecipient","activeRoute","setActiveRoute","pendingRef","useRef","recipientRef","genRef","configRef","getOrCreateAddress","useCallback","nextRecipient","gen","request","baseUrl","result","createSmartRoutingAddress","error","err","retry","current","value","useMemo","jsx","useCreateSmartRoutingAddress","useSmartRoutingAddress","QrSheet","open","onOpenChange","onCopy","BottomSheet","BottomSheetContent","BottomSheetTitle","jsxs","Text","QrCode","Button","BottomSheetClose","LoadingCard","text","className","rest","Wrapper","cn","Icon","AddressDisplayUI","loadingText","onQrClick","AddressDisplay","status","ErrorRetryCard","message","onRetry","busy","retryLabel","CHAIN_ARBITRUM","CHAIN_BASE","CHAIN_BSC","CHAIN_ETHEREUM","CHAIN_HYPERLIQUID","CHAIN_LINEA","CHAIN_MONAD","CHAIN_OPTIMISM","CHAIN_POLYGON","CHAIN_SCROLL","CHAIN_SONEIUM","CHAIN_UNICHAIN","CHAIN_WORLDCHAIN","CHAIN_BLAST","CHAIN_INK","CHAIN_MODE","CHAIN_TEMPO","CHAIN_ZORA","TOKEN_ETH","TOKEN_EURC","TOKEN_WBTC","TOKEN_DAI","TOKEN_USDC","TOKEN_USDT","CHAIN_ICONS","sepolia","arbitrumSepolia","baseSepolia","optimismSepolia","TOKEN_ICONS","PROVIDER_ACROSS","PROVIDER_RELAY","PROVIDER_ICONS","displayFractionDigits","formatDisplayAmount","decimals","round","amount","formatUnits","digits","factor","truncateAddress","formatSlippage","basisPoints","formatDuration","seconds","STABLE_SYMBOLS","formatRelativeTime","iso","now","then","minutes","hours","days","months","sum","values","total","v","AcrossLegSchema","z","AcrossSuggestedFeesSchema","E18","acrossPct","raw","tokenUsd","symbol","parseAcrossFees","res","leg","key","label","kind","accent","lines","l","RelayFeeSchema","RelayQuoteSchema","usdOf","parseRelayFees","fees","push","usd","totalUsd","buildFeeBreakdown","feeData","provider","sraUsd","bridgeUsd","feeToken","executionUsd","showTokenFallback","formatFeePct","pct","formatFeeUsd","FEE_INFO","PROVIDER_URLS","LiveValue","loading","flashKey","FeeSummary","breakdown","ProviderValue","url","iconUrl","inner","Fragment","InfoMark","info","Tooltip","LineValue","line","BreakdownRow","FeeBreakdownRows","getDepositKey","deposit","getDepositStage","getNewDeposits","deposits","baseline","STATUS_COLOR","TxnItem","destAmount","href","timestamp","sourceTokenIconUrl","sourceChainIconUrl","destTokenIconUrl","destChainIconUrl","sourceChainName","destChainName","detailed","badgeIconUrl","TokenMark","RouteArrow","ChainTag","AddressLine","tokenIconUrl","name","STAGE_TO_STATUS","PendingDeposits","onSelectDeposit","destChain","destChainLogo","sourceSymbol","sourceTokenLogo","sourceChainLogo","destTokenLogo","amountLabel","row","INITIAL_STATE","useDepositStatus","enabled","pollingInterval","state","setState","pollRef","useEffect","cancelled","poll","requestGen","getSmartRoutingAddressStatus","previous","intervalId","refetch","useNewDeposits","ready","baselineRef","ACROSS_API","RELAY_API","QUOTE_USER","acrossToken","relayToken","fetchAcross","route","signal","inputToken","outputToken","params","json","parsed","fetchRelay","originCurrency","destinationCurrency","bestRoute","routes","available","r","withUsd","best","useProviderFees","setBreakdown","setLoading","sourceChainId","minDeposit","controller","safe","p","across","relay","chosen","SUBTITLE","FULL_ROW_PANEL_STYLE","Deposit","onViewPastDeposits","feeOpen","setFeeOpen","retrying","setRetrying","success","srcTokens","selectedTokenType","setSelectedTokenType","selectedChainId","setSelectedChainId","fallback","hasLoaded","depositsError","refetchDeposits","newDeposits","pastDepositsCount","tokenSymbol","tokenLogo","fillTime","providerFees","uniqueTokens","seen","out","availableChains","slippage","minDepositAmount","feeFlashKey","pickerDisabled","addressError","noRoutesError","pollingError","errorMessage","handleRetry","ArrowCardPair","CardTitle","PillRow","Select","id","SelectTrigger","Pill","SelectIcon","SelectContent","i","chainCount","logo","SelectItem","TokenListItem","DataRow","prev","CopyAddressButton","WrappedPressable","PAST_DEPOSITS_CARD","PastDepositsRow","copied","setCopied","handleCopy","count","left","right","dayStart","d","groupLabel","today","day","groupByDay","buckets","sortKey","existing","a","b","PastDeposits","groups","group","destAmountLabel","useLiveDeposit","initial","targetHash","FEE_PANEL_ID","formatDate","ts","TransactionDetails","initialDeposit","sourceChain","stage","execution","outAmountRaw","failed","sourceHeadline","destHeadline","sourceHref","destHref","date","InfoCard","Section","NetworkValue","ProgressStep","TxLink","ProviderChipSkeleton","ProviderChip","StatusText","logoUrl","tone","TITLE_BY_STEP","renderStep","step","selectedDeposit","SmartRoutingAddress","onClose","size","qrOpen","setQrOpen","setStep","setSelectedDeposit","title","handleQrClick","goBack","Screen","TopNav","PoweredBy"],"mappings":"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"}
|