Action envelope, and the protocol re-verifies the signature before applying it. Four methods cover the distinct destinations:
private/transfer_spot
Move collateral between two subaccounts you own.
private/transfer_spot_external
Send collateral to a subaccount owned by a different wallet, bounded by your recipient allow-list.
private/withdraw
Withdraw collateral on-chain to an L1 recipient address.
private/transfer_positions
Move open positions between subaccounts, booked as an RFQ trade.
nonce, signer, signature, and signature_expiry_sec built exactly as described in Action signing. The action module for each flow is filled in by the server and does not appear on the wire — it is part of the signed struct hash and must match the deployment’s module address in Action signing.
Amounts, prices, and fees are human decimals on the wire — decimal strings (e.g.
"100.5") or JSON numbers. The
exception is private/withdraw, whose on-chain amount uses the asset’s native ERC-20 decimals (see below).Transfer collateral between your subaccounts
private/transfer_spot moves a spot balance from one of your subaccounts to another subaccount you own (existing, or a new one created in the same call). Positions are not moved by this method — use private/transfer_positions for that.
Required scope: transfer:existing_subaccount or transfer:new_subaccount (see Access scopes).
Transfer positions between subaccounts
private/transfer_positions moves open positions from one subaccount to another. It is booked as an RFQ-module trade: both sides sign a transfer quote over the same legs, and the transfer clears at the agreed prices. The signing key needs a transfer:* scope covering the destination (transfer:existing_subaccount, transfer:new_subaccount, or transfer:different_owner_subaccount).
Both quotes sign the same legs hash; each side authorizes its own max_fee. The response returns the resulting maker_quote and taker_quote.
Transfer collateral to another wallet
private/transfer_spot_external sends collateral to a subaccount owned by a different wallet. The destination owner must be on the sender’s whitelisted-recipient allow-list, and the signing key needs transfer:different_owner_subaccount.
Managing the recipient allow-list
Withdrawals or transfers to external subaccounts can only reach wallets you have explicitly whitelisted. Manage the list withprivate/update_whitelisted_recipients. Permissions that can modify this list are:
- owner
adminscoped session key
Withdraw
private/withdraw removes collateral from a subaccount and settles it to an Ethereum L1 recipient. It is a signed action requiring the withdraw scope.
Withdrawals signed by a session key must go to an address on the owner’s whitelisted-recipient allow-list, including the owner wallet itself. See Managing the recipient allow-list above.
recipient is optional and defaults to the account’s owner wallet — not the signer, and not the subaccount. The
signature commits to it, so the server cannot redirect a payout: a recipient disagreeing with what you signed fails
signature verification rather than being honored.A session key may only pay out to an address on the owner’s whitelist — including the owner wallet itself, which is
not whitelisted implicitly. Whitelist it before granting a key the withdraw scope, or the withdrawal is rejected with
RecipientNotWhitelisted. The owner and admin-scoped keys skip the whitelist entirely.