Skip to main content

Withdraw

GET 

/v1/actions/lending/withdraw

Build calldata for withdrawing from a lending pool. Identify the market via marketUid (format: lender:chainId:address). Approval transactions are automatically filtered: if the user already has sufficient allowances, permissions (envelope) and permissionTxns (per-entry) will be empty. Pass simulate=true to include projected post-trade metrics. When on-chain deposit data is available and amount covers the full deposit balance, the API uses protocol-level max-withdraw mechanisms automatically (e.g. maxUint256 or share-based redemption). If isAll=true but amount is less than the deposit balance, the API falls back to a partial withdrawal to avoid reverts.

Plain-text reference — GET /v1/actions/lending/withdraw

Parameters

ParameterInTypeRequiredDescription
marketUidquerystringyesMarket identifier (lender:chainId:address). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital).
amountquerystringyesAmount in wei
modequeryproxy, directnoExecution mode. proxy = 1delta composer, direct = raw protocol
operatorquerystringnoWallet address of the user executing the action
receiverquerystringnoRecipient of the lender position (deposit) or underlying tokens (borrow/withdraw).
Defaults to operator when omitted.

Custom-receiver support is per-lender. The API auto-selects the execution path:

Direct path supported

  • Aave V2/V3 — supply / withdraw honor to.
  • Aave V4 — deposit via GiverPM supplyOnBehalfOf. Requires the GiverPM to be curated in aave-v4-peripherals.json with a name containing "giver".
  • Compound V3 — supplyTo / withdrawTo.
  • Morpho Blue & Lista DAO ERC-20 markets — Morpho onBehalf.
  • Euler V2 ERC-20 vaults — ERC-4626 deposit(receiver). Collateral auto-enable is dropped for non-sub-account receivers.
  • Silo V2/V3 ERC-20 — deposit(_, receiver, _).
  • Gearbox V3 passive-pool deposits — ERC-4626 deposit(_, receiver).
  • Fluid borrow & withdraw — operate(..., to_) outflow slot.
  • Fluid deposit to an existing NFT when accountId is supplied — pure-deposit operate() calls bypass Fluid's owner auth gate, and the API folds a pre-flight VaultFactory.ownerOf(nftId) == receiver check into the merged multicall (rejects with 400 INVALID_PARAM on mismatch, VALIDATION_FAILED if the RPC can't confirm ownership).

Routes to composer (proxy) path

  • Compound V2 family — direct mint is msg.sender-only.
  • Fluid fresh-open deposits — no accountId or accountId=0. The composer mints the new position NFT to itself, then transfers it to receiver via the encoder's nftReceiver slot.
  • Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards msg.value to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as payAsset.

Direct-only branches that throw

  • Gearbox V3 credit-side addCollateral — CA bound to operator.
  • Aave V4 native-gateway path — supplyAsCollateralNative has no recipient slot.

Unsupported in any single tx

  • Init Capital — position NFT swept to operator.
  • Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender.
  • Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default).

When the lender cannot honor a custom receiver on the direct path, getTarget falls back to proxy automatically. Forcing mode=direct on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | isAll | query | boolean | no | Withdraw/repay full balance.

When on-chain position data is available, the API compares amount against the actual balance to decide the effective mode:

  • If amount covers the full position the action is treated as "withdraw/repay all" regardless of this flag.
  • If isAll is true but amount is less than the position, the API falls back to a partial action with the provided amount to avoid on-chain reverts.

Without on-chain data, the flag is trusted as-is. | | receiveAsset | query | string | no | Asset to receive.

Use the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 cETH markets).

Proxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | isShares | query | boolean | no | Amount is in shares (direct mode) | | accountId | query | string | no | Per-position identifier. Lender-specific:

  • Init Capital — account ID, required for borrow/withdraw/repay.
  • Euler V2 — sub-account index (0..255), defaults to 0.
  • Gearbox V3 — credit-account address (alias: creditAccount).
  • Fluid — position NFT id. Omit or pass 0 to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom receiver (deposit lands on the receiver-owned NFT after pre-flight ownerOf validation). | | slippage | query | number | no | Slippage tolerance in basis points (50 = 0.5%, 100 = 1%).

