Skip to main content

Vault withdraw

GET 

/v1/actions/vaults/withdraw

Build calldata for an ERC-4626 vault withdraw. When the user wants the underlying back (no native unwrap), the dispatcher calls vault.withdraw / vault.redeem directly with no approval needed. When the receiver wants native ETH, falls back to the composer (unwraps WETH).

This endpoint targets passive ERC-4626 vaults. For Fluid's NFT-position margin vaults use /v1/actions/lending/withdraw.

Execution mode (mode query param)

  • auto (default) — direct when receiveAsset === underlying and not native, otherwise composer.
  • direct — force direct; returns 400 when not eligible.
  • proxy — force the composer (legacy behavior).

Direct withdraw skips the share-token approval entirely — the user calls vault.withdraw(assets, receiver, owner=operator) themselves and the vault uses its own balance check (msg.sender == owner).

Assets vs shares

  • isShares=false (default): amount is assets — issues vault.withdraw(assets, receiver, owner).
  • isShares=true: amount is shares — issues vault.redeem(shares, receiver, owner).

Withdraw all (isAll=true)

Two ways to drive a full-balance withdraw — both resolve the operator's vault-share balance and encode vault.redeem(shares, …). They differ only in where the share balance is read:

  • GET + isAll=true — worker reads balanceOf(vault, operator) against its own configured RPC. Simple but only works when the worker can see the state (i.e. live mainnet, not fork). Returns BALANCE_READ_FAILED on RPC failure.
  • POST + isAll=true + body { "sharesRaw": "<uint string>" } — caller pre-reads the balance against any RPC (fork, custom, premium) and supplies it. The worker just trusts and encodes. Mirrors the lending simulation pattern (SimulationBody).

The POST body's amount query param is ignored when isAll=true.

Request

Responses

Transaction calldata + any approval(s) needed for the vault withdraw