> ## Documentation Index
> Fetch the complete documentation index at: https://xoxno.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Withdraw

> Withdraw supplied assets, handle full-position amounts, and verify actual payouts.

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](/docs/stellar-lending/dev/health-factor) after the
withdrawal. [Repay](/docs/stellar-lending/dev/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.

<Warning>
  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.
</Warning>

## 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

```rust theme={"system"}
withdraw(
    caller: Address,
    account_id: u64,
    withdrawals: Vec<(HubAssetKey, i128)>,
    to: Option<Address>,
) -> Vec<(HubAssetKey, i128)>
```

<CodeGroup>
  ```bash Stellar CLI theme={"system"}
  # Set CONTROLLER, IDENTITY, and CALLER_ADDRESS as in the quickstart.
  # Replace the token address. Withdraw the full USDC position from account 42.
  stellar contract invoke \
    --id "$CONTROLLER" \
    --source-account "$IDENTITY" \
    --network testnet \
    -- withdraw \
    --caller "$CALLER_ADDRESS" \
    --account_id 42 \
    --withdrawals '[[{"hub_id":1,"asset":"<USDC_SAC>"}, "0"]]' \
    --to null
  ```

  ```typescript TypeScript theme={"system"}
  import { rpc } from '@stellar/stellar-sdk'
  import {
    assertStellarPreparedTxAuth,
    buildStellarWithdrawTx,
    getStellarDeployment,
    prepareStellarBuiltTx,
    type StellarHubAsset,
    type StellarNetwork,
  } from '@xoxno/sdk-js/stellar-lending'

  export async function prepareFullWithdrawal(
    server: rpc.Server,
    network: StellarNetwork,
    caller: string,
    accountId: string,
    market: StellarHubAsset,
  ): Promise<string> {
    const deployment = getStellarDeployment(network)
    const source = await server.getAccount(caller)
    const built = buildStellarWithdrawTx({
      network,
      caller,
      sourceSequence: source.sequenceNumber(),
      controllerAddress: deployment.lendingController,
    }, { ...market, accountNonce: accountId, amount: '0' })
    const preparedXdr = await prepareStellarBuiltTx(server, built, { network })
    assertStellarPreparedTxAuth(preparedXdr, {
      network, caller, builtXdr: built.xdr,
    })
    return preparedXdr
  }
  ```
</CodeGroup>

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](/docs/stellar-lending/dev/wallet-integration#4-sign-submit-and-confirm)
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](/docs/stellar-lending/dev/accounts-and-risk).

## Common errors

| Error | Cause | Fix |
| - | - | - |
| `#100 InsufficientCollateral` | LTV gate or the health-factor gate fails after the withdrawal | Withdraw less, or repay debt first. |
| `#112 InsufficientLiquidity` | Pool cash below the requested amount | Withdraw less, or wait for repayments. |
| `#126 MinBorrowCollateralNotMet` | LTV-weighted collateral below the instance floor while debt remains | Repay debt first or withdraw less. |
| `#121 CollateralPositionNotFound` | No supply position for that hub asset | Withdraw an asset the account actually supplied. |
| `#49 WithdrawRoundsToZeroShares` | The amount is too small to burn one scaled share | Withdraw more, or use the `0` full-close sentinel. |
| `#315 SpokeAssetPaused` | The listing is paused, which blocks exit too | Wait for governance to unpause. |

For contract-owned accounts, see [Vault integrations](/docs/stellar-lending/dev/vault-integrations).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.