React modal component for Rhinestone cross-chain deposits
npm install @rhinestone/deposit-modalReact components for cross-chain deposits and withdrawals via Rhinestone smart accounts.
``bash`
npm install @rhinestone/deposit-modal viem
Deposits tokens from any supported chain into a target chain/token via a Rhinestone smart account.
``
User wallet → transfer → Rhinestone smart account → bridge → target chain/token
`tsx
import { DepositModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";
onClose={() => setIsOpen(false)}
walletClient={walletClient}
publicClient={publicClient}
address={address}
targetChain={8453}
targetToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
switchChain={(chainId) => switchChainAsync({ chainId })}
onDepositComplete={(data) => console.log("Done!", data)}
/>
`
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| isOpen | boolean | Yes | Modal open state |onClose
| | () => void | Yes | Close handler |targetChain
| | Chain \| number | Yes | Destination chain |targetToken
| | Address | Yes | Destination token address |walletClient
| | WalletClient \| null | No | viem WalletClient |publicClient
| | PublicClient \| null | No | viem PublicClient |address
| | Address \| null | No | Connected wallet address |switchChain
| | (chainId: number) => Promise<{id: number} \| void> | No | Chain switch callback |inline
| | boolean | No | Render inline without overlay |sourceChain
| | Chain \| number | No | Pre-selected source chain |sourceToken
| | Address | No | Pre-selected source token |defaultAmount
| | string | No | Pre-filled amount |recipient
| | Address | No | Custom recipient address |backendUrl
| | string | No | Backend URL |signerAddress
| | Address | No | Session signer address |waitForFinalTx
| | boolean | No | Wait for destination tx (default: true) |onRequestConnect
| | () => void | No | Called when wallet connection needed |connectButtonLabel
| | string | No | Custom connect button label |theme
| | DepositModalTheme | No | Theme customization |branding
| | DepositModalBranding | No | Logo and title |uiConfig
| | DepositModalUIConfig | No | UI display options |className
| | string | No | Additional CSS class |
| Callback | Description |
|----------|-------------|
| onReady | Modal initialized |onConnected(address, smartAccount)
| | Smart account created |onDepositSubmitted(txHash, sourceChain, amount)
| | Transfer signed |onDepositComplete(txHash, destinationTxHash?)
| | Deposit arrived on target chain |onDepositFailed(txHash, error?)
| | Bridge failed |onError(message, code?)
| | Error during flow |
Withdraws tokens from a 1/1 Safe to a target chain/token. The connected wallet must be the sole Safe owner. User signs an EIP-712 SafeTx authorizing the ERC20 transfer, then funds are bridged to the destination.
``
Safe → ERC20 transfer → Rhinestone smart account → bridge → target chain/token
`tsx
import { WithdrawModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";
onClose={() => setIsOpen(false)}
walletClient={walletClient}
publicClient={publicClient}
address={address}
safeAddress="0x..."
sourceChain={8453}
sourceToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
targetChain={1}
targetToken="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
switchChain={(chainId) => switchChainAsync({ chainId })}
onWithdrawComplete={(data) => console.log("Done!", data)}
/>
`
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| safeAddress | Address | Yes | Safe holding funds |sourceChain
| | Chain \| number | Yes | Chain where the Safe exists |sourceToken
| | Address | Yes | Token in the Safe |
| Callback | Description |
|----------|-------------|
| onWithdrawSubmitted(txHash, sourceChain, amount, safeAddress) | Safe transfer signed |onWithdrawComplete(txHash, destinationTxHash?)
| | Withdrawal arrived |onWithdrawFailed(txHash, error?)
| | Bridge failed |
Also supports onReady, onConnected, and onError (same as DepositModal).
`tsx`
branding={{ logoUrl: "https://example.com/logo.png", title: "Fund Account" }}
uiConfig={{ showLogo: true, showStepper: true, maxDepositUsd: 10000 }}
/>
Theme: mode (light/dark), ctaColor, ctaHoverColor, fontColor, iconColor, borderColor, backgroundColor, radius (none/sm/md/lg/full)
Branding: logoUrl, title
UI Config: showLogo, showStepper, showBackButton, balanceTitle, maxDepositUsd
`tsx``
import {
SOURCE_CHAINS, SUPPORTED_CHAINS, chainRegistry,
getChainName, getChainIcon, getChainObject,
getUsdcAddress, getTokenAddress, getTokenDecimals, getTokenSymbol, getTokenIcon,
getExplorerTxUrl, DEFAULT_BACKEND_URL, NATIVE_TOKEN_ADDRESS,
} from "@rhinestone/deposit-modal";
Base (8453), Optimism (10), Arbitrum (42161)
MIT