Purpose
TheRedeemQueue contract enables delayed, batched redemptions of vault shares into underlying assets. Redemptions are processed in two phases:
- Oracle pricing – Shares are priced via a trusted price report.
- Liquidity settlement – Vault liquidity is allocated to fulfill priced requests.
Overview
TheRedeemQueue enables users to convert their vault shares into underlying assets, introducing a time delay enforced by an oracle-defined redeemInterval. It maintains the following core invariants:
- Request Format: Each request is structured as a
(shares, timestamp)pair. - Non-Cancellable: Redemption requests cannot be cancelled to prevent griefing (e.g., submitting and canceling after unstaking starts).
- Multiple Requests Allowed: Users may submit multiple independent redemption requests.
reportTimestamp, the system processes all requests with:
Liquidity Processing (Two-Stage)
To enable flexible and asynchronous liquidity management, redemption is handled in two distinct phases:- Post-Request: Vault curators monitor and, if needed, pull liquidity from external protocols.
-
Post-Oracle Report:
- Once a valid report is submitted and sufficient liquidity is available,
- Anyone can call
handleBatches(n)on theRedeemQueue. The function has no access control, and in practice the curator or a keeper calls it, - This action triggers the movement of required assets from the vault (and associated subvaults) to process redemption requests.
Function: redeem
- Reverts with
ZeroValueifsharesis zero, or withQueuePausedif the vault has paused the queue. - Locks
sharesfrom the caller withshareManager.lock(caller, shares). Locked shares move to the share manager’s own balance and no longer count as the caller’s active shares. - Unless the caller is the fee recipient, computes the redeem fee with
feeManager.calculateRedeemFee(shares). The fee is burned from the locked shares, minted to the fee recipient and subtracted from the request. - Adds the remaining shares to the request at the current timestamp and emits
RedeemRequested(account, shares, timestamp).
Function: handleBatches
batches priced batches, in order, starting from batchIterator:
- Reads available liquidity with
vault.getLiquidAssets(), which uses the queue’s redeem hook. - Takes batches while their cumulative
assetsfit within that liquidity, and stops at the first batch that does not fit. - Calls
vault.callHook(demand), so the redeem hook pulls the assets from subvaults and the vault transfers them to the queue. - Decreases the vault balance in the
RiskManagerandtotalDemandAssets, advancesbatchIteratorand emitsRedeemRequestsHandled(counter, demand).
handleBatches.
Scalability Approach
Unlike deposits, redemption requests are never cancelled, which allows for a simplified and gas-efficient tracking model: A prefix sum array is used to efficiently manage cumulative share redemptions over time.Redemption Processing Logic
-
On Redemption:
When a user redeems
amountof shares at timeT, the system logs:prefixSum[T] += amount -
On Oracle Report:
At
reportTimestamp, all requests with:are priced into a new batch. The batch’s shares are burned from the share manager’s locked balance, and its asset value (shares * 1e18 / priceD18) is added tototalDemandAssets. -
Post-Processing:
- The curator ensures the necessary asset liquidity is available,
- Then anyone, usually the curator or a keeper, calls
handleBatches()to finalize processing.
-
User Claim:
After requests are processed, users can call:
to claim assets for their requested vault shares corresponding to each processed timestamp.
Storage Layout
All internal state is maintained inRedeemQueueStorage, including:
Structs
Request
Represents a single redemption request from a user:
timestamp: When the request was submitted.shares: Amount of vault shares being redeemed.isClaimable: Set to true after batch is fulfilled.assets: Amount of assets claimable for this request (set after pricing).
Batch
Represents a priced redemption batch:
assets: Total value fulfilled for the batch (via oracleshares / report.price).shares: Total shares matched in this batch.
View Functions
requestsOf(account, offset, limit)
Returns paginated redemption request data for the specified account. Each request includes:
- Timestamp
- Shares
- Claimable status
- Asset amount
batchAt(index)
Returns the (assets, shares) for a given redemption batch.
getState()
Returns core system state:
- Current
batchIterator(next unfulfilled batch index) - Total
batches - Total
demandedAssetsstill awaiting liquidity - Total
pendingSharesthat are not yet claimable
State Transition Guarantees
- Non-Cancellable Requests
- Prevents griefing where a user requests redemption, causing curator to pull liquidity, then cancels.
- Price Separation
- Oracle reports must be delayed by at least
redeemIntervalseconds from the original request.
- Oracle reports must be delayed by at least
- Asynchronous Fulfillment
- Liquidity can be managed independently of oracle report submission.
Events
RedeemRequested(account, shares, timestamp)RedeemRequestClaimed(account, receiver, assets, timestamp)RedeemRequestsHandled(counter, demand)