> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rhinestone.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deposit modal

> Configure the deposit modal for different wallet connection modes and deposit flows.

The `DepositModal` component handles the full deposit flow: wallet connection, source chain and token selection, amount input, and cross-chain bridging. It supports three wallet integration modes depending on how your app manages wallets.

## recipient vs dappAddress

Two props look similar but serve different purposes:

* **`recipient`** (required) — the address that receives the bridged funds on the target chain. This is a pure delivery target.
* **`dappAddress`** (embedded wallet & QR modes) — the address that owns the deposit. The modal uses it to derive the smart account and, by default, as the delivery target. It is the user's identity in the flow, not a destination.

In external wallet mode, the connected wallet is the owner, so only `recipient` is needed. In embedded and QR modes, you must pass `dappAddress` because the modal has no other way to know who owns the deposit.

## Integration modes

### External wallet

The user connects their own wallet via Reown (WalletConnect). The modal manages the wallet connection UI internally. Use this when your app doesn't have existing wallet infrastructure.

Pass a `reownAppId` to enable external wallet connection.

```tsx theme={null}
import { DepositModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";

<DepositModal
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  targetChain={8453}
  targetToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  recipient="0xYOUR_RECIPIENT_ADDRESS"
  reownAppId="YOUR_REOWN_PROJECT_ID"
  onLifecycle={(event) => event.type === "complete" && console.log(event)}
/>
```

### Embedded wallet

Your app manages the wallet (e.g. via Privy, Dynamic, or Turnkey) and passes the owner address to the modal. The modal skips its own wallet connection UI and uses your app's wallet context.

Pass `dappAddress` with the wallet owner address, and `onRequestConnect` to trigger your app's login flow when the modal needs a connected wallet.

```tsx theme={null}
import { DepositModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";

<DepositModal
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  targetChain={8453}
  targetToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  recipient="0xYOUR_RECIPIENT_ADDRESS"
  dappAddress={embeddedWalletAddress}
  onRequestConnect={() => login()}
  onLifecycle={(event) => event.type === "complete" && console.log(event)}
/>
```

### QR code deposit

The modal displays a deposit address and QR code. The user sends funds from any wallet externally — no wallet connection is required inside the modal.

Pass `dappAddress` without `onRequestConnect` or `reownAppId`.

```tsx theme={null}
import { DepositModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";

<DepositModal
  isOpen={isOpen}
  onClose={() => setIsOpen(false)}
  targetChain={8453}
  targetToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  recipient="0xYOUR_RECIPIENT_ADDRESS"
  dappAddress={ownerAddress}
  onLifecycle={(event) => event.type === "complete" && console.log(event)}
/>
```

## Transfer configuration

Control the deposit destination and optionally pre-fill source parameters.

| Prop               | Type                          | Required | Description                                                                                                                          |
| ------------------ | ----------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `targetChain`      | `Chain \| number \| "solana"` | Yes      | Destination chain (viem `Chain` object, chain ID, or `"solana"`)                                                                     |
| `targetToken`      | `Address \| string`           | Yes      | Token address on the destination chain (base58 mint for Solana)                                                                      |
| `recipient`        | `Address \| string`           | Yes      | Where funds are delivered on the target chain (base58 address for Solana)                                                            |
| `defaultAmount`    | `string`                      | No       | Pre-filled deposit amount. A USD number string (e.g. `"25"`) or the sentinel `"max"` to fill the full available balance.             |
| `sourceChain`      | `Chain \| number`             | No       | Pre-selected source chain                                                                                                            |
| `sourceToken`      | `Address`                     | No       | Pre-selected source token                                                                                                            |
| `allowedRoutes`    | `RouteConfig`                 | No       | Restrict available source chains and tokens                                                                                          |
| `outputTokenRules` | `OutputTokenRule[]`           | No       | Route the deposit to a different final token based on what the user deposited                                                        |
| `rejectUnmapped`   | `boolean`                     | No       | Reject deposits that don't match any routing rule instead of falling back to `targetToken`                                           |
| `appBalanceUsd`    | `number`                      | No       | The user's current in-app balance (USD). When set, the amount screen shows a "Balance after deposit" row (`appBalanceUsd + amount`). |

