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:

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

  • 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)

  • 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

TypeScript — queued path


Wind-down path

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

  • 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


Last updated