@rhinestone/deposit-modal
v0.1.18
Published
React modal component for Rhinestone cross-chain deposits
Readme
@rhinestone/deposit-modal
React components for cross-chain deposits and withdrawals via Rhinestone smart accounts.
Install
npm install @rhinestone/deposit-modal viemDepositModal
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/tokenimport { DepositModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";
<DepositModal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
dappWalletClient={walletClient}
dappPublicClient={publicClient}
dappAddress={address}
targetChain={8453}
targetToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
onDepositComplete={(data) => console.log("Done!", data)}
/>Deposit flow matrix
| | Flow 1: Dapp signer | Flow 2: External wallet | Flow 3: QR deposit |
|---|---|---|---|
| Typical dapp input | dappWalletClient + dappAddress | dappAddress (user selects/connects external wallet in modal) | dappAddress only |
| Connect step options | Connected Wallet (+ External Wallet/Transfer Crypto if available) | Usually External Wallet + Transfer Crypto | Same options, user picks Transfer Crypto |
| Smart-account owner (ownerAddress) | dappWalletClient.account.address | Selected external wallet address | dappAddress |
| createSmartAccount(userSigner, sessionOwner.account) userSigner | walletClientToAccount(dappWalletClient) | walletClientToAccount(externalWalletClient) | createViewOnlyAccount(dappAddress) |
| createSmartAccount(..., sessionOwner.account) co-owner | Local browser session-owner keypair (sessionOwner.account) | Local browser session-owner keypair (sessionOwner.account) | Local browser session-owner keypair (sessionOwner.account) |
| Smart account S owners passed to SDK | [ownerAddress, sessionOwner.address] | [ownerAddress, sessionOwner.address] | [ownerAddress, sessionOwner.address] |
| Session-owner localStorage key | rhinestone:session-owner:<ownerAddress.lowercase()> | rhinestone:session-owner:<ownerAddress.lowercase()> | rhinestone:session-owner:<ownerAddress.lowercase()> |
| Session policy signer in sessionDetails | DEFAULT_SIGNER_ADDRESS (or signerAddress prop override) | DEFAULT_SIGNER_ADDRESS (or signerAddress prop override) | DEFAULT_SIGNER_ADDRESS (or signerAddress prop override) |
| Who signs source transfer | dappWalletClient | External wallet client | No modal signer (user sends funds manually) |
| How processing starts | Confirm step submits transfer tx | Confirm step submits transfer tx | User sends to QR address; modal polls status |
| POST /register address | Smart account address (S) | Smart account address (S) | Smart account address (S) |
| POST /register eoaAddress | ownerAddress | ownerAddress | dappAddress |
| POST /register sessionOwner | sessionOwner.address (local co-owner key) | sessionOwner.address (local co-owner key) | sessionOwner.address (local co-owner key) |
| POST /register accountParams.sessionDetails | Built from session policy signer + sessionOwner.account signature | Built from session policy signer + sessionOwner.account signature | Built from session policy signer + sessionOwner.account signature |
| POST /register target | { chain: targetChain, token: targetToken, recipient? } | { chain: targetChain, token: targetToken, recipient? } | { chain: targetChain, token: targetToken, recipient? } |
| If dappAddress is missing | Unsupported for this flow | External-only flow can still run | Not available (QR hidden) |
Notes:
- External wallet option is available when Reown is enabled (
reownAppId) and a wallet can be connected in the modal. onConnected({ address, smartAccount })reports the active owner address used for that flow.- Smart-account owner config is passed to the SDK as two ECDSA owners (
ownerAddress+ localsessionOwner) with threshold1. DEFAULT_SIGNER_ADDRESSis the session policy signer insidesessionDetails; it is not the local co-owner key stored in browser.
Props
| 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 |
| dappWalletClient | WalletClient \| null | No | Host-provided signer wallet client |
| dappPublicClient | PublicClient \| null | No | Host-provided public client (fallbacks are created internally if missing) |
| dappAddress | Address \| null | No | Dapp identity / owner anchor used by setup and QR flow |
| 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 |
| rhinestoneApiKey | string | No | Optional SDK api key forwarded to RhinestoneSDK during smart-account setup |
| 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 |
Callbacks
| Callback | Description |
|----------|-------------|
| onReady | Modal initialized |
| onConnected(data) | Smart account created ({ address, smartAccount }) |
| onDepositSubmitted(data) | Transfer signed ({ txHash, sourceChain, amount }) |
| onDepositComplete(data) | Deposit arrived ({ txHash, destinationTxHash? }) |
| onDepositFailed(data) | Bridge failed ({ txHash, error? }) |
| onError(data) | Error payload ({ message, code? }) |
WithdrawModal
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/tokenimport { WithdrawModal } from "@rhinestone/deposit-modal";
import "@rhinestone/deposit-modal/styles.css";
<WithdrawModal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
dappWalletClient={walletClient}
dappPublicClient={publicClient}
dappAddress={address}
safeAddress="0x..."
sourceChain={8453}
sourceToken="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
targetChain={1}
targetToken="0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
onWithdrawComplete={(data) => console.log("Done!", data)}
/>Additional Props (beyond shared DepositModal props)
| 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 |
Callbacks
| Callback | Description |
|----------|-------------|
| onWithdrawSubmitted(data) | Safe transfer signed ({ txHash, sourceChain, amount, safeAddress }) |
| onWithdrawComplete(data) | Withdrawal arrived ({ txHash, destinationTxHash? }) |
| onWithdrawFailed(data) | Bridge failed ({ txHash, error? }) |
Also supports onReady, onConnected, and onError (same as DepositModal).
Theming
<DepositModal
theme={{ mode: "dark", ctaColor: "#8b5cf6", radius: "lg" }}
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
Utility Exports
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";Supported Chains
Mainnet (1), Base (8453), Arbitrum (42161), Optimism (10), Polygon (137), BSC (56)
License
MIT
