How Withdrawals Work
Unlike deposits, withdrawals are not instant. They use a queue-based model:Approve account shares
Grant the WithdrawQueue permission to transfer your account shares by calling
approve() on the BoringVault (share token) contract.Submit a withdrawal order
Call
submitOrder() on the WithdrawQueue. Your shares are locked and a
withdrawal order is created.Why can’t I withdraw instantly? Account assets may be deployed in DeFi
strategies. The account operator needs time to unwind positions and source
liquidity. This is standard across DeFi account protocols.
What You’ll Need
| Requirement | Description |
|---|---|
| Contract addresses | boringVaultAddress, withdrawQueueAddress, and accountantAddress — see Account Discovery |
| ABI | Provided below |
| RPC endpoint | An Ethereum node URL |
| Private key or wallet | To sign and send transactions |
| Account shares | You must have shares from a prior deposit |
ABI Reference
WithdrawQueue ABI
FeeModule ABI
BoringVault ABI (ERC-20 for share approval)
Accountant ABI (for share conversion)
Contract Method Reference
submitOrder(params)
| Field | Type | Description |
|---|---|---|
amountOffer | uint256 | Account shares to offer. Shares have 18 decimals, so 1000000000000000000 = 1 share. |
wantAsset | address | Token you want to receive (e.g., USDC address) |
intendedDepositor | address | Must match the caller (msg.sender) |
receiver | address | Where the want asset is sent when fulfilled |
refundReceiver | address | Where account shares are returned if the order is cancelled |
signatureParams | tuple | For standard ERC-20 approval flow, pass all zeros (see below) |
Empty Signature Params
When you’ve already calledapprove(), pass empty signature params to indicate standard ERC-20 approval:
| Field | Value |
|---|---|
approvalMethod | 0 (EIP20_APPROVE) |
approvalV | 0 |
approvalR | 0x + 32 zero bytes |
approvalS | 0x + 32 zero bytes |
submitWithSignature | false |
deadline | 0 |
eip2612Signature | 0x (empty bytes) |
Order Statuses
| Value | Status | Meaning |
|---|---|---|
0 | NOT_FOUND | Order doesn’t exist |
1 | PENDING | Waiting for the account operator to fulfill |
2 | COMPLETE | Fulfilled — want asset sent to receiver |
3 | COMPLETE_PRE_FILLED | Filled during submission |
4 | PENDING_REFUND | Being refunded |
5 | COMPLETE_REFUNDED | Cancelled — shares returned |
6 | FAILED_TRANSFER_REFUNDED | Transfer failed — shares returned |
Withdrawal Fees
The WithdrawQueue charges a fee on withdrawal orders via its FeeModule. You should check the fee before submitting to display accurate amounts to your users. The fee is deducted from youramountOffer in account shares — meaning you receive the want asset equivalent of amountOffer - feeAmount.
How to read the fee
This requires two contract reads: Step 1 — Get the FeeModule address from the WithdrawQueue:feeAmount is in account shares (18 decimals). To get the fee percentage:
5000000000000000 = 0.5%).
Converting Withdrawal Amount to Shares
Users typically think in terms of the want asset (e.g., “I want to withdraw 1,000 USDC”), butamountOffer is denominated in account shares. Use the Accountant’s exchange rate to convert.
Contract call
rateInQuote represents the amount of the want asset per 1e18 account shares. Pass the want asset (withdrawal token) address as the quote parameter.
Conversion formula
To withdraw a specific amount of the want asset:Don’t forget to account for withdrawal fees when
calculating the share amount. If there’s a 0.5% fee, you’ll need to offer
slightly more shares:
sharesNeeded / (1 - feePercentage).Minimum Order Size
Each WithdrawQueue enforces a minimum order size. Check it before submitting:amountOffer is below this threshold, the transaction will revert with AmountBelowMinimum.
Withdrawal Walkthrough
Convert want amount to shares (read)
If you know the want asset amount, convert it to shares.Then calculate:
sharesNeeded = (wantAmount × 1e18) / rateInQuoteIf you already know the share amount you want to offer, skip this step.Check the withdrawal fee (read)
Get the FeeModule address and calculate the fee that will be deducted.The net shares applied to the withdrawal =
sharesNeeded - feeAmount. Display this to the user so they know the effective withdrawal amount.Check the minimum order size (read)
Ensure your order meets the minimum.If
sharesNeeded < minimumShares, the order will be rejected.Check existing allowance (read)
See if the WithdrawQueue already has permission to transfer your shares.If the returned value is ≥ your
sharesNeeded, skip to Step 7.Approve account shares to the WithdrawQueue (transaction)
Grant the WithdrawQueue permission to transfer your account shares.Wait for the transaction to be mined before proceeding.
Submit the withdrawal order (transaction)
Call The return value
submitOrder() on the WithdrawQueue with empty signature params (since you used ERC-20 approval in Step 6).orderIndex uniquely identifies your order. Save it to check status or cancel later.You can also extract orderIndex from the OrderSubmitted event in the transaction receipt logs.Poll for order completion (read)
The account operator typically fulfills orders within 24 hours. Check the status:Poll periodically (e.g., every 60 seconds) until
status ≥ 2:2(COMPLETE) — Want asset has been sent to your receiver address5(COMPLETE_REFUNDED) — Order was cancelled, shares returned6(FAILED_TRANSFER_REFUNDED) — Transfer failed, shares returned
Example values (withdrawing ~1,000 USDC worth of shares on Ethereum mainnet)
| Parameter | Value |
|---|---|
amountOffer | Calculated from exchange rate (e.g., 990099009900...) |
wantAsset | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 (USDC) |
intendedDepositor | Your wallet address |
receiver | Your wallet address |
refundReceiver | Your wallet address |
signatureParams | All zeros (see empty signature params table above) |
Troubleshooting
AmountBelowMinimum
AmountBelowMinimum
Your
amountOffer is below the queue’s minimum order size. Call
minimumOrderSize() to check the threshold, and increase your amount.InvalidDepositor
InvalidDepositor
The
intendedDepositor field doesn’t match the transaction sender. Set it
to the wallet address that’s sending the transaction.AssetNotSupported
AssetNotSupported
The
wantAsset address isn’t enabled for this account. Query the account config
to find supported withdrawal assets.PermitFailedAndAllowanceTooLow
PermitFailedAndAllowanceTooLow
Account shares haven’t been approved to the WithdrawQueue. Call
BoringVault.approve() first.TellerIsPaused
TellerIsPaused
Account operations are temporarily paused by the operator. Wait and retry
later. You can check programmatically with
Teller.isPaused() — see
Pause State.Next Steps
- Direct Cancellations — Cancel a pending withdrawal order
- Account Queries & Monitoring — Read withdrawal fees, check pause state, monitor withdrawal history
- Direct Deposits — Deposit tokens into an account
- SDK Withdrawals Guide — Use the Amplify SDK instead