Skip to main content
Initiate a withdrawal from active positions to user’s EOA. Supports both full and partial withdrawals. Processed asynchronously by backend. The SDK calls GET /api/v1/users/withdraw/v2 (full) or POST /api/v1/users/partial-withdraw/v2 (partial). When the accept response includes both id and statusUrl, withdrawFunds attaches a lifecycle object with status accepted. Poll that id with getWithdrawStatus, waitForWithdrawSettlement, or waitForWithdrawComplete. Do not call withdrawFunds again for the same request; poll the lifecycle id instead. Funds are always withdrawn to the Safe owner’s address (the userAddress parameter). Supported assets: USDC (default), WETH, EURC, USDT, PYUSD, and NVDAc. Chains and decimals: Supported Assets. NVDAc withdrawals are always delayed — see below.

Delayed withdrawals (yieldmaxxing strategy)

Positions held in protocols with asynchronous withdrawals (Ipor, Superform) cannot be exited on demand. Every NVDAc withdrawal falls in this case, since those two protocols are the only ones holding it. For those the backend sends the immediately available portion straight away, then queues a redemption for the rest and forwards the funds to the EOA once the protocol releases them (roughly a day on Ipor, three on Superform). The user has nothing else to call, but withdrawFunds returns as soon as the immediate portion is sent, so its txHash does not cover the whole amount. When every source is an async pool, nothing settles on-chain at that point and txHash is undefined on a successful call. Treat it as optional and track the remainder through lifecycle polling (above) and getPortfolio:
Once requested, that amount can no longer be withdrawn: it is gone from both the position snapshot and the Safe balance.
While an entry for a pool is REQUESTED or CLAIMABLE, a second withdrawFunds aimed at that same pool is not allowed. The protocols behind it (ERC-7540) hold a single request slot per user; the backend drops the duplicate and still answers success: true. The SDK throws instead of returning that no-op:
It only throws when nothing the call could reach is withdrawable. Another pool, another asset or an idle Safe balance still goes through, partially.To disable the action before the user tries, read pendingAsyncWithdrawals:
It is also missing from portfolioByAssetType while in flight, so validate user-entered amounts against that field rather than the total balance. Read Computing the total balance before showing any balance to the user.

Signature

Parameters

Returns

Withdraw response with status message

Return Type

The lifecycle field on accept is a local stub (status: "accepted"). Call getWithdrawStatus for the live state.

Example

Withdraw USDC (default)

Withdraw WETH

Withdraw EURC

Withdraw NVDAc

Always delayed, and only one redemption can be in flight per pool. If pendingAsyncWithdrawals already has a REQUESTED or CLAIMABLE entry for NVDAc, do not call withdrawFunds again — it throws.