> For the complete documentation index, see [llms.txt](https://docs.keystonefi.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keystonefi.xyz/keystone-finance/withdraw.md).

# Withdraw

Burn `ksUSD` to receive USDC. Two normal paths plus a wind-down path.

| Path                                                     | When to use                                  | Speed                                                                                                     |
| -------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Instant** (`withdraw_instant`)                         | Vault has enough idle USDC                   | One transaction                                                                                           |
| **Queued** (`request_withdrawal` + `process_withdrawal`) | Withdrawal larger than the liquidity buffer  | Burned immediately at locked price; USDC paid out (FIFO, strict) after the keeper unwinds enough position |
| **Wind-down** (`claim_wind_down`)                        | Active only when `position_mode == WindDown` | Pro-rata redemption against the vault's idle USDC; no queue, no FIFO                                      |

* **Instant** is the primary user flow
* The liquidity buffer (default **10% of NAV**) is sized to absorb 99% of real withdrawals

***

## Instant withdrawal

```
withdraw_instant(shares: u64)
```

* Burns `shares` of `ksUSD`
* Pays out USDC from the vault's idle balance at the current share price

| Account              | Mutability | Purpose                                 |
| -------------------- | ---------- | --------------------------------------- |
| `vault`              | mut        | Vault PDA                               |
| `vault_usdc_account` | mut        | Vault USDC ATA — source of payout       |
| `ksusd_mint`         | mut        | ksUSD share mint                        |
| `user_ksusd_account` | mut        | User's ksUSD ATA (must hold ≥ `shares`) |
| `user_usdc_account`  | mut        | User's USDC destination                 |
| `user`               | signer     | Withdrawer                              |
| `token_program`      | —          | SPL token program                       |

Math:

```
usdc_owed = shares × share_price_1e9 / 1e9
```

**Reverts with `InsufficientLiquidityBuffer`** if `vault_usdc_account.amount < usdc_owed` — in that case use the queued path.

***

## Queued withdrawal

When the vault doesn't have enough idle USDC to pay you instantly:

* Queue a request
* Shares burn immediately at the current share price → **redemption value is locked**
* A `WithdrawalRequest` PDA is created
* A permissionless keeper processes it once the position is unwound and the buffer refills

### Step 1 — request

```
request_withdrawal(shares: u64)
```

* Burns shares
* Creates a request PDA at `[b"withdrawal_request", vault, queue_next_id]`
* Locks `usdc_owed = shares × share_price_1e9 / 1e9` on the request record

| Account                            | Mutability  | Purpose                                           |
| ---------------------------------- | ----------- | ------------------------------------------------- |
| `vault`                            | mut         | Vault PDA                                         |
| `withdrawal_request`               | init        | New per-request PDA (payer = user)                |
| `ksusd_mint`                       | mut         | ksUSD share mint                                  |
| `user_ksusd_account`               | mut         | User's ksUSD ATA (burned from)                    |
| `user_usdc_account`                | —           | User's USDC destination (recorded on the request) |
| `user`                             | signer, mut | Requester (pays rent)                             |
| `token_program` / `system_program` | —           | —                                                 |

### Step 2 — process (permissionless crank)

```
process_withdrawal()
```

* Anyone can call this — including the requester
* **Strict FIFO**: the next request must be `queue_processed_through + 1`; any other request reverts with `WithdrawalNotNextInQueue`
* Pays out USDC **capped at the live share price** — depositors never extract more than pro-rata if NAV has fallen since queueing
* **Closes the PDA**, refunding rent to the original requester

| Account              | Mutability | Purpose                                      |
| -------------------- | ---------- | -------------------------------------------- |
| `vault`              | mut        | Vault PDA                                    |
| `withdrawal_request` | mut        | The queued request (will be closed)          |
| `vault_usdc_account` | mut        | Vault USDC ATA — source of payout            |
| `user_usdc_account`  | mut        | Recorded destination from the request        |
| `recipient_for_rent` | mut        | Original requester (rent refund destination) |
| `cranker`            | signer     | Anyone can crank                             |
| `token_program`      | —          | —                                            |

***

## TypeScript — instant path

```ts
const tx = await program.methods
  .withdrawInstant(new BN("25_000_000"))    // 25 ksUSD
  .accountsStrict({
    vault: vaultPda,
    vaultUsdcAccount: vaultUsdcAta,
    ksusdMint: vault.ksusdMint,
    userKsusdAccount: userKsusdAta,
    userUsdcAccount: userUsdcAta,
    user: user.publicKey,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .rpc();
```

## TypeScript — queued path

```ts
const nextId = vault.queueNextId.toString();
const [requestPda] = PublicKey.findProgramAddressSync(
  [
    Buffer.from("withdrawal_request"),
    vaultPda.toBuffer(),
    new BN(nextId).toArrayLike(Buffer, "le", 8),
  ],
  PROGRAM_ID
);

await program.methods
  .requestWithdrawal(new BN("100_000_000_000"))   // 100,000 ksUSD
  .accountsStrict({
    vault: vaultPda,
    withdrawalRequest: requestPda,
    ksusdMint: vault.ksusdMint,
    userKsusdAccount: userKsusdAta,
    userUsdcAccount: userUsdcAta,
    user: user.publicKey,
    tokenProgram: TOKEN_PROGRAM_ID,
    systemProgram: SystemProgram.programId,
  })
  .rpc();

// Later, after the keeper has unwound enough position:
await program.methods
  .processWithdrawal()
  .accountsStrict({
    vault: vaultPda,
    withdrawalRequest: requestPda,
    vaultUsdcAccount: vaultUsdcAta,
    userUsdcAccount: userUsdcAta,
    recipientForRent: user.publicKey,
    cranker: anyWallet.publicKey,
    tokenProgram: TOKEN_PROGRAM_ID,
  })
  .rpc();
```

***

## Wind-down path

Once the admin invokes `init_wind_down`, the vault stops accepting deposits and new positions. Users redeem with:

```
claim_wind_down(shares: u64)
```

* Pays USDC pro-rata against vault idle USDC at the live `effective_nav` share price
* No queue, no rent refund, no FIFO
* The residual settlement path, **not** a normal operational mode
* Reverts unless `position_mode == WindDown`

***

## Events

* `WithdrawEvent` — emitted by `withdraw_instant`
* `WithdrawalRequested` — emitted by `request_withdrawal`
* `WithdrawalProcessed` — emitted by `process_withdrawal`
* `WindDownClaimed` — emitted by `claim_wind_down`

***

## Related

* [Deposit](/keystone-finance/deposit.md) · [Check position & NAV](/keystone-finance/check-position.md)
* [Fees](/reference/fees.md) — no withdrawal fees on either path
* [Errors](/for-developers/errors.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keystonefi.xyz/keystone-finance/withdraw.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
