Processing User Redemptions

Overview

User redemptions in the protocol follow an asynchronous pattern:

  1. User requests redemption (shares → Escrow)

  2. Rebalancer fulfills redemption (Node → Escrow)

  3. User claims assets (Escrow → User)

Request State Structure

struct Request {
    uint256 pendingRedeemRequest;   // Shares waiting to be processed
    uint256 claimableRedeemRequest; // Shares processed and ready
    uint256 claimableAssets;        // Assets ready for withdrawal
    uint256 sharesAdjusted;         // Shares after swing pricing
}

Step 1: User Requests Redemption

function requestRedeem(
    uint256 shares,
    address controller,
    address owner
) external returns (uint256)

Actions:

  • Validates owner permissions

  • Transfers shares to Escrow

  • Updates request state:

    request.pendingRedeemRequest += shares
    request.sharesAdjusted += adjustedShares  // If swing pricing enabled
    sharesExiting += shares  // Tracks total pending redemptions

Step 2: Rebalancer Fulfills Redemption

Three fulfillment methods:

A. From Reserve

function fulfillRedeemFromReserve(address controller)
function fulfillRedeemBatch(address[] memory controllers)

B. From ERC4626 Component

function fulfillRedeemRequest(
    address node,
    address controller,
    address component
) external returns (uint256 assetsReturned)

C. From ERC7540 Component

function fulfillRedeemRequest(
    address node,
    address controller,
    address component
) external returns (uint256 assetsReturned)

All methods eventually call:

function finalizeRedemption(
    address controller,
    uint256 assetsToReturn,
    uint256 sharesPending,
    uint256 sharesAdjusted
) external

Which:

  • Burns shares from Escrow

  • Updates request state:

    request.pendingRedeemRequest -= sharesPending
    request.claimableRedeemRequest += sharesPending
    request.claimableAssets += assetsToReturn
    request.sharesAdjusted -= sharesAdjusted
    sharesExiting -= sharesPending
  • Transfers assets to Escrow

Step 3: User Claims Assets

Users can claim using either:

function withdraw(uint256 assets, address receiver, address controller)
function redeem(uint256 shares, address receiver, address controller)

These functions:

  • Check available assets via maxWithdraw() or maxRedeem()

  • Transfer assets from Escrow to receiver

  • Decrement claimable amounts

Important Notes

  1. Liquidation Order

    • Reserve is always used first

    • Components follow liquidationQueue order

    • Enforced by enforceLiquidationOrder()

  2. Swing Pricing

    • Applied at request time

    • Stored in sharesAdjusted

    • Affects final asset amount

  3. State Tracking

    • sharesExiting tracks total pending redemptions

    • Used for reserve calculations

    • Updated during request and fulfillment

  4. Timing

    • Fulfillment only during rebalance window

    • Claims can happen anytime

    • No timeout on pending requests

Last updated