Withdrawal Queue Mechanics

Overview

The withdrawal queue system is a critical component that manages and optimizes asset withdrawals across multiple chains and vaults. It maintains two fixed-size queues:

  • Local queue for same-chain vaults

  • Cross-chain queue for vaults on other networks

Queue Management

Queue Structure

// Fixed size queues for withdrawal prioritization
uint256[WITHDRAWAL_QUEUE_SIZE] public localWithdrawalQueue;
uint256[WITHDRAWAL_QUEUE_SIZE] public xChainWithdrawalQueue;

Queue Registration

When a new vault is added, it's automatically registered in the appropriate queue based on its chain:

function addVault(
    uint64 chainId,
    uint256 superformId,
    address vault,
    // ... other params
) external onlyRoles(ADMIN_ROLE) {
    // Validate and store vault data
    
    if (chainId == THIS_CHAIN_ID) {
        // Add to local queue
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
            if (localWithdrawalQueue[i] == 0) {
                localWithdrawalQueue[i] = superformId;
                break;
            }
        }
    } else {
        // Add to cross-chain queue
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
            if (xChainWithdrawalQueue[i] == 0) {
                xChainWithdrawalQueue[i] = superformId;
                break;
            }
        }
    }
}

Withdrawal Processing

State Tracking

struct ProcessRedeemRequestCache {
    // Per-chain tracking
    uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] dstVaults;      // Target vaults
    uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] sharesPerVault; // Shares to withdraw
    uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] assetsPerVault; // Expected assets
    uint256[N_CHAINS] lens;                                  // Vaults per chain
    
    // Global tracking
    uint256 amountToWithdraw;       // Remaining to withdraw
    uint256 sharesFulfilled;        // Processed shares
    uint256 totalClaimableWithdraw; // Available for immediate withdrawal
    uint256 totalAssets;           // Total vault assets
    uint256 totalIdle;             // Unallocated assets
    uint256 totalDebt;             // Allocated assets
    uint256 assets;                // Requested withdrawal
    
    // Operation type flags
    bool isSingleChain;
    bool isMultiChain;
    bool isMultiVault;
}

Withdrawal Route Calculation

The route calculator follows a strict priority order:

  1. Check Idle Assets

if (_totalIdle >= cache.assets) {
    // Fulfill directly from idle
    cache.totalClaimableWithdraw = cache.assets;
    cache.sharesFulfilled = config.shares;
    return;
}
  1. Calculate Required Assets

cache.amountToWithdraw = cache.assets - _totalIdle;
  1. Process Withdrawal Queues

function _prepareWithdrawalRoute(
    ProcessRedeemRequestCache memory cache
) private view {
    // Process local queue first
    _exhaustWithdrawalQueue(cache, localWithdrawalQueue, false);
    
    // Process cross-chain queue if needed
    _exhaustWithdrawalQueue(cache, xChainWithdrawalQueue, true);
}

Queue Processing Logic

function _exhaustWithdrawalQueue(
    ProcessRedeemRequestCache memory cache,
    uint256[WITHDRAWAL_QUEUE_SIZE] memory queue,
    bool resetValues
) private view {
    // Iterate through queue
    for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
        // Exit conditions
        if (queue[i] == 0 || 
            (resetValues && cache.amountToWithdraw == 0)) {
            break;
        }

        // Calculate maximum withdrawal
        VaultData memory vault = vaults[queue[i]];
        uint256 maxWithdraw = vault.convertToAssets(
            _sharesBalance(vault), 
            true
        );

        // Calculate withdrawal amount
        uint256 withdrawAssets = Math.min(
            maxWithdraw,
            cache.amountToWithdraw
        );
        
        if (withdrawAssets > 0) {
            // Update state tracking
            _updateWithdrawalCache(cache, vault, withdrawAssets);
        }
    }
}

Optimization Mechanisms

1. Cost Optimization

  • Prioritizes idle assets (no withdrawal cost)

  • Prefers local withdrawals (lower gas)

  • Batches cross-chain operations (reduced bridge fees)

2. Gas Optimization

// Batch multiple withdrawals when possible
function divestSingleDirectMultiVault(
    address[] calldata vaultAddresses,
    uint256[] calldata shares,
    uint256[] calldata minAssetsOuts
) external payable returns (uint256[] memory assets)

3. Slippage Protection

// Minimum output validation
if (assets < minAssetsOut) {
    revert InsufficientAssets();
}

Error Handling

1. Withdrawal Failures

// Handle partial fulfillment
if (settledAssets < requestedAssets) {
    // Update state and emit event
    emit PartialFulfillment(controller, settledAssets);
}

2. Bridge Failures

function handleFailedMessage(
    uint256 superformId,
    bytes memory failureData
) external {
    require(msg.sender == address(gateway), "Only Gateway");
    
    // Reverse pending states
    uint256 failedAmount = pendingXChainInvests[superformId];
    pendingXChainInvests[superformId] = 0;
    _totalIdle += failedAmount;
}

Last updated