Skip to main content
The withdrawal queue is a market-level mechanism that lets depositors hold a place in line for liquidity when a reserve is fully utilized. Instead of a withdrawal reverting because the available pool is empty, the depositor enqueues a WithdrawTicket and is paid out FIFO as borrowers repay, deposits arrive, or liquidations free liquidity. The queue is opt-in per market, controlled by three boolean flags on the LendingMarket account.

When to enable the queue

Three flags, three operations

Curators flip these together when launching the queue. The most useful intermediate state is issuance + redemption enabled, cancellation disabled — depositors can join the line and be paid, but cannot back out, which simplifies accounting for vaults sitting on top.

The minimum queued value threshold

min_withdraw_queued_liquidity_value sets the minimum USD value (scaled fraction) a single ticket may represent. Below the threshold, enqueue-to-withdraw reverts with WithdrawTicketValueTooSmall.

Configure the queue via SDK

Enabling the queue is a market-level config update. Use kaminoManager.updateLendingMarketIxs and toggle the relevant fields.

User-side queue operations

The user-facing queue instructions (enqueueToWithdraw, withdrawQueuedLiquidity, cancelWithdrawTicket, recoverInvalidTicketCollateral) are part of the on-chain klend program. The current public klend-sdk does not yet expose dedicated TypeScript helpers for these.Until the helpers ship, end-user apps integrate the queue via:
  • A direct kvault deposit/redeem flow when a vault sits on top of the market (the vault submits the ticket on the user’s behalf via its own kvault tooling)
  • The Kamino webapp surface for queue-enabled markets that are listed in resources.json
  • Building the ixes manually from the program IDL
For curator-side enablement, the SDK flow above is the only thing you need.

Anatomy of a ticket

When a depositor calls enqueue-to-withdraw, the program:
  1. Burns their collateral cTokens from their wallet
  2. Increments the reserve’s WithdrawQueue.queued_collateral_amount
  3. Creates a WithdrawTicket account with:
    • sequence_number (monotonically increasing per reserve)
    • owner (the depositor’s wallet)
    • reserve (the reserve being withdrawn from)
    • queued_collateral_amount (the cTokens held in queue)
    • created_at_timestamp
    • progress_callback_type and progress_callback_custom_accounts (optional callback hook)
The ticket is a Solana account. The depositor (or whoever submitted on their behalf) holds the right to redeem when their sequence number is up.

Sequence numbers and FIFO order

The reserve tracks two counters:
A ticket with sequence number N is redeemable when next_withdrawable_ticket_sequence_number == N, provided the reserve has enough liquidity to satisfy it.

The redemption flow

The reserve gains liquidity over time through borrower repayments, new deposits, liquidations, and (for markets with a vault sitting on top) the vault’s invest operation routing capital in. Whenever liquidity is available, the holder of the next-eligible ticket can call withdraw-queued-liquidity. The program checks the ticket’s sequence_number against the reserve’s next_withdrawable_ticket_sequence_number; if they match, it pays out as much of the queued collateral as the available liquidity covers. Partial fills are allowed: a ticket that asks for $100k against a reserve with $30k free liquidity is paid $30k now and waits for the rest. When a ticket is fully drained, the program closes its account and increments next_withdrawable_ticket_sequence_number so the next ticket in line becomes eligible. Holders watch the queue and submit the redemption transaction when liquidity allows; in practice, off-chain bots monitor and submit on behalf of users, which is how the standard Kamino UX surfaces the queue to depositors.

Cancellation

When withdraw_ticket_cancellation_enabled = 1, a ticket holder can call cancel-withdraw-ticket to back out of the queue:
  • The remaining queued_collateral_amount is converted back to cTokens and returned to the holder
  • The ticket is marked invalid = 1 and closed
  • next_withdrawable_ticket_sequence_number does not advance — the cancelled slot is skipped on the next redemption
Cancellation is a depositor-friendly feature. Disable it for institutional vaults where queue position is sold or transferred contractually under the off-chain agreement.

Recovering invalid tickets

If a ticket gets stuck in an invalid state (the program detects this on certain edge cases), the curator or emergency authority can call recover-invalid-ticket-collateral to drain its queued collateral and restore queue progression.

Vault integration: progress callback

A WithdrawTicket can carry an optional progress callback. When the ticket completes redemption, the program invokes the callback to notify a corresponding program — most commonly a Kamino vault.
If a kvault submits the enqueue-to-withdraw on behalf of one of its depositors, the ticket can carry KlendQueueAccountingHandlerOnKvault so that on redemption, the kvault is automatically notified to credit the depositor’s vault share. This is the standard pattern for institutional vaults sitting on top of a queue-enabled market.

Common errors

Reference