Withdrawal Queue Mechanics

Overview

The withdrawal queue system orchestrates asset withdrawals across multiple chains and vaults through two fixed-size queues:

  • Local queue for same-chain vaults

  • Cross-chain queue for vaults on other networks

Queue Structure

    // Fixed size for all queues
    uint256 public constant WITHDRAWAL_QUEUE_SIZE = 30;
    
    // Queue storage
    uint256[WITHDRAWAL_QUEUE_SIZE] public localWithdrawalQueue;
    uint256[WITHDRAWAL_QUEUE_SIZE] public xChainWithdrawalQueue;

Queue Management

Queue Registration

    /// @notice Add a new vault to the portfolio
    /// @param chainId chainId of the vault
    /// @param superformId id of superform in case its crosschain
    /// @param vault vault address
    /// @param vaultDecimals decimals of ERC4626 token
    /// @param oracle vault shares price oracle
   function addVault(
        uint32 chainId,
        uint256 superformId,
        address vault,
        uint8 vaultDecimals,
        ISharePriceOracle oracle
    )
        external
        onlyRoles(MANAGER_ROLE)
    {
        if (superformId == 0) revert();
        // If its already listed revert
        if (isVaultListed(vault)) revert VaultAlreadyListed();

        // Save it into storage
        vaults[superformId].chainId = chainId;
        vaults[superformId].superformId = superformId;
        vaults[superformId].vaultAddress = vault;
        vaults[superformId].decimals = vaultDecimals;
        vaults[superformId].oracle = oracle;
        uint192 lastSharePrice = vaults[superformId].sharePrice(asset()).toUint192();
        if (lastSharePrice == 0) revert();
        _vaultToSuperformId[vault] = superformId;

        if (chainId == THIS_CHAIN_ID) {
            // Push it to the local withdrawal queue
            uint256[WITHDRAWAL_QUEUE_SIZE] memory queue = localWithdrawalQueue;
            for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
                if (queue[i] == 0) {
                    localWithdrawalQueue[i] = superformId;
                    break;
                }
            }
            // If its on the same chain perfom approval to vault
            asset().safeApprove(vault, type(uint256).max);
        } else {
            // Push it to the crosschain withdrawal queue
            uint256[WITHDRAWAL_QUEUE_SIZE] memory queue = xChainWithdrawalQueue;
            for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
                if (queue[i] == 0) {
                    xChainWithdrawalQueue[i] = superformId;
                    break;
                }
            }
        }

        emit AddVault(chainId, vault);
    }

Withdrawal Processing

State Tracking

Withdrawal Route Calculation

Queue Processing Logic

Asset Tracking

Optimization Strategies

Gas Optimizations

  1. Prioritizes idle assets (no withdrawal cost)

  2. Processes local withdrawals before cross-chain

  3. Batches cross-chain operations

  4. Uses unchecked blocks for counters

  5. Caches chain indexes and lengths

Slippage Protection

Asset Validation

Gas Analysis

  1. Estimated Costs

    • Local withdrawals: ~100k-200k gas

    • Cross-chain operations: varies by chain

    • Batch processing savings

  2. Queue Security Implications

    • Maximum queue size impact

    • Reordering attack vectors

    • Front-running mitigations

  3. Slippage Protection Analysis

    • Minimum output validation

    • Cross-chain slippage handling

    • Price impact considerations

Error Types

Last updated