How Withdrawals Work
Unlike deposits, withdrawals are not instant. They use a queue-based model:Approve vault shares
Grant the WithdrawQueue permission to transfer your vault 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? Vault assets may be deployed in DeFi
strategies. The vault operator needs time to unwind positions and source
liquidity. This is standard across DeFi vault protocols.
What You’ll Need
| Requirement | Description |
|---|---|
| Contract addresses | boringVaultAddress, withdrawQueueAddress, and accountantAddress — see Vault Discovery |
| ABI | Provided below |
| RPC endpoint | An Ethereum node URL |
| Private key or wallet | To sign and send transactions |
| Vault 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 | Vault 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 vault 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 vault 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 vault 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 vault 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 vault shares. Use the Accountant’s exchange rate to convert.
Contract call
rate represents the amount of the want asset per 1e18 vault shares.
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) / rateIf 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 vault shares to the WithdrawQueue (transaction)
Grant the WithdrawQueue permission to transfer your vault 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 vault 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 vault. Query the vault config
to find supported withdrawal assets.PermitFailedAndAllowanceTooLow
PermitFailedAndAllowanceTooLow
Vault shares haven’t been approved to the WithdrawQueue. Call
BoringVault.approve() first.TellerIsPaused
TellerIsPaused
Vault 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
- Vault Queries & Monitoring — Read withdrawal fees, check pause state, monitor withdrawal history
- Direct Deposits — Deposit tokens into a vault
- SDK Withdrawals Guide — Use the Amplify SDK instead