Skip to main content
DaimoWithdrawal is a pre-built React flow for sending USDC or USDT to a recipient. It collects the recipient and destination first, asks your server to create an open-amount session, then funds that session from an injected wallet or a host-controlled wallet. The component provides:
  • EVM addresses, Solana addresses, and ENS recipients
  • saved recipient routes scoped to the authenticated user
  • supported stablecoin and destination-network selection
  • wallet token/balance selection and amount entry
  • session polling and started/completed lifecycle callbacks
The current destination picker supports USDC on Arbitrum, Base, BNB Smart Chain, Ethereum, HyperEVM, Optimism, Polygon, and Solana. It supports USDT on the same EVM networks except HyperEVM. Solana destinations currently support USDC only.

Install and provide the client

Server callback

ENS resolution is built in. The only required backend callback is createSession, which runs from browser code and must call your authenticated backend. Keep your Daimo API key on the server.

ENS resolution

DaimoWithdrawal trims and ENSIP-15-normalizes ENS names, then resolves them through the Daimo API URL configured on DaimoSDKProvider. Resolution always uses Ethereum mainnet, regardless of the selected destination network. Saved ENS recipients are resolved again before reuse so session creation receives the same concrete address the user reviewed. Most integrations should use this zero-configuration default. If your integration intentionally needs a different resolver, pass resolveEns:
The explicit callback receives the normalized name and takes precedence over Daimo resolution. Keep paid RPC credentials behind your authenticated backend; never include them in the browser bundle. Your session endpoint should validate the destination against isDaimoWithdrawalDestination, then call POST /v1/sessions with that destination and no amountUnits. Set display.paymentOptions to ["AutoconnectInjectedWallets"] for injected-wallet funding or ["AllAddresses"] for manual funding. Return only sessionId and clientSecret to the component.
Never place a Daimo API key in the browser bundle. Bind saved-recipient contactStorageScope to a stable authenticated user or account ID; do not use a shared constant.

Embedded or modal presentation

DaimoWithdrawal renders inline by default. Set embedded={false} and mount it only while open to use the SDK’s floating modal instead of building another drawer around the embedded component:
The modal owns its backdrop and close button. Unmount and remount it to start a fresh recipient flow.

Injected-wallet funding

The SDK discovers a browser wallet, shows its token balances, and submits the selected EVM or Solana transaction. If your app already owns an EVM provider, pass both the connected address and that scoped provider.
Omit connectToAddress and evmProvider to let the SDK discover and connect a wallet. The default walletSource="all" includes EVM and Solana funding; walletSource="evm" excludes Solana-only providers.

Manual funding

Manual funding is for embedded, smart-account, custodial, or sponsored wallets whose transaction lifecycle belongs to your application. The SDK never calls eth_sendTransaction or any other provider transaction method in manual mode. It invokes sendManualTransaction and waits for your promise instead. There are three amount variants.

Fixed amount

Pass a positive decimal amountUnits. After destination review, the SDK creates the open-amount session and immediately invokes the adapter. Fixed amount and connectToAddress are mutually exclusive.

Generic amount entry

Omit both amountUnits and connectToAddress. The SDK shows a plain USD input that accepts $0.01+ with up to two decimal places. It deliberately shows no token artwork, balance, or Max action. Your adapter owns source network, token, and decimal-to-raw conversion.

Address-aware token and balance selection

Omit amountUnits and pass the embedded wallet’s EVM address. The SDK uses the address only to fetch wallet options, shows supported tokens and balances, and always shows Max on the wallet amount page. It does not connect to the wallet.
sourceTokenFilter removes unsupported balances before the selector renders. Use it when the host wallet supports only particular chains or token-transfer commands; do not hide rows with CSS. The adapter must still validate source before submitting because the predicate is a UI constraint, not authorization. evmProvider is not accepted by any manual variant.
World Mini Apps should map every supported World Chain payment token (for example USDC, WLD, EURC, WARS, WCOP, WMXN, WBRL, WPEN, and WCLP) to the corresponding MiniKit Tokens value and call MiniKit.pay. A direct ERC-20 call through sendTransaction requires that contract to be allowlisted and otherwise fails with invalid_contract. Filter out non-World-Chain and non-MiniKit tokens with sourceTokenFilter.

Manual adapter contract

amountUnits is the exact fixed or user-entered decimal string. In the address-aware variant, source is always present: source.address is the address you supplied, source.token contains the selected chain, token address, symbol, and decimals, and source.amount is the exact raw, balance-capped token amount. In the other variants, source is omitted. Resolve the adapter only after the transaction has been submitted or durably handed off. Return txHash when available so polling can detect it sooner. Reject only when repeating the same transfer is safe: the retry action invokes the adapter again for the same session and hidden receiver. Concurrent calls and calls after a successful adapter result are deduplicated.

Recipient and session lifecycle

The flow is recipient-first:
  1. The user enters an EVM address, Solana address, or ENS name, or selects a saved recipient.
  2. The user chooses USDC or USDT and a compatible destination network.
  3. The SDK asks your server to create an open-amount session.
  4. The injected wallet or manual adapter submits funds to the hidden receiver.
  5. The SDK polls until the session succeeds, bounces, or expires.
Saved recipients include the identifier, destination asset, and network. ENS is resolved again before reuse, so the reviewed address stays current. The component calls onPaymentStarted once after submission and onPaymentCompleted once when the session reaches succeeded. Typical session progression is waiting_paymentprocessingsucceeded. bounced means delivery failed and funds were returned; expired means no transfer was detected before the session deadline. Amount choice does not alter the session contract: all withdrawal sessions remain open-amount.