Skip to main content
Withdraw removes supplied assets and pays them to to, or to caller when no recipient is set. The caller must own the account’s position NFT or hold an active delegate grant. An account with debt must still pass its LTV and health-factor gates after the withdrawal. Repay debt first when a larger withdrawal would fail those checks.

Choose the amount

Each withdrawal is (HubAssetKey, amount) in token base units. The list must be nonempty and amounts cannot be negative. 0 requests the full position after interest accrues. A positive amount below the half-up displayed balance requests a partial withdrawal. An amount at or above that balance also closes the asset’s position and pays its floor-valued claim. Duplicate market entries are summed in first-appearance order. Any zero entry for a market makes its total a full withdrawal, including when other entries for that market are positive.
A full withdrawal pays the floor-valued balance. The balance view rounds half-up, so the payout can be one base unit below the displayed balance. Use the returned payout amounts for downstream accounting. The controller has no max_withdraw view; simulate the intended call.

Check withdrawal conditions

  • Each requested market has a supply position in the account.
  • The pool has enough cash and the withdrawal passes the market’s utilization limit.
  • If debt remains, LTV coverage and health factor pass, and LTV-weighted collateral meets the minimum-borrow floor.
  • If debt remains, each collateral position below 3 decimals holds at least two token base units.
  • Valid prices are available for indebted account valuation. Debt-free withdrawal skips valuation.
  • The listing is not paused. Frozen or missing listings permit withdrawal of existing collateral. Global protocol pause permits withdrawal.
  • The recipient is neither the controller nor the pool.

Build and authorize the call

The SDK builder is synchronous and RPC-free. The function above prepares a full withdrawal; pass the selected account’s hub and SAC as market. The RPC must use the selected network. Sign only the returned prepared XDR. Follow the wallet transaction lifecycle for signing, submission, confirmation, and uncertain outcomes. Use buildStellarWithdrawBatchTx for several supply markets. caller authorizes the controller call. The pool pays the recipient directly; no caller token-transfer authorization is needed. An optional recipient changes the payout destination only.

Verify the withdrawal

The return value contains actual payouts for each aggregated market. Read get_collateral_amount(account_id, hub_asset) to confirm the remaining balance. For accounts with debt, also read get_health_factor(account_id). The controller emits UpdatePositionBatchEvent at ["position", "batch_update"], with Withdraw legs. The pool emits PoolMarketStateBatchEvent at ["market", "batch_state_update"]. Withdrawing the final position from a debt-free account removes the account and burns its NFT. get_account_attributes(account_id) then raises #13 AccountNotInMarket. Clear the stored id only after a successful account_exists(account_id) read returns false. An RPC, restoration, or ownership lookup error does not prove account deletion. After confirmed deletion, pass account_id = 0 to create the next account. See account lifecycle.

Common errors

For contract-owned accounts, see Vault integrations.