import { Address, Hex, WalletClient, PublicClient, Chain } from 'viem'; interface SafeTransactionRequest { chainId: number; safeAddress: Address; safeTxHash: Hex; typedData: { domain: { chainId: number; verifyingContract: Address; }; types: typeof SAFE_TX_TYPES; primaryType: "SafeTx"; message: { to: Address; value: bigint; data: Hex; operation: number; safeTxGas: bigint; baseGas: bigint; gasPrice: bigint; gasToken: Address; refundReceiver: Address; nonce: bigint; }; }; } declare const SAFE_TX_TYPES: { readonly SafeTx: readonly [{ readonly name: "to"; readonly type: "address"; }, { readonly name: "value"; readonly type: "uint256"; }, { readonly name: "data"; readonly type: "bytes"; }, { readonly name: "operation"; readonly type: "uint8"; }, { readonly name: "safeTxGas"; readonly type: "uint256"; }, { readonly name: "baseGas"; readonly type: "uint256"; }, { readonly name: "gasPrice"; readonly type: "uint256"; }, { readonly name: "gasToken"; readonly type: "address"; }, { readonly name: "refundReceiver"; readonly type: "address"; }, { readonly name: "nonce"; readonly type: "uint256"; }]; }; /** * Public config shape exposed on DepositModalProps. Each dapp defaults to * off — clients must explicitly opt in. */ interface DappImportsConfig { polymarket?: boolean; } /** * Consumer-supplied RPC URL overrides, scoped to a single modal instance (see * {@link RpcUrlsProvider}). Threaded into every client the modal builds — EVM * public clients (`public-client.ts`), the wallet adapter's transports * (`reown.tsx`), and the Solana connection (`solana.ts`). * * Keyed by the same `number | "solana"` chain identifier the rest of the modal * uses (see `core/constants.ts`), so a single `rpcUrls` prop covers every * chain — EVM mainnets, Polygon (137, also feeds Polymarket reads), HyperEVM * (999), and Solana. */ type ChainKey = number | "solana"; type RpcUrlMap = Partial>; type Caip2ChainId = `eip155:${number}` | `solana:${string}`; type ChainId = number | "solana" | Caip2ChainId; interface DepositModalTheme { mode?: "light" | "dark"; radius?: "none" | "sm" | "md" | "lg" | "full"; fontColor?: string; iconColor?: string; ctaColor?: string; ctaHoverColor?: string; borderColor?: string; backgroundColor?: string; } interface DepositModalUIConfig { showBackButton?: boolean; showHistoryButton?: boolean; maxDepositUsd?: number; minDepositUsd?: number; /** * When true the network/protocol fee is sponsored — the Review / Processing / * Success / Failure screens render the fee line-through and surface a * tooltip on the info icon explaining the sponsorship. */ feeSponsored?: boolean; /** * Custom tooltip copy for the fee info icon. Defaults to a generic * "Fees are sponsored" / "Fees apply" message based on `feeSponsored`. */ feeTooltip?: string; /** * Run the liquidity check before the amount step continues. Off by default: * the check adds an orchestrator round-trip per continue and its low/unavailable * result isn't surfaced anyway, so skipping it makes the route faster. Enable * to gate continue on liquidity and show the unavailable/check-failed warning. */ checkLiquidity?: boolean; } interface ConnectedEventData { address: Address; smartAccount: Address; } interface DepositSubmittedEventData { txHash: string; sourceChain: ChainId | "unknown"; amount: string; } interface DepositCompleteEventData { txHash: string; destinationTxHash?: string; amount: string; sourceChain: ChainId | "unknown"; sourceToken?: string; targetChain: number | "solana"; targetToken: string; } interface DepositFailedEventData { txHash: string; error?: string; } interface WithdrawSubmittedEventData { txHash: Hex; sourceChain: number; amount: string; safeAddress: Address; } interface WithdrawCompleteEventData { txHash: Hex; destinationTxHash?: Hex; amount: string; sourceChain: number; sourceToken: Address; targetChain: number; targetToken: Address; } interface WithdrawFailedEventData { txHash: Hex; error?: string; } interface ErrorEventData { message: string; code?: string; } interface OutputTokenRule { match: { chain?: string; token?: string; symbol?: string; }; outputToken: string; } interface RouteConfig { sourceChains?: number[]; sourceTokens?: string[]; } interface FiatPaymentMethodOption { /** * Swapped's `payment_group` value (e.g. `creditcard`, `apple-pay`, * `bank-transfer`) from GET /api/v1/merchant/get_payment_methods. This exact * value is what the widget URL's `method` param prepopulates from — Apple Pay * is `apple-pay`, not `applepay`. */ method: string; /** Row label shown in ConnectStep. */ label: string; /** Optional sublabel under the row. */ sublabel?: string; /** Optional icon name: `card` | `apple` | `bank`. Defaults to `card`. */ icon?: "card" | "apple" | "bank"; } interface DepositModalProps { dappWalletClient?: WalletClient | null; dappPublicClient?: PublicClient | null; dappAddress?: Address | null; targetChain: Chain | number | "solana"; targetToken: Address | string; isOpen: boolean; onClose: () => void; inline?: boolean; closeOnOverlayClick?: boolean; sourceChain?: Chain | number; sourceToken?: Address; /** * Pre-fills the deposit amount. Either a USD-denominated number string * (e.g. "25") or the case-insensitive sentinel `"max"`, which fills the * full available balance once it loads (same as the Max preset). */ defaultAmount?: string; recipient: Address | string; /** * The user's current in-app balance, in USD, as the consuming app displays * it. When provided, the amount screen shows a "Balance after deposit" row * (`appBalanceUsd + amount`) so the user sees their post-deposit app * balance. The row is hidden when this is omitted. */ appBalanceUsd?: number; postBridgeActions?: PostBridgeAction[]; outputTokenRules?: OutputTokenRule[]; rejectUnmapped?: boolean; backendUrl?: string; /** * Per-chain RPC URL overrides, keyed by EVM chain id plus the literal * `"solana"` key. Applied everywhere the modal reads chain state — EVM * public clients, the connected wallet's transports (avoiding the * rate-limited public defaults), Polygon/Polymarket reads, HyperEVM (999), * and the Solana connection. Chains left unset use their default RPC. */ rpcUrls?: RpcUrlMap; rhinestoneApiKey?: string; signerAddress?: Address; sessionChainIds?: number[]; forceRegister?: boolean; reownAppId?: string; enableSolana?: boolean; /** * Enable importing balances from third-party dapps. Each dapp defaults to * off — clients must explicitly opt in. When a dapp is enabled and the * connected wallet has a balance there, a new row appears on the deposit * entry screen. */ dappImports?: DappImportsConfig; /** * Open the modal pre-routed into a dapp-import provider, skipping the * deposit-method home screen. Must name an enabled `dappImports` key * (e.g. "polymarket"); disabled/unknown values are a no-op. While the * provider's balances are checked the modal shows a loading skeleton; * if the flow turns out to be unreachable (no account, no balance, no * wallet) it falls back to the home screen. */ initialDappImport?: keyof DappImportsConfig; /** Show fiat on-ramp option(s) that embed Swapped's iframe. Default: false. */ enableFiatOnramp?: boolean; /** Show the Transfer Crypto / QR row. Default: true. */ enableQrTransfer?: boolean; /** * One row per Swapped payment method (Pay with Card / Apple Pay / Bank * Transfer). When set, replaces the generic "Pay with Card" row. */ fiatOnrampMethods?: FiatPaymentMethodOption[]; /** * Show a "Connect exchange" row that opens Swapped Connect — the user * picks their CEX (Coinbase, Binance, Kraken…) or wallet inside the iframe * and Swapped pulls the crypto on-chain to the smart account. Default: false. */ enableExchangeConnect?: boolean; onRequestConnect?: () => void; theme?: DepositModalTheme; uiConfig?: DepositModalUIConfig; allowedRoutes?: RouteConfig; className?: string; onReady?: () => void; /** Discriminated stream of deposit lifecycle transitions. */ onLifecycle?: (event: DepositLifecycleEvent) => void; onEvent?: (event: DepositAnalyticsEvent) => void; onError?: (data: ErrorEventData) => void; debug?: boolean; } interface WithdrawModalProps { dappWalletClient?: WalletClient | null; dappPublicClient?: PublicClient | null; dappAddress?: Address | null; safeAddress: Address; sourceChain: Chain | number; sourceToken: Address; targetChain: Chain | number; targetToken: Address; recipient?: Address; defaultAmount?: string; isOpen: boolean; onClose: () => void; inline?: boolean; closeOnOverlayClick?: boolean; allowedRoutes?: RouteConfig; backendUrl?: string; /** * Per-chain RPC URL overrides, keyed by EVM chain id plus the literal * `"solana"` key. Applied to every chain read (EVM public clients and the * connected wallet's transports). Chains left unset use their default RPC. */ rpcUrls?: RpcUrlMap; rhinestoneApiKey?: string; signerAddress?: Address; sessionChainIds?: number[]; forceRegister?: boolean; reownAppId?: string; onSignTransaction?: (request: SafeTransactionRequest) => Promise<{ signature: Hex; }>; onRequestConnect?: () => void; theme?: DepositModalTheme; uiConfig?: DepositModalUIConfig; className?: string; onReady?: () => void; /** Discriminated stream of withdraw lifecycle transitions. */ onLifecycle?: (event: WithdrawLifecycleEvent) => void; onEvent?: (event: WithdrawAnalyticsEvent) => void; onError?: (data: ErrorEventData) => void; debug?: boolean; } interface AssetOption { id: string; chainId: number; token: Address; symbol: string; name: string; decimals: number; balance?: string; balanceUsd?: number; } interface OrderBookSwapAction { type: "orderbook-swap"; contract: Address; outputToken: Address; } type PostBridgeAction = OrderBookSwapAction; /** * Discriminated union covering every deposit flow state transition the * consumer can observe. Consumers handle additions in a single switch; the * modal can add new event variants without changing the prop surface. */ type DepositLifecycleEvent = { type: "connected"; address: Address; smartAccount: Address; } | { type: "submitted"; txHash: string; sourceChain: ChainId | "unknown"; /** Source-token base units (e.g. "1100000" for 1.10 USDC). */ amount: string; /** * Decimals of the source token, for converting `amount` to a * human-readable value. Omitted when the token is not recognised * (e.g. a QR deposit of an unlisted token). */ sourceDecimals?: number; /** * USD equivalent of the deposit as entered in the modal (token units * for unpriced non-stablecoins). Omitted for flows without an amount * input (QR transfer, fiat onramp, exchange connect). */ amountUsd?: string; } | { type: "complete"; txHash: string; destinationTxHash?: string; /** Source-token base units (e.g. "1100000" for 1.10 USDC). */ amount: string; sourceChain: ChainId | "unknown"; sourceToken?: string; /** * Decimals of the source token, for converting `amount` to a * human-readable value. Omitted when the token is not recognised * (e.g. a QR deposit of an unlisted token). */ sourceDecimals?: number; /** * USD equivalent of the deposit as entered in the modal (token units * for unpriced non-stablecoins). Omitted for flows without an amount * input (QR transfer, fiat onramp, exchange connect). */ amountUsd?: string; targetChain: number | "solana"; targetToken: string; } | { type: "failed"; txHash: string; error?: string; } | { type: "balance-changed"; totalUsd: number; } | { type: "smart-account-changed"; evm: Address | null; solana: string | null; }; type WithdrawLifecycleEvent = { type: "connected"; address: Address; smartAccount: Address; } | { type: "submitted"; txHash: Hex; sourceChain: number; amount: string; safeAddress: Address; } | { type: "complete"; txHash: Hex; destinationTxHash?: Hex; amount: string; sourceChain: number; sourceToken: Address; targetChain: number; targetToken: Address; } | { type: "failed"; txHash: Hex; error?: string; }; /** * Telemetry events fired when screens open or CTAs are clicked. * Distinct from {@link DepositLifecycleEvent}, which tracks transaction state. */ type DepositAnalyticsEvent = { type: "deposit_modal_connected_wallet_select_source_open"; total_balance_in_external_wallet: number | null; pred_balance: number | null; } | { type: "deposit_modal_connected_wallet_select_source_cta_click"; total_balance_in_external_wallet: number | null; pred_balance: number | null; cta_name: "token_selected"; token_name: string; token_balance: string; } | { type: "deposit_modal_transfer_crypto_open"; default_chain: string; default_token: string; pred_balance: number | null; } | { type: "deposit_modal_transfer_crypto_cta_click"; default_chain: string; default_token: string; pred_balance: number | null; cta_name: "copy"; } | { type: "deposit_modal_connected_wallet_enter_value_open"; send_token: string; receive_token: string; pred_balance: number | null; } | { type: "deposit_modal_connected_wallet_enter_value_cta_click"; send_token: string; receive_token: string; pred_balance: number | null; cta_name: "continue" | "25%" | "50%" | "75%" | "Max"; }; type WithdrawAnalyticsEvent = { type: "withdraw_modal_select_amount_open"; pred_balance: number | null; default_token: string; default_chain: string; } | { type: "withdraw_modal_select_amount_cta_click"; pred_balance: number | null; selected_token: string; selected_chain: string; amount: string; cta_name: "withdraw"; }; type ModalAnalyticsEvent = DepositAnalyticsEvent | WithdrawAnalyticsEvent; export type { AssetOption as A, ChainId as C, DappImportsConfig as D, ErrorEventData as E, ModalAnalyticsEvent as M, OrderBookSwapAction as O, PostBridgeAction as P, RouteConfig as R, SafeTransactionRequest as S, WithdrawAnalyticsEvent as W, ConnectedEventData as a, DepositAnalyticsEvent as b, DepositCompleteEventData as c, DepositFailedEventData as d, DepositLifecycleEvent as e, DepositModalProps as f, DepositModalTheme as g, DepositModalUIConfig as h, DepositSubmittedEventData as i, OutputTokenRule as j, RpcUrlMap as k, WithdrawCompleteEventData as l, WithdrawFailedEventData as m, WithdrawLifecycleEvent as n, WithdrawModalProps as o, WithdrawSubmittedEventData as p };