Withdraw
Burn ksUSD to receive USDC. Two normal paths plus a wind-down path.
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
sharesofksUSDPays out USDC from the vault's idle balance at the current share price
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
WithdrawalRequestPDA is createdA 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 / 1e9on the request record
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 withWithdrawalNotNextInQueuePays 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
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_navshare priceNo queue, no rent refund, no FIFO
The residual settlement path, not a normal operational mode
Reverts unless
position_mode == WindDown
Events
WithdrawEvent— emitted bywithdraw_instantWithdrawalRequested— emitted byrequest_withdrawalWithdrawalProcessed— emitted byprocess_withdrawalWindDownClaimed— emitted byclaim_wind_down
Related
Fees — no withdrawal fees on either path
Last updated