The `allowedRoutes` prop accepts `{ sourceChains?: number[], sourceTokens?: string[] }` to limit what the user can select. For supported chains and tokens, see [supported chains](/deposits/overview#supported-chains-and-tokens).

## Session configuration

Sessions allow the widget to execute bridging on behalf of the user's smart account. These props control session behavior.

| Prop              | Type       | Default              | Description                                                         |
| ----------------- | ---------- | -------------------- | ------------------------------------------------------------------- |
| `sessionChainIds` | `number[]` | All supported chains | Restrict which chains get session keys                              |
| `forceRegister`   | `boolean`  | `false`              | Force session re-creation even if the account is already registered |

## 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`.

```tsx theme={null}
<DepositModal
  // ...required props
  targetToken="0xFALLBACK_TOKEN_ADDRESS"
  outputTokenRules={[
    {
      match: { symbol: "USDC" },
      outputToken: "0x7f5c764cbc14f9669b88837ca1490cca17c31607",
    },
    {
      match: { symbol: "ETH" },
      outputToken: "0x4200000000000000000000000000000000000006",
    },
  ]}
/>
```

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](/deposits/api/account-registration#optional-token-routing) for the full rule semantics, priority order, and additional examples.

## Import from other apps

The modal can pull balances a user already holds in a supported third-party app
and fund the deposit from there — no manual transfer first. Each source is
**off by default**; opt in per source via `dappImports`.

```tsx theme={null}
<DepositModal
  // ...required props
  dappImports={{ polymarket: true }}
/>
```

When enabled and the connected wallet has a balance in that app, a new row
(e.g. "Transfer from Polymarket") appears on the deposit entry screen. The
user picks it, and the modal pulls the funds into their smart account and
bridges them to `targetChain` / `targetToken` like any other source.

### Polymarket

Set `dappImports={{ polymarket: true }}`. The modal looks up the connected
EOA's Polymarket proxy wallet on Polygon and surfaces any pUSD or USDC.e
balance. pUSD is unwrapped to USDC.e on the way out; USDC.e is what lands in the
smart account and what the orchestrator bridges from.

Polymarket exposes two wallet types and the modal handles both: some transfer
on-chain directly from the user's signed transaction, while others are relayed
through your configured [`backendUrl`](#backend). The default Rhinestone
backend handles both with no extra setup.

#### Open directly into Polymarket

To skip the deposit-method home screen and land the user straight on the
Polymarket transfer, pass `initialDappImport="polymarket"` alongside
`dappImports={{ polymarket: true }}`. While balances load the modal shows a
skeleton; if there's no account, no balance, or no connected wallet it falls
back to the home screen.

```tsx theme={null}
<DepositModal
  // ...required props
  dappImports={{ polymarket: true }}
  initialDappImport="polymarket"
/>
```

#### Headless account lookup

If you build your own UI and only need the data, the
`@rhinestone/deposit-modal/polymarket` subpath exports a headless
`getPolymarketAccount` — no React, modal, or wallet-connect code pulled into
your bundle. Give it the connected EOA and it returns the user's Polymarket
proxy wallet address and on-chain pUSD / USDC.e balances on Polygon.

```ts theme={null}
import { getPolymarketAccount } from "@rhinestone/deposit-modal/polymarket";

const account = await getPolymarketAccount({ eoa: connectedAddress });

if (account) {
  account.proxyWallet; // the user's Polymarket address on Polygon
  account.pusd.formatted; // pUSD balance, e.g. "12.5"
  account.usdce.formatted; // USDC.e balance
  account.totalUsd; // combined USD value
}
```

Returns `null` only when the EOA has no Polymarket account. A transient failure
(network, 5xx, abort) rejects instead, so an outage is never mistaken for "no
account". Pass `rpcUrl` to override the default public Polygon RPC, or a
`signal` (`AbortSignal`) to cancel the lookup.

## 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.

```tsx theme={null}
<DepositModal
  isOpen={true}
  onClose={() => {}}
  inline={true}
  // ...other props
/>
```

Set `closeOnOverlayClick={false}` to prevent the modal from closing when the user clicks outside it.

## Props reference

### Required

| Prop          | Type                          | Description                                                      |
| ------------- | ----------------------------- | ---------------------------------------------------------------- |
| `isOpen`      | `boolean`                     | Controls modal visibility                                        |
| `onClose`     | `() => void`                  | Called when the user closes the modal                            |
| `targetChain` | `Chain \| number \| "solana"` | Destination chain (viem `Chain` object, chain ID, or `"solana"`) |
| `targetToken` | `Address \| string`           | Token address on the destination chain                           |
| `recipient`   | `Address \| string`           | Where funds are delivered on the target chain                    |

### Wallet

| Prop               | Type           | Default | Description                                              |
| ------------------ | -------------- | ------- | -------------------------------------------------------- |
| `reownAppId`       | `string`       | —       | Reown project ID. Enables external wallet connection.    |
| `dappAddress`      | `Address`      | —       | Owner address for embedded wallet or QR code flows       |
| `dappWalletClient` | `WalletClient` | —       | Host-provided viem wallet client for signing             |
| `dappPublicClient` | `PublicClient` | —       | Host-provided viem public client                         |
| `onRequestConnect` | `() => void`   | —       | Called when the modal needs the user to connect a wallet |

### Transfer

| Prop                | Type                      | Default | Description                                                                                                                           |
| ------------------- | ------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `defaultAmount`     | `string`                  | —       | Pre-filled deposit amount. USD number string or the sentinel `"max"`.                                                                 |
| `sourceChain`       | `Chain \| number`         | —       | Pre-selected source chain                                                                                                             |
| `sourceToken`       | `Address`                 | —       | Pre-selected source token                                                                                                             |
| `appBalanceUsd`     | `number`                  | —       | In-app USD balance; enables the "Balance after deposit" row                                                                           |
| `allowedRoutes`     | `RouteConfig`             | —       | `{ sourceChains?, sourceTokens? }` to restrict selection                                                                              |
| `outputTokenRules`  | `OutputTokenRule[]`       | —       | Per-deposit output token routing rules                                                                                                |
| `rejectUnmapped`    | `boolean`                 | `false` | Reject deposits that don't match any `outputTokenRules` entry                                                                         |
| `dappImports`       | `DappImportsConfig`       | —       | [Import balances](#import-from-other-apps) from third-party apps (e.g. `{ polymarket: true }`)                                        |
| `initialDappImport` | `keyof DappImportsConfig` | —       | Open the modal pre-routed into a dapp import (e.g. `"polymarket"`), skipping the home screen. Must name an enabled `dappImports` key. |

### Session

| Prop               | Type       | Default        | Description                        |
| ------------------ | ---------- | -------------- | ---------------------------------- |
| `sessionChainIds`  | `number[]` | All supported  | Chain IDs for session key creation |
| `forceRegister`    | `boolean`  | `false`        | Force session re-creation          |
| `signerAddress`    | `Address`  | Default signer | Session signer address             |
| `rhinestoneApiKey` | `string`   | —              | API key for account setup          |

### Backend

| Prop         | Type        | Default                   | Description                                                                                                                                                                                                                                                        |
| ------------ | ----------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `backendUrl` | `string`    | Rhinestone production URL | URL of your deposit-widget-backend instance                                                                                                                                                                                                                        |
| `rpcUrls`    | `RpcUrlMap` | —                         | Per-chain RPC overrides keyed by EVM chain id or the literal `"solana"` key (e.g. `{ 8453: "https://…", solana: "https://…" }`). Applied to EVM public clients, the connected wallet, HyperEVM, and the Solana connection; chains left unset use their default RPC |

### Display

| Prop                  | Type                   | Default | Description                                                         |
| --------------------- | ---------------------- | ------- | ------------------------------------------------------------------- |
| `inline`              | `boolean`              | `false` | Render without modal overlay                                        |
| `closeOnOverlayClick` | `boolean`              | `true`  | Close modal on backdrop click                                       |
| `className`           | `string`               | —       | CSS class for the modal container                                   |
| `theme`               | `DepositModalTheme`    | —       | [Theme configuration](/deposits/widget/customization#theme)         |
| `uiConfig`            | `DepositModalUIConfig` | —       | [UI configuration](/deposits/widget/customization#ui-configuration) |
| `debug`               | `boolean`              | `false` | Enable debug logging                                                |

### Callbacks

| Prop          | Type                                     | Description                                                                                                                                                                           |
| ------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onReady`     | `() => void`                             | Modal initialized                                                                                                                                                                     |
| `onLifecycle` | `(event: DepositLifecycleEvent) => void` | [Lifecycle event](/deposits/widget/status-tracking#onlifecycle) — switch on `event.type` (`connected`, `submitted`, `complete`, `failed`, `balance-changed`, `smart-account-changed`) |
| `onError`     | `(data: ErrorEventData) => void`         | Error at any stage                                                                                                                                                                    |
| `onEvent`     | `(event: DepositAnalyticsEvent) => void` | [Analytics event](/deposits/widget/status-tracking#analytics)                                                                                                                         |

See [status tracking](/deposits/widget/status-tracking) for lifecycle event payloads.

### Solana

| Prop           | Type      | Default | Description                               |
| -------------- | --------- | ------- | ----------------------------------------- |
| `enableSolana` | `boolean` | `true`  | Enable Solana wallet support and QR flows |
