WithdrawModal component handles outbound transfers. The user selects a destination chain and token, enters a recipient and an amount, and the modal registers the account that routes the funds — then asks your app to perform one transfer.
The modal never holds a key and never moves funds itself, so it works with any account model: an EOA, a smart account, an embedded or in-app wallet, or a relayer.
Basic usage
accountAddress is the account holding the funds. The modal reads its balance and stops the user sending to themselves; it never transacts from it.
Executing the transfer
onSendTransaction is required. The modal calls it once, when the user confirms on the review screen, with everything needed for a single transfer:
If your funds are in a Safe
A 1/1 Safe signs withpersonal_sign over the SafeTx hash, relayed by whoever pays the gas. Build the EIP-712 SafeTx, sign it, and submit execTransaction:
Safe’s
eth_sign path requires adding 4 to the v value of a personal_sign signature. This adjustment is specific to Safe’s signature verification — see the Safe docs for details.POST /safe/withdraw on your proxy rather than submitting execTransaction from the user’s wallet. Note that a relayed transaction cannot use Safe’s pre-validated (v = 1) signature shortcut: that only validates when msg.sender is the owner, and for a relayed call the sender is the relayer.
Props reference
Required
Transfer
targetChain and targetToken are optional — they seed the form, and the user can
pick any supported destination. Omit them to open on a same-chain, same-token
withdrawal.Account
Backend
Display
Callbacks
Withdraw sessions send analytics to Rhinestone from the browser too, so the same content security policy applies.
WithdrawLifecycleEvent has no balance-changed or smart-account-changed variants, and its payload types differ from the deposit union: txHash is Hex, sourceChain is always a number, sourceToken / targetToken are Address, and "submitted" carries an accountAddress.