Required whenever the action has to price something:

  • Aggregator swap — when payAsset / receiveAsset differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap.
  • Order-book take (Morpho Midnight) — bounds the worst execution price accepted while filling offers.

Ignored when neither applies (same-asset action on a pool lender). | | simulate | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the simulation field. Default: false. |

Response 200

FieldTypeDescription
successTrue
dataobjectInformational data (quotes, simulation results, etc.)
data.transactionobjectAn EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them.
data.transaction.tostringTarget contract address
data.transaction.datastringEncoded calldata
data.transaction.valuestringETH value to send with the transaction
data.transaction.descriptionstringHuman-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1").
data.permissionTxnsobject[]Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances.
data.permissionTxns[].tostringTarget contract address
data.permissionTxns[].datastringEncoded calldata
data.permissionTxns[].valuestringETH value
data.permissionTxns[].descriptionstringHuman-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20")
data.permissionTxns[].spenderstringERC-20 approve spender (x-chain permissions). Match it against the selected quote's approvalTarget — several bridges can share one spender, so do not match by description.
data.rateImpactobject[]Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable.
data.rateImpact[].marketUidstringMarket identifier (format: lender:chainId:address)
data.rateImpact[].utilizationobjectA current/projected pair for a single rate metric.
data.rateImpact[].utilization.currentnumberCurrent value
data.rateImpact[].utilization.projectednumberProjected value after the action
data.rateImpact[].borrowRateobjectA current/projected pair for a single rate metric.
data.rateImpact[].borrowRate.currentnumberCurrent value
data.rateImpact[].borrowRate.projectednumberProjected value after the action
data.rateImpact[].depositRateobjectA current/projected pair for a single rate metric.
data.rateImpact[].depositRate.currentnumberCurrent value
data.rateImpact[].depositRate.projectednumberProjected value after the action
data.transactionobjectAn EVM transaction ready to sign and broadcast. Send to, data and value as-is; do not re-encode them.
data.transaction.tostringTarget contract address
data.transaction.datastringEncoded calldata
data.transaction.valuestringETH value to send with the transaction
data.transaction.descriptionstringHuman-readable label. For alternatives, this is the aggregator name (e.g. "Paraswap"). For transactions, describes the setup action (e.g. "Switch e-mode to 1").
data.permissionTxnsobject[]Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances.
data.permissionTxns[].tostringTarget contract address
data.permissionTxns[].datastringEncoded calldata
data.permissionTxns[].valuestringETH value
data.permissionTxns[].descriptionstringHuman-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20")
data.permissionTxns[].spenderstringERC-20 approve spender (x-chain permissions). Match it against the selected quote's approvalTarget — several bridges can share one spender, so do not match by description.
data.rateImpactobject[]Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable.
data.rateImpact[].marketUidstringMarket identifier (format: lender:chainId:address)
data.rateImpact[].utilizationobjectA current/projected pair for a single rate metric.
data.rateImpact[].utilization.currentnumberCurrent value
data.rateImpact[].utilization.projectednumberProjected value after the action

Example response

{
"success": true,
"data": {
"transaction": {
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
},
"permissionTxns": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
],
"rateImpact": [
{
"marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006",
"utilization": {
"current": 1.0,
"projected": 1.0
},
"borrowRate": {
"current": 1.0,
"projected": 1.0
},
"depositRate": {
"current": 1.0,
"projected": 1.0
}
}
]
},
"actions": {
"transactions": [
{
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"alternatives": [
{
"to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string"
}
],
"permissions": [
{
"to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"data": "0x617ba037000000000000000000000000c02aaa39b2",
"value": "0",
"description": "string",
"spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
]
}
}

Request

Responses

Transaction calldata and approvals for withdraw