Skip to main content
The DepositModal component handles the full deposit flow: funding method, source chain and token selection, amount input, and cross-chain bridging.

Where the funds go

recipient (required) is the address that receives the bridged funds on the target chain. The deposit account is service-managed and derived from (recipient, targetChain, targetToken), so it doesn’t depend on which wallet the user pays from — or on a wallet existing at all. Changing the target changes the deposit address.

Connecting a wallet

Three options. The wallet is optional in all of them.

The modal connects one

The user connects their own wallet via Reown (WalletConnect). The modal manages the connection UI internally. Use this when your app has no wallet infrastructure of its own.

You supply one

Your app already has a wallet connected (via Privy, Dynamic, Turnkey, wagmi, or anything else). Pass its viem walletClient and the modal reuses that session instead of opening its own connect step. The modal reads the address off walletClient.account, so it cannot disagree with what your app thinks the user is connected as.
Pass onRequestConnect as well if your app needs to run a login flow when the user picks the wallet row before one is connected. To disconnect a wallet the modal connected, call the exported disconnectWallet(). It no-ops with a warning if @reown/appkit isn’t installed.
walletClient={undefined} is not the same as omitting the prop. Passing it while your wallet connects tells the modal one is coming, so it waits instead of deciding there is none.

No wallet at all

QR transfer, the fiat on-ramp and exchange connect need no wallet. Supply neither walletClient nor reownAppId and the modal opens straight into whichever funding methods you enabled.

Funding methods

Each method is a row on the modal’s home screen. When exactly one is enabled there is nothing to choose, and the modal opens directly into it. enableFiatOnramp and enableExchangeConnect require Swapped keys on your backend.

Regional payment methods

Leave fiatMethods unset and the modal personalizes the Cash options for the user’s region. It renders the method list the backend resolves — provider labels, icons, limits, and one optional Popular badge — and hands the exact method the user picked to the signed Swapped widget URL. This is the recommended default: which methods exist varies by country, and a hard-coded subset can only go stale. Personalization never blocks the flow. After 500 ms the standard card, bank transfer and Apple Pay rows render; a late regional result only replaces a picker the user hasn’t touched; and any failure keeps the complete default set. Resolving the country happens at your proxy — see regional payment methods for what it needs.
A known country with no available methods is authoritative merchant data, and the modal hides the Cash option entirely. That is different from an unresolved country, which renders the defaults.

Restricting fiat payment methods

fiatMethods is a boolean map keyed by Swapped payment_group. Passing it pins the Cash rows to that exact subset and opts this modal instance out of regional personalization.
Valid keys are creditcard, bank-transfer, and apple-pay. Enabling one does not advertise the others.
An empty or all-false fiatMethods offers no payment methods, not all of them. To offer everything, omit the prop — which also turns personalization back on.

Transfer configuration

Control the deposit destination and optionally pre-fill source parameters. For supported chains and tokens, see supported chains.

HyperCore destinations

HyperCore is targetChain: "hypercore:spot" (exported as HYPERCORE_SPOT_CAIP2) and accepts USDC only. The recipient can be an EOA or a smart account: deposits are credited through the MulticallHandler’s depositFor(recipient), which funds any address’s HyperCore account identically and never executes on the recipient. A HyperCore delivery names the venue it credits, because spot and perp margin are different balances. Spot is the only venue deposits are delivered to — perp margin cannot be moved back out without a signature the deposit account cannot produce.
targetChain: 1337 (HYPERCORE_CHAIN_ID) is the older spelling and still works. It resolves to the same venue and the same deposit address, so switching to HYPERCORE_SPOT_CAIP2 does not move your users’ accounts.
Earlier versions pre-screened the recipient’s bytecode and blocked a contract with an onError code of HYPERCORE_RECIPIENT_NOT_EOA. That rule never matched the orchestrator and is gone as of v0.9.0 — the code is no longer emitted.
HyperCore is also available as a deposit source in the QR / transfer flow, using the account’s own EVM address as the deposit address; a native Hyperliquid L1 spot transfer lands there.

Restricting which sources you accept

Which chains and tokens you accept is your project’s deposit whitelist, set via POST /setup and enforced by the processor when a deposit arrives. Configure it there rather than in the modal. To offer a restricted subset, use an API key whose whitelist matches.
Filtering the pickers client-side instead offers the user a source the processor then rejects, as soon as the two lists drift apart. The whitelist is the only place the restriction is enforced.

Account setup

The modal uses service-managed accounts: the deposit account is owned by Rhinestone and settles to your recipient, so there is no session key to configure and the user is never asked to sign during setup.

Destination token routing

Deliver a different final token depending on what the user deposits. Pass outputTokenRules to map source deposits — matched by chain, token address, or symbol — to the output token delivered on the target chain. Deposits that don’t match any rule fall back to targetToken, or are rejected when rejectUnmapped is true.
When several rules match the same deposit, the most specific one wins: chain + token outranks chain + symbol, which outranks token, then symbol, then chain alone. See token routing for the full rule semantics, priority order, and additional examples.

Migrate assets from other apps

Fund a deposit from balances the user already holds in a supported third-party app, with no manual transfer first. Opt in per provider via assetMigrations. See asset migrations for the provider list, Polymarket specifics, and the headless account lookup.

Package entry points

Everything is on the root entry; the subpaths exist so you only bundle what you use.

Display modes

By default, the component renders as a centered modal overlay with a backdrop. Set inline={true} to render it without the overlay, fitting into your page layout.
Backdrop closing is opt-in. Set closeOnOverlayClick={true} to close the modal when the user clicks outside it.

Props reference

Required

Wallet

Transfer

Funding

Account

Backend

Display

Callbacks

See status tracking for lifecycle event payloads.

Analytics

Content security policy

The modal loads chain, token and exchange logos from Rhinestone’s asset CDN. If your app sets an explicit img-src policy, it must allow the CDN:
A blocked image fails silently — the icon renders blank with no console error naming the policy, so this is easy to misread as a modal bug. Apps with no explicit img-src (or img-src *) need no change.
If you enable the fiat on-ramp or exchange connect, the modal embeds Swapped’s widget in an iframe, which needs frame-src:
The deposit, withdraw and claim modals all send session analytics to Rhinestone from the browser, so an explicit connect-src policy must allow the ingest origin:
That directive governs every request the modal makes, not just analytics — it must also list your own backendUrl origin and any endpoint you pass in rpcUrls. A policy assembled from the ingest origin alone breaks the modal.
A blocked ingest origin loses every event for the session, and the browser reports it to the modal as an ordinary network failure — nothing names the policy. The only signal is analytics_ingest_failure on onEvent, with reason: "network". Deposits are unaffected.