A vault depositor can request a withdrawal at any time. Whether that withdrawal completes immediately or has to wait depends on where the vault’s capital is and how it can be unwound. This page is the model — the buffer that absorbs normal withdrawals, the rules that govern instant exits, and the withdrawal queue primitive that handles everything else.Documentation Index
Fetch the complete documentation index at: https://kamino.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
The three liquidity layers
When a depositor redeems shares, the vault tries to satisfy the request from three sources, in order:- Unallocated buffer — capital sitting idle in the vault, immediately available.
- Standard allocations — capital deployed into reserves that have free liquidity (i.e. not all borrowed). The vault can pull what’s available.
- The withdrawal queue — for any portion that can’t be served instantly. This is the exit path for capital locked in fixed-rate reserves or fully-utilized reserves.
The unallocated buffer
The buffer is the simplest layer: capital that’s intentionally not deployed. The vault holds it as the deposit token, available for any withdrawal request. The size is governed by two parameters:| Parameter | Effect |
|---|---|
UnallocatedWeight | Relative weight for unallocated funds; participates in the total weight calculation alongside reserve allocations |
UnallocatedTokensCap | Hard cap on the buffer regardless of weight |
UnallocatedWeight and UnallocatedTokensCap as part of allocations — see Concepts → Allocations for the model and Configure allocations for the workflow.
Instant withdrawals
When the vault can satisfy the redemption from buffer + reserve liquidity, the user gets the deposit token in one transaction. The vault:- Burns the redeeming shares from the user.
- Pulls from the unallocated buffer first.
- If still short, redeems cTokens from Standard allocations against reserves with free liquidity.
- Charges the configured withdrawal penalty (returns to vault).
- Sends the deposit tokens to the user.
- Reserve utilization. The vault can only pull from a reserve to the extent the reserve has uncommitted capital. A 100% utilized reserve has nothing to redeem.
- Withdrawal penalty floor. If the available portion is below the configured
WithdrawalPenaltyLamports, the withdraw leg reverts. The fix in this case is to skip the instant leg entirely and enqueue the full amount (the SDK exposesskipWithdrawLegfor this). The penalty itself is set at vault creation — see Create a vault and Yield & fees → The withdrawal penalty. - Conditional allocations don’t help here. Capital “in” a Conditional allocation is actually still in the underlying floating reserve — so it counts toward instant capacity. But once a Conditional allocation has been filled (committed to a fixed-rate reserve), that capital is locked for the loan term.
The withdrawal queue
When part or all of a redemption can’t be served instantly, the remainder enters the withdrawal queue. The queue is a per-reserve FIFO that fills automatically as capital re-enters the reserve. This is a fundamental Kamino primitive. It’s used for vault depositor redemptions (the Private Credit V2 redemption flow is built on it) and for curator-side exits from fixed-rate reserve allocations. Both consume the same machinery.How it works
Each reserve maintains its own FIFO queue. When a withdrawal can’t be served instantly:- The vault calls
enqueue_to_withdrawon the relevant reserve, submitting a withdrawal ticket with a sequence number. - The ticket waits at its position in the queue.
- As liquidity returns to the reserve (from any source — see below), the head ticket fills first. If the available liquidity covers the head ticket fully, the queue advances. If it’s a partial fill, the head ticket stays at position 0 with the remainder.
- When the user’s ticket fully fills, the deposit tokens are delivered to their destination token account.
next_withdrawable_ticket_sequence_number, enforced by the on-chain PDA seed. You cannot skip ahead.
What feeds the queue
Three on-chain events return liquidity to a reserve:| Source | Trigger |
|---|---|
| Borrower repayments | Any repay — early (with penalty if applicable), at maturity, or via a rollover that lands in a different reserve |
| New deposits | Standard-allocation deposits from another vault, retail supply if the reserve allows it, or rebalance settlements |
| Liquidations | Both regular collateral-health liquidations and protocol-enforced liquidations (term-breach, maturity-breach for fixed-rate reserves) |
withdraw_queued_liquidity against the head ticket. Anyone can run their own bot; in practice Kamino’s runs reliably.
What the queue takes precedence over
The design rule is: lender exit takes precedence over borrower stay-in or new entry. Concretely:- A queued ticket blocks rollover for every borrower in that reserve. Borrowers at maturity must repay; they cannot extend.
- Tickets are filled before any new borrow-order fill takes liquidity.
- Tickets are filled before any regular borrow draws available capital.
- Tickets are filled before fee accrual claims would settle.
Lifecycle of a ticket
- No notice period. Tickets take effect immediately. Queue when you decide to.
- Cancellation is free. Tickets can be cancelled any time before they fully fill. Speculative queue submissions cost nothing if you change your mind.
- Recovery for invalid tickets. If a ticket’s destination token account becomes invalid mid-queue (frozen, delegated, wrong mint), the protocol marks the ticket invalid and the head advances past it. The owner calls
recover_invalid_ticket_collateralto retrieve their cTokens.
Two integration paths
Vaults expose the queue through two distinct flows. Both are available in the SDK.Vault depositor redemption (withdrawRedeemAndEnqueueIxs)
The orchestrator helper for end users redeeming vault shares. Sends up to three sequential transactions:
- Withdraw — pull whatever instant liquidity exists (buffer + redeemable reserve liquidity) and send to the user.
- Redeem-in-kind — exchange the user’s remaining shares for cTokens of the underlying reserves, proportional to vault exposure.
- Enqueue — submit those cTokens as withdrawal tickets against each reserve.
Curator-side disinvestment
A curator wanting to reduce or remove a Standard allocation to a high-utilization reserve (especially a fixed-rate reserve) faces the same constraint: the capital is locked. The vault submits a withdrawal ticket against the reserve. As liquidity returns, the ticket fills and the cTokens land back in the vault, where the rebalancer redeploys them per current target weights. To trigger a disinvestment from a high-utilization reserve, lower the allocation’s weight or cap via Configure allocations. For the FR-specific view of the same flow, see Fixed Rates → Lifecycle → Exiting via the withdrawal queue.Strategic implications
The queue isn’t just an exit mechanism — once you understand its dynamics, it’s a position-management lever:- Queue depth as a demand signal. A reserve with deep queued tickets is one where any returning liquidity is already spoken for. Adding new allocation there means going to the back of the line.
- Queue early as a forcing function. If you know you want out by a given date, queue ahead. The ticket sits cheaply (cancellable for free) and locks in priority for the next repayment cycle.
- Cancel and resubmit are free. Manage your queue position responsively.
- Available liquidity ≠ borrowable liquidity. A reserve’s nominal
available_liquidityis gross; what’s actually available for a new borrow isavailable_liquidity − queued_amount. Both numbers matter.
Required market flags
The queue is gated by three market-level flags. A market needs all three set for the full lifecycle:| Flag | Required for |
|---|---|
withdraw_ticket_issuance_enabled | Submitting tickets via enqueue_to_withdraw |
withdraw_ticket_redemption_enabled | Filling tickets via withdraw_queued_liquidity |
withdraw_ticket_cancellation_enabled | Cancelling tickets |
min_withdraw_queued_liquidity_value (default 2), the anti-dust floor for new tickets and partial-fill remainders. These are set by market managers — see Markets → Fixed Rates → Market Settings.
Edge cases worth knowing
- Dust progress stalls. If a head ticket’s remainder falls below
min_withdraw_queued_liquidity_value, the WQP bot won’t fill it. The ticket stays head-of-queue until enough new liquidity arrives to clear the threshold in one shot. - Same-tx open-and-close prevention. A ticket opened and closed in the same transaction is detected and rejected. This protects the allocation priority system from being exploited.
- Vault-owned tickets need callback support. When a vault submits a ticket against a reserve, the on-chain
progress_callback_typeis set so vault accounting stays in sync as the ticket fills. Older kvault versions don’t support this; ensure your vault is on a recent release. - The vault
investoperation does not auto-queue. If you decrease a Standard allocation’s weight on a fully-utilised reserve, the rebalancer won’t automatically submit a withdrawal ticket — you trigger it explicitly.
What’s next
Allocations
The allocation primitive, including the unallocated buffer.
Configure allocations
Operational walkthrough — adjust the unallocated buffer, increase/decrease allocations to trigger queued exits.
Fixed Rates → Lifecycle
The FR-specific operational treatment of exits, including the rollover-blocking rule and queue-as-strategy.