# MetaVault

###


# Introduction

### Protocol Overview

MetaVault is an advanced implementation of the ERC7540 standard enabling cross-chain yield aggregation through integration with the Superform protocol. Built on ERC4626 principles, the vault manages assets across multiple blockchain networks while providing advanced performance tracking, fee distribution systems, and robust risk management controls.\
\
Github: <https://github.com/VerisLabs/metavault>

### Technical Architecture

#### Core Components

1. **MetaVault (Core)**
   * ERC7540-compliant vault with ERC4626 base functionality
   * Asset allocation and tracking through NFT-based positions
   * Performance-based fee system with high watermark tracking
   * Cross-chain position management via Superform integration
2. **ERC7540Engine**
   * Asynchronous withdrawal request processing
   * Priority-based withdrawal queue implementation
   * Receiver contract system for cross-chain settlements
   * Optimized multi-chain withdrawal routing
3. **AssetsManager**
   * Direct and cross-chain portfolio allocation
   * ERC4626-compatible investment operations
   * Cross-chain debt and position tracking
   * Manager-controlled rebalancing and reconciliation
4. **Gateway System**
   * ERC20 asset bridging via Superform protocol
   * NFT-based position management (SuperPositions)
   * Cross-chain receiver contract deployment
   * Failed transaction recovery system

### Key Technical Features

#### Cross-Chain Operations

```solidity
// Cross-chain investment with receiver system and gas handling
function investSingleXChainSingleVault(SingleXChainSingleVaultStateReq calldata req)
    external
    payable
    onlyVault
    refundGas  // Important: Handles crosschain gas refunds
{
    // Validate vault in approved list
    if (!isVaultListed(vaultAddress)) revert VaultNotListed();
    
    // Deploy or retrieve receiver 
    address receiverAddress = getReceiver(key);
    ERC20Receiver(receiverAddress).setMinExpectedBalance(req.outputAmount);
    
    // Track pending investment
    pendingXChainInvests[superformId] += amount;
    totalpendingXChainInvests += amount;
    
    // Initiate cross-chain transfer with gas refund
    gateway.investSingleXChainSingleVault{value: msg.value}(req);
}
```

* Asynchronous settlement system via receiver contracts
* NFT-based position tracking through SuperPositions
* Cross-chain message verification
* Bridge failure recovery mechanisms

#### Risk Management

```solidity
// Emergency controls with recovery system
modifier noEmergencyShutdown() {
    if (emergencyShutdown) {
        revert VaultShutdown();
    }
    _;
}

function setRecoveryAddress(address _recoveryAddress) external onlyRoles(ADMIN_ROLE) {
    if (_recoveryAddress == address(0)) revert InvalidRecoveryAddress();
    recoveryAddress = _recoveryAddress;
}
```

* Emergency shutdown with recovery procedures
* Share locking with time-based restrictions
* Minimum output protection for all operations
* Multi-level oracle price validation

#### Performance Tracking

```solidity
// High watermark with fee calculation
modifier updateGlobalWatermark() {
    _;
    uint256 sp = sharePrice();
    assembly {
        let spwm := sload(sharePriceWaterMark.slot)
        if lt(spwm, sp) { sstore(sharePriceWaterMark.slot, sp) }
    }
}

function hurdleRate() public view returns (uint256) {
    return _hurdleRateOracle.getRate(asset());
}
```

* Performance fee calculation using high watermark
* Dynamic hurdle rate tracking
* Cross-chain price aggregation
* Protocol-level yield optimization

### Security Model

#### Access Control

```solidity
uint256 public constant ADMIN_ROLE = _ROLE_0;      // Protocol administration
uint256 public constant EMERGENCY_ADMIN_ROLE = _ROLE_1; // Emergency controls
uint256 public constant ORACLE_ROLE = _ROLE_2;     // Price updates
uint256 public constant MANAGER_ROLE = _ROLE_3;    // Investment operations
uint256 public constant RELAYER_ROLE = _ROLE_4;    // Settlement processing
```

* Role-based permission system
* Relayer-specific settlement controls
* Role-restricted administrative functions
* Emergency override capabilities

#### Asset Safety

```solidity
// Core safety with receiver validation
error InsufficientAssets();
error VaultNotListed();
error RequestNotSettled();
error SharesLocked();
error InvalidRecoveryAddress();
error InvalidReceiver();
```

* Receiver contract validation system
* Cross-chain settlement verification
* Minimum output enforcement
* Recovery address system for failed operations
* Minimum balance requirements for receiver contracts
* Gas refund protection mechanisms
* Withdrawal queue size constraints (30 vaults max)

#### Gas Management

* `refundGas` modifier ensures cross-chain operations don't strand ETH
* Calculates and refunds unused bridge fees

### Integration Points

#### Superform Protocol

```solidity
ISuperformGateway public gateway;
ISuperPositions public superPositions;

// Initialization requires
function initialize(
    VaultConfig memory config
) {
    gateway = config.gateway;
    superPositions = config.superPositions;
    asset().safeApprove(address(gateway), type(uint256).max);
}
```

* ERC20 asset bridging capabilities
* NFT position management
* Cross-chain message routing
* Settlement verification system

#### Oracle System

```solidity
IHurdleRateOracle public _hurdleRateOracle;
ISharePriceOracle public oracle;

function setHurdleRateOracle(IHurdleRateOracle hurdleRateOracle) external onlyRoles(ADMIN_ROLE) {
    _hurdleRateOracle = hurdleRateOracle;
}
```

* Asset-specific hurdle rates
* Cross-chain price verification
* Performance benchmarking
* Oracle reward distribution

### Protocol Parameters

```solidity
// Critical protocol constants
uint256 public constant WITHDRAWAL_QUEUE_SIZE = 30; // Maximum vaults per queue
uint24 public constant REQUEST_REDEEM_DELAY = 1 days; // Withdrawal processing delay
```

#### Network Support

```solidity
uint64[N_CHAINS] public DST_CHAINS = [
    1,     // Ethereum Mainnet
    137,   // Polygon
    56,    // BNB Chain
    10,    // Optimism
    8453,  // Base
    42161, // Arbitrum One
    43114  // Avalanche
];
```

#### Fee Configuration

```solidity
uint16 public managementFee;    // Base management fee (time-based)
uint16 public performanceFee;   // Above hurdle rate fee
uint16 public oracleFee;        // Price update incentive
uint256 public sharePriceWaterMark; // High watermark tracking
```

### Technical Considerations for Auditors

#### Critical Components

1. Receiver contract deployment and validation
2. Cross-chain settlement verification
3. Asset and debt tracking accuracy
4. Fee calculation precision with watermark

#### Key Invariants

1. Total assets = idle assets + allocated assets + pending cross-chain assets
2. Share price updates maintain a high watermark
3. Fee calculations respect hurdle rates
4. Cross-chain positions match SuperPositions balances

#### Security Checkpoints

1. Recovery mechanism for failed transactions
2. Role-based access enforcement
3. Settlement verification process
4. Oracle price validation

### Protocol Constraints and Limitations

* Maximum number of vaults per chain: WITHDRAWAL\_QUEUE\_SIZE (30)
* Asset types supported: ERC20 only
* Maximum cross-chain operation timeout: determined by bridge
* Price oracle update frequency requirements

### Role Access Matrix

| Function                      | ADMIN | MANAGER | RELAYER | EMERGENCY\_ADMIN |
| ----------------------------- | ----- | ------- | ------- | ---------------- |
| addVault                      | ✓     |         |         |                  |
| investSingleDirectSingleVault |       | ✓       |         |                  |
| processRedeemRequest          |       |         | ✓       |                  |
| settleLiquidation             |       |         | ✓       |                  |
| setEmergencyShutdown          |       |         |         | ✓                |

### Protocol Constants

```solidity
uint256 public constant WITHDRAWAL_QUEUE_SIZE = 30;
uint256 public constant SECS_PER_YEAR = 31_556_952;
uint256 public constant MAX_BPS = 10_000;
uint24 public constant REQUEST_REDEEM_DELAY = 1 days;
```

### Getting Started

For detailed implementation guidelines and integration examples, refer to the subsequent sections covering specific protocol components and operations.


# Architecture

#### Inheritance Structure

```solidity
MetaVault
├── MetaVaultBase
│   └── MultiFacetProxy
│       └── OwnableRoles
├── Multicallable
└── NoDelegateCall

ERC7540Engine
└── ModuleBase
    └── OwnableRoles

AssetsManager
└── ModuleBase
    └── OwnableRoles

Gateway System
├── SuperformGateway
│   └── MultiFacetProxy
│       └── GatewayBase
├── InvestSuperform
│   └── GatewayBase
├── DivestSuperform
│   └── GatewayBase
└── LiquidateSuperform
    └── GatewayBase
```

#### Core Contract Relationships

**MetaVault Core**

```solidity
contract MetaVault {
    // Core state tracking
    uint128 internal _totalIdle;
    uint128 internal _totalDebt;
    
    // Module interfaces
    AssetsManager public assetsManager;
    ERC7540Engine public engine;
    ISuperformGateway public gateway;
    
    // Access control
    mapping(address => mapping(address => bool)) public isOperator;
    mapping(address => uint256) public positions;
}
```

**ERC7540Engine**

```solidity
contract ERC7540Engine {
    // Withdrawal state management
    struct ProcessRedeemRequestCache {
        uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] dstVaults;
        uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] sharesPerVault;
        uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] assetsPerVault;
        uint256[N_CHAINS] lens;
        // ... additional fields
    }
    
    // Withdrawal queue processing
    function _prepareWithdrawalRoute(
        ProcessRedeemRequestCache memory cache
    ) private view;
}
```

**Gateway System**

```solidity
contract GatewayBase {
    // Core gateway state
    ISuperPositions public superPositions;
    IBaseRouter public superformRouter;
    IMetaVault public vault;
    address public receiverImplementation;
    
    // Cross-chain tracking
    mapping(bytes32 => address) public receivers;
    mapping(uint256 => uint256) public pendingXChainInvests;
    uint256 public totalpendingXChainInvests;
}
```

```solidity
// Receiver contract deployment
function getReceiver(bytes32 key) public returns (address receiverAddress) {
    receiverAddress = LibClone.clone(receiverImplementation);
    ERC20Receiver(receiverAddress).initialize(key);
}
```

```
Engine Architecture Components
ERC7540EngineBase
└── Core withdrawal queue routing logic
└── State caching for cross-chain operations
└── Chain and vault selection algorithms
```

```solidity
contract ERC7540EngineBase is ModuleBase {
    // Core withdrawal routing functionality
    function _prepareWithdrawalRoute(
        ProcessRedeemRequestCache memory cache,
        bool despiseDust
    ) internal view {
        // Process local withdrawal queue
        _exhaustWithdrawalQueue(cache, localWithdrawalQueue, false, despiseDust);
        // Process cross-chain withdrawal queue
        _exhaustWithdrawalQueue(cache, xChainWithdrawalQueue, true, despiseDust);
    }
    
    // Dust threshold management
    function setDustThreshold(uint256 dustThreshold) external onlyRoles(ADMIN_ROLE) {
        // Sets minimum threshold for cross-chain withdrawals
    }
    
    function getDustThreshold() public view returns (uint256) {
        // Retrieves current minimum threshold
    }
}
```

```solidity
ERC7540EngineReader
└── Withdrawal simulation and preview
└── Route optimization analysis
```

```solidity
contract ERC7540EngineReader is ERC7540EngineBase {
    // Simulates withdrawal without execution
    function previewWithdrawalRoute(
        address controller,
        uint256 shares,
        bool despiseDust
    ) public view returns (ProcessRedeemRequestCache memory cachedRoute) {
        // Simulates complete withdrawal route
        // Calculates optimal asset sourcing from idle funds and vaults
        // Returns detailed breakdown of withdrawal strategy
    }
}
```

```
ERC7540EngineSignatures
└── Signature verification for gasless transactions
└── External processing authorization
```

```solidity
contract ERC7540EngineSignatures is ERC7540ProcessRedeemBase {
    // Verifies signed withdrawal requests
    function verifySignature(
        ProcessRedeemRequestParams calldata params,
        uint256 deadline,
        uint256 nonce,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public view returns (bool) {
        // Validates signature against expiration, nonce and request parameters
    }
    
    // Processes withdrawals initiated via signature
    function processSignedRequest(
        ProcessRedeemRequestParams calldata params,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external {
        // Processes withdrawal request authorized by signature
        // Enables gas-less withdrawals for users
    }
}
```

#### Error Catalog

```solidity
error InsufficientAssets();
error VaultNotListed();
error RequestNotFound();
error InvalidController();
error MinimumBalanceNotMet();
error InvalidSuperformId();
error InvalidRecoveryAddress();
error InvalidAmount();
error TotalAmountMismatch();
error SharesLocked();
error VaultShutdown();
error Unauthorized();
error ExceedsMaxDeposit();
error ExceedsMaxMint();
```

### State Flow Diagrams

#### Deposit Flow

1. User -> MetaVault: `requestDeposit()`
2. MetaVault: Update deposit request state
3. MetaVault -> User: `deposit()` available
4. MetaVault: Share minting and accounting

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2FrIQcojtlXKEnML3IfPdL%2Fimage.png?alt=media&amp;token=0819b4d7-895c-4af7-903c-483f846f60c3" alt=""><figcaption></figcaption></figure>

#### Investment Flow

```solidity
// Example investment flow
function investSingleXChainSingleVault(
    SingleXChainSingleVaultStateReq calldata req
) external payable onlyVault {
    // 1. Validate and prepare
    if (!isVaultListed(vaultAddress)) revert VaultNotListed();
    
    // 2. Setup receiver
    address receiver = getReceiver(key);
    
    // 3. Track investment
    pendingXChainInvests[superformId] += amount;
    
    // 4. Initiate bridge
    gateway.investSingleXChainSingleVault{value: msg.value}(req);
}
```

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2F6uPlngoxoD5pIpgE1oCG%2FScreenshot_2025-01-14_12-41-04.png?alt=media&amp;token=b3bd62fd-cfa5-4489-9e77-2057e105bc66" alt=""><figcaption></figcaption></figure>

#### Withdrawal Flow

1. User -> MetaVault: `requestRedeem()`
2. ERC7540Engine: Process withdrawal route
3. Gateway: Handle cross-chain settlements
4. MetaVault -> User: Final redemption

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2FZAwvwO2KHSoiuso1QSAa%2Fimage.png?alt=media&amp;token=925396ea-5367-4d80-83a9-62fec5b7ea40" alt=""><figcaption></figcaption></figure>

### Key Dependencies

#### External Protocol Integration

```solidity
interface ISuperformGateway {
    function investSingleXChainSingleVault(
        SingleXChainSingleVaultStateReq calldata req
    ) external payable;
    
    function divestSingleXChainSingleVault(
        SingleXChainSingleVaultStateReq calldata req
    ) external payable;
}
```

#### Oracle Integration

```solidity
interface ISharePriceOracle {
    function getLatestSharePrice(
        uint64 chainId,
        address vault
    ) external view returns (uint256);
}
```

### State Management

```solidity
// Request states
mapping(address => ERC7540_Request) private _pendingRedeemRequest;
mapping(address => ERC7540_FilledRequest) private _claimableRedeemRequest;
```

#### Critical State Variables

```solidity
struct VaultData {
    uint16 deductedFees;
    uint64 chainId;
    uint192 lastReportedSharePrice;
    uint256 superformId;
    ISharePriceOracle oracle;
    uint8 decimals;
    uint128 totalDebt;
    address vaultAddress;
}

// Vault positions
mapping(uint256 => VaultData) public vaults;
```

#### Cross-Chain State

```solidity
// Gateway state tracking
mapping(bytes32 => RequestData) public requests;
EnumerableSetLib.Bytes32Set internal _requestsQueue;
```

### Security Architecture

#### Access Control Matrix

| Role             | Permissions            |
| ---------------- | ---------------------- |
| ADMIN\_ROLE      | Protocol configuration |
| EMERGENCY\_ADMIN | Emergency controls     |
| ORACLE\_ROLE     | Price updates          |
| MANAGER\_ROLE    | Investment operations  |
| RELAYER\_ROLE    | Settlement processing  |

#### State Protection

```solidity
modifier nonReentrant() {
    require(_locked != 2, "ReentrancyGuard: reentrant call");
    _locked = 2;
    _;
    _locked = 1;
}

modifier noDelegateCall() {
    require(address(this) == __self, "DelegateCall");
    _;
}
```

### Upgrade Architecture

* Modular design through facet system
* Role-based module management
* State separation between core and modules

### Critical Paths

#### Investment Critical Path

1. Vault listing validation
2. Cross-chain message verification
3. Position tracking updates
4. Settlement confirmation

#### Withdrawal Critical Path

1. Share lock verification
2. Withdrawal route calculation
3. Cross-chain settlement
4. Final redemption processing

### Integration Points

#### Bridge Integration

```solidity
// Bridge configuration
function setGateway(ISuperformGateway _gateway) external onlyRoles(ADMIN_ROLE) {
    gateway = _gateway;
    asset().safeApprove(address(_gateway), type(uint256).max);
    gateway.superPositions().setApprovalForAll(address(_gateway), true);
}
```

#### Oracle Integration

```solidity
function setHurdleRateOracle(IHurdleRateOracle hurdleRateOracle) external onlyRoles(ADMIN_ROLE) {
    _hurdleRateOracle = hurdleRateOracle;
}
```


# Core Operations

### Error Types

```solidity
error InsufficientAssets();
error VaultNotListed();
error RequestNotFound();
error InvalidController();
error MinimumBalanceNotMet();
error InvalidSuperformId();
error InvalidRecoveryAddress();
error InvalidAmount();
error TotalAmountMismatch();
error SharesLocked();
error VaultShutdown();
error Unauthorized();
error ExceedsMaxDeposit();
error ExceedsMaxMint();
```

### Events

```solidity
event Invest(uint256 amount);
event Divest(uint256 amount);
event SettleXChainInvest(uint256 indexed superformId, uint256 assets);
event SettleXChainDivest(uint256 assets);
event ProcessRedeemRequest(address indexed controller, uint256 shares);
event FulfillRedeemRequest(address indexed controller, uint256 shares, uint256 assets);
event RequestSettled(bytes32 indexed key, address indexed controller, uint256 settledAmount);
```

### Constants

```solidity
uint256 public constant WITHDRAWAL_QUEUE_SIZE = 30;
uint256 public constant SECS_PER_YEAR = 31_556_952;
uint256 public constant MAX_BPS = 10_000;
```

### Deposit Operations

#### Atomic Deposit Flow

```solidity
// Step 1: Request Deposit
requestId = vault.requestDeposit(
    1000e6,     // Amount
    msg.sender, // Controller
    msg.sender  // Owner
);

// Step 2: Execute Deposit (same transaction)
shares = vault.deposit(
    1000e6,     // Amount
    recipient,  // Share recipient
    msg.sender  // Controller
);
```

```solidity
// Deposit validation
function _deposit(
    uint256 assets,
    uint256 shares,
    address receiver,
    address controller
)
    internal
    override
    returns (uint256 assetsReturn, uint256 sharesReturn)
{
    _updatePosition(controller, shares);
    if (lastRedeem[controller] == 0) lastRedeem[controller] = block.timestamp;
    return super._deposit(assets, shares, receiver, controller);
}

function _afterDeposit(uint256 assets, uint256 /*uint shares*/ ) internal override {
    uint128 assetsUint128 = assets.toUint128();
    _totalIdle += assetsUint128;
}
```

Key Features:

* Atomic execution via `multicall`
* Immediate request fulfillment
* Direct share minting
* No asynchronous operations

Security Considerations:

* Emergency shutdown check
* Share lock enforcement
* Balance verification

#### Alternative Deposit Methods

```solidity
// Direct minting flow
function mint(
    uint256 shares,
    address to,
    address controller
) public override noEmergencyShutdown returns (uint256 assets) {
    uint256 sharesBalance = balanceOf(to);
    assets = super.mint(shares, to, controller);
    _lockShares(to, sharesBalance, shares);
    _afterDeposit(assets, shares);
}

// Share locking mechanism
function _lockShares(
    address to, 
    uint256 sharesBalance, 
    uint256 newShares
) private {
    uint256 newBalance = sharesBalance + newShares;
    if (sharesBalance == 0) {
        _depositLockCheckPoint[to] = block.timestamp;
    } else {
        _depositLockCheckPoint[to] = 
            ((_depositLockCheckPoint[to] * sharesBalance) / newBalance) +
            ((block.timestamp * newShares) / newBalance);
    }
}
```

### Investment Operations

#### Direct Investment (Same Chain)

```solidity
function investSingleDirectSingleVault(
    address vaultAddress,
    uint256 assets,
    uint256 minSharesOut
)
    public
    onlyRoles(MANAGER_ROLE)
    returns (uint256 shares)
{
    // Ensure the target vault is in the approved list
    if (!isVaultListed(vaultAddress)) revert VaultNotListed();

    // Record the balance before deposit to calculate received shares
    uint256 balanceBefore = vaultAddress.balanceOf(address(this));

    // Deposit assets into the target vault
    ERC4626(vaultAddress).deposit(assets, address(this));

    // Calculate the number of shares received
    shares = vaultAddress.balanceOf(address(this)) - balanceBefore;

    // Ensure the received shares meet the minimum expected assets
    if (shares < minSharesOut) {
        revert InsufficientAssets();
    }

    // Update the vault's internal accounting
    uint128 amountUint128 = assets.toUint128();
    _totalIdle -= amountUint128;
    _totalDebt += amountUint128;
    vaults[_vaultToSuperformId[vaultAddress]].totalDebt += amountUint128;

    emit Invest(assets);
    return shares;
}
```

#### Cross-Chain Investment

```solidity
function investSingleXChainSingleVault(SingleXChainSingleVaultStateReq calldata req)
    external
    payable
    onlyRoles(MANAGER_ROLE)
{
        gateway.investSingleXChainSingleVault{ value: msg.value }(req);

        // Update the vault's internal accounting
        uint256 amount = req.superformData.amount;
        uint128 amountUint128 = amount.toUint128();
        _totalIdle -= amountUint128;

        emit Invest(amount);
}
```

#### Multi-Vault Investment

```solidity
function investSingleDirectMultiVault(
    address[] calldata vaultAddresses,
    uint256[] calldata assets,
    uint256[] calldata minSharesOuts
) external returns (uint256[] memory shares) {
    shares = new uint256[](vaultAddresses.length);
    for (uint256 i = 0; i < vaultAddresses.length; ++i) {
        shares[i] = investSingleDirectSingleVault(
            vaultAddresses[i], 
            assets[i], 
            minSharesOuts[i]
        );
    }
}
```

#### Gas Management

```solidity
modifier refundGas() {
        uint256 balanceBefore;
        assembly {
            balanceBefore := sub(selfbalance(), callvalue())
        }
        _;
        assembly {
            let balanceAfter := selfbalance()
            switch lt(balanceAfter, balanceBefore)
            case true {
                mstore(0x00, 0x1c26714c) // `InsufficientGas()`.
                revert(0x1c, 0x04)
            }
            case false {
                // Transfer all the ETH to sender and check if it succeeded or not.
                if iszero(call(gas(), origin(), balanceAfter, codesize(), 0x00, codesize(), 0x00)) {
                    mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }
```

### Withdrawal Operations

#### Request Phase

```solidity
function requestRedeem(
        uint256 shares,
        address controller,
        address owner
    )
        public
        override
        noEmergencyShutdown
        returns (uint256 requestId)
    {
        // Require deposited shares arent locked
        _checkSharesLocked(controller);
        requestId = super.requestRedeem(shares, controller, owner);
    }
```

#### Processing Phase

```solidity
function processRedeemRequest(ProcessRedeemRequestParams calldata params)
    external
    payable
    onlyRoles(RELAYER_ROLE)
    nonReentrant
{
    // Retrieve the pending redeem request for the specified controller
    // This request may involve cross-chain withdrawals from various ERC4626 vaults

    // Process the redemption request asynchronously
    // Parameters:
    // 1. pendingRedeemRequest(controller): Fetches the pending shares
    // 2. controller: The address initiating the redemption (used as both 'from' and 'to')
    _processRedeemRequest(
        ProcessRedeemRequestConfig(
            params.shares == 0 ? pendingRedeemRequest(params.controller) : params.shares,
            params.controller,
            params.sXsV,
            params.sXmV,
            params.mXsV,
            params.mXmV
        )
    );
    // Note: After processing, the redeemed assets are held by this contract
    // The user can later claim these assets using `redeem` or `withdraw`
}
```

```solidity
// Withdrawal Queue Processing
function _exhaustWithdrawalQueue(
        ProcessRedeemRequestCache memory cache,
        uint256[WITHDRAWAL_QUEUE_SIZE] memory queue,
        bool resetValues
    )
        private
        view
    {
        // Cache how many chains we need and how many vaults in each chain
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
            // If we exhausted the queue stop
            if (queue[i] == 0) {
                if (resetValues) {
                    // reset values
                    cache.amountToWithdraw = cache.assets - cache.totalIdle;
                }
                break;
            }
            if (resetValues) {
                // If its fulfilled stop
                if (cache.amountToWithdraw == 0) {
                    break;
                }
            }
            // Cache next vault from the withdrawal queue
            VaultData memory vault = vaults[queue[i]];
            // Calcualate the maxWithdraw of the vault
            uint256 maxWithdraw = vault.convertToAssets(_sharesBalance(vault), true);

            // Dont withdraw more than max
            uint256 withdrawAssets = Math.min(maxWithdraw, cache.amountToWithdraw);
            if (withdrawAssets == 0) continue;
            // Cache chain index
            uint256 chainIndex = chainIndexes[vault.chainId];
            // Cache chain length
            uint256 len = cache.lens[chainIndex];
            // Push the superformId to the last index of the array
            cache.dstVaults[chainIndex][len] = vault.superformId;

            uint256 shares;
            if (cache.amountToWithdraw >= maxWithdraw) {
                uint256 balance = _sharesBalance(vault);
                shares = balance;
            } else {
                shares = vault.convertToShares(withdrawAssets, true);
            }

            if (shares == 0) continue;
            // Push the shares to redeeem of that vault
            cache.sharesPerVault[chainIndex][len] = shares;
            // Push the assetse to withdraw of that vault
            cache.assetsPerVault[chainIndex][len] = withdrawAssets;
            // Reduce the total debt by no more than the debt of this vault
            uint256 debtReduction = Math.min(vault.totalDebt, withdrawAssets);
            // Reduce totalDebt
            cache.totalDebt -= debtReduction;
            // Reduce needed assets
            cache.amountToWithdraw -= withdrawAssets;

            // Cache wether is single chain or multichain
            if (vault.chainId != THIS_CHAIN_ID) {
                if (!cache.isSingleChain && !cache.isMultiChain) {
                    // First external chain encountered
                    cache.isSingleChain = true;
                } else if (cache.isSingleChain) {
                    // Find the first external chain ID
                    uint256 firstChainId;
                    for (uint256 j = 0; j < N_CHAINS; j++) {
                        if (cache.lens[j] > 0 && j != chainIndexes[THIS_CHAIN_ID]) {
                            firstChainId = j;
                            break;
                        }
                    }
                    // If this vault is from a different chain than the first one, it's multi-chain
                    if (chainIndex != firstChainId) {
                        cache.isSingleChain = false;
                        cache.isMultiChain = true;
                    }
                }
            
                // Check if there are multiple vaults in this chain
                if (cache.lens[chainIndex] >= 1) {
                    cache.isMultiVault = true;
                }
            }

            // Increase index for iteration
            unchecked {
                cache.lens[chainIndex]++;
            }
        }
    }
```

#### Settlement Phase

```solidity
function settleLiquidation(bytes32 key, bool force) external onlyRoles(RELAYER_ROLE) {
    if (!_requestsQueue.contains(key)) revert RequestNotFound();

    RequestData memory data = requests[key];
    if (data.controller == address(0)) revert InvalidController();

    ERC20Receiver receiverContract = ERC20Receiver(getReceiver(key));
    uint256 settledAssets = receiverContract.balance();

    _requestsQueue.remove(key);

    if (!force) {
        if (receiverContract.balance() < receiverContract.minExpectedBalance()) {
            revert MinimumBalanceNotMet();
        }
    }

    receiverContract.pull(settledAssets);
    asset.safeTransfer(address(vault), settledAssets);
    vault.fulfillSettledRequest(data.controller, data.requestedAssets, settledAssets);
    emit RequestSettled(key, data.controller, settledAssets);
}
```

#### Balance Verification

```solidity
function previewWithdrawalRoute(
    address controller,
    uint256 shares,
    bool despiseDust
)
    public
    view
    returns (ProcessRedeemRequestCache memory cachedRoute)
{
    if (shares == 0) {
        shares = pendingRedeemRequest(controller);
    }

    cachedRoute.shares = shares;
    cachedRoute.assets = convertToAssets(shares);
    cachedRoute.totalIdle = _totalIdle;
    cachedRoute.totalDebt = _totalDebt;
    cachedRoute.totalAssets = totalAssets();

    // Cannot process more assets than the available
    if (cachedRoute.assets > totalWithdrawableAssets()) {
        revert InsufficientAvailableAssets();
    }

    // If totalIdle can covers the amount fulfill directly
    if (cachedRoute.totalIdle >= cachedRoute.assets) {
        cachedRoute.sharesFulfilled = shares;
        cachedRoute.totalClaimableWithdraw = cachedRoute.assets;
    }
    // Otherwise perform Superform withdrawals
    else {
        // Cache amount to withdraw before reducing totalIdle
        cachedRoute.amountToWithdraw = cachedRoute.assets - cachedRoute.totalIdle;
        // Use totalIdle to fulfill the request
        if (cachedRoute.totalIdle > 0) {
            cachedRoute.totalClaimableWithdraw = cachedRoute.totalIdle;
            cachedRoute.sharesFulfilled = _convertToShares(cachedRoute.totalIdle, cachedRoute.totalAssets);
        }
        ///////////////////////////////// PREVIOUS CALCULATIONS ////////////////////////////////
        _prepareWithdrawalRoute(cachedRoute, despiseDust);
    }
    return cachedRoute;
}
```

### Failure Mode Analysis

1. **Bridge Failures**
   * Timeout scenarios
   * Asset recovery process
   * State reconciliation
2. **Oracle Failures**
   * Price feed delays
   * Stale price handling
   * Fallback mechanisms
3. **Gas-Related Failures**
   * Cross-chain operation out of gas
   * Batch operation partial success
   * Recovery procedures

### Cross-Chain Settlement

#### Investment Settlement

```solidity
function settleXChainInvest(uint256 superformId, uint256 bridgedAssets) public {
        if (msg.sender != address(gateway)) revert Unauthorized();
        _totalDebt += bridgedAssets.toUint128();
        vaults[superformId].totalDebt += bridgedAssets.toUint128();
        emit SettleXChainInvest(superformId, bridgedAssets);
    }
```

#### Divestment Settlement

```solidity
function settleDivest(bytes32 key, bool force) external onlyRoles(RELAYER_ROLE) {
        if (!_requestsQueue.contains(key)) revert();
        RequestData memory data = requests[key];
        _requestsQueue.remove(key);
        ERC20Receiver receiverContract = ERC20Receiver(getReceiver(key));
        if (data.controller != address(vault)) revert();
        if (!force) {
            if (receiverContract.balance() < receiverContract.minExpectedBalance()) revert();
        }
        uint256 settledAssets = receiverContract.balance();
        uint256 requestedAssets = data.requestedAssets;
        receiverContract.pull(settledAssets);
        totalPendingXChainDivests -= settledAssets;
        asset.safeTransfer(address(vault), settledAssets);
        vault.settleXChainDivest(requestedAssets);
    }
```

#### Refund Handling

```solidity
function notifyRefund(uint256 superformId, uint256 value) external {
        // Prevent bugs from superform
        if(value == 0) return;
        bytes32 key = ERC20Receiver(msg.sender).key();
        if (requests[key].receiverAddress != msg.sender) revert();
        RequestData memory req = requests[key];
        uint256 currentExpectedBalance = ERC20Receiver(msg.sender).minExpectedBalance();

        uint256 vaultIndex;
        for (uint256 i = 0; i < req.superformIds.length; ++i) {
            if (req.superformIds[i] == superformId) {
                vaultIndex = i;
                break;
            }
        }
        uint256 vaultRequestedAssets = req.requestedAssetsPerVault[vaultIndex];

        _handleRefund(key, superformId, value, vaultRequestedAssets);

        _requestsQueue.remove(key); // We can only remove the request if it's a single vault otherwise we need to
            // confirm both succeeded
        ERC20Receiver(msg.sender).setMinExpectedBalance(_sub0(currentExpectedBalance, vaultRequestedAssets));
    }
```

#### NFT Position Safety

```solidity
function onERC1155Received(
        address operator,
        address from,
        uint256 superformId,
        uint256 value,
        bytes memory data
    )
        public
        returns (bytes4)
    {
        // Silence compiler warnings
        operator;
        value;
        data;
        if (msg.sender != address(_superPositions)) revert();
        if (from != address(0)) revert();
        ISuperformGateway(_deployer).notifyRefund(superformId, value);
        return this.onERC1155Received.selector;
    }
    
function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] memory superformIds,
        uint256[] memory values,
        bytes memory data
    )
        public
        returns (bytes4)
    {
        // Silence compiler warnings
        operator;
        from;
        values;
        data;
        if (msg.sender != address(_superPositions)) revert();
        if (from != address(0)) revert();
        ISuperformGateway(_deployer).notifyBatchRefund(superformIds, values);
        return this.onERC1155BatchReceived.selector;
    }
```

### Security Considerations

#### Critical Invariants

1. Total assets = idle assets + allocated assets
2. Pending requests must be processed in order
3. Settlement amounts must meet minimum requirements

#### Fee Management

```solidity
function chargeGlobalFees() external updateGlobalWatermark onlyRoles(MANAGER_ROLE) returns (uint256) {
        uint256 currentSharePrice = sharePrice();
        uint256 lastSharePrice = sharePriceWaterMark;
        uint256 duration = block.timestamp - lastFeesCharged;
        uint256 currentTotalAssets = totalAssets();
        uint256 lastTotalAssets = totalSupply().fullMulDiv(lastSharePrice, 10 ** decimals());

        // Calculate time-based fees (management & oracle)
        // These are charged on total assets, prorated for the time period
        uint256 managementFees = (currentTotalAssets * duration).fullMulDiv(managementFee, SECS_PER_YEAR) / MAX_BPS;
        uint256 oracleFees = (currentTotalAssets * duration).fullMulDiv(oracleFee, SECS_PER_YEAR) / MAX_BPS;
        uint256 totalFees = managementFees + oracleFees;
        uint256 performanceFees;

        currentTotalAssets += managementFees + oracleFees;

        lastFeesCharged = block.timestamp;

        // Calculate the asset's value change since entry
        // This gives us the raw profit/loss in asset terms
        int256 assetsDelta = int256(currentTotalAssets) - int256(lastTotalAssets);

        // Only calculate fees if there's a profit
        if (assetsDelta > 0) {
            uint256 excessReturn;

            // Calculate returns relative to hurdle rate
            uint256 hurdleReturn = (lastTotalAssets * hurdleRate()).fullMulDiv(duration, SECS_PER_YEAR) / MAX_BPS;
            uint256 totalReturn = uint256(assetsDelta);

            // Only charge performance fees if:
            // 1. Current share price is not below
            // 2. Returns exceed hurdle rate
            if (currentSharePrice > sharePriceWaterMark && totalReturn > hurdleReturn) {
                // Only charge performance fees on returns above hurdle rate
                excessReturn = totalReturn - hurdleReturn;

                performanceFees = excessReturn * performanceFee / MAX_BPS;
            }

            // Calculate total fees
            totalFees += performanceFees;
        }
        // Transfer fees to treasury if any were charged
        if (totalFees > 0) {
            _mint(treasury, convertToShares(totalFees));
            _afterDeposit(totalFees, 0);
        }
        assembly {
            let m := shr(96, not(0))

            // Emit the {AssessFees} event
            mstore(0x00, managementFees)
            mstore(0x20, performanceFees)
            mstore(0x40, oracleFees)
            log2(0x00, 0x60, 0xa443e1db11cb46c65620e8e21d4830a6b9b444fa4c350f0dd0024b8a5a6b6ef5, and(m, address()))
        }
        return totalFees;
    }
```

#### Access Control

```solidity
modifier onlyRoles(uint256 role) {
    if (!hasRole(role, msg.sender)) revert Unauthorized();
    _;
}
```

#### State Protection

```solidity
modifier nonReentrant() {
    require(_locked != 2, "ReentrancyGuard: reentrant call");
    _locked = 2;
    _;
    _locked = 1;
}
```

#### Emergency Controls

```solidity
modifier noEmergencyShutdown() {
    if (emergencyShutdown) {
        revert VaultShutdown();
    }
    _;
}
```


# State Management & Operations

## State Management & Operations

### Core State Structures

#### Vault State Structure

```solidity
/// @notice A struct describing the status of an underlying vault
/// @dev Contains data about a vault's chain ID, share price, oracle, and more
struct VaultData {
    /// @dev The ID of the chain where the vault is deployed
    uint64 chainId;
    /// @dev The superform ID of the vault in the Superform protocol
    uint256 superformId;
    /// @dev The oracle that provides the share price for the vault
    ISharePriceOracle oracle;
    /// @dev The number of decimals used in the ERC4626 shares
    uint8 decimals;
    /// @dev The total assets invested in the vault
    uint128 totalDebt;
    /// @dev The address of the vault
    address vaultAddress;
}
```

#### Request States

```solidity
/// @notice Data structure for cross-chain requests
    /// @param controller Address controlling the request
    /// @param superformIds Array of Superform IDs involved in request
    /// @param requestedAssetsPerVault Array of requested assets per vault
    /// @param requestedAssets Total requested assets
    /// @param receiverAddress Address to receive assets
    struct RequestData {
        address controller;
        uint256[] superformIds;
        uint256[] requestedAssetsPerVault;
        uint256 requestedAssets;
        address receiverAddress;
    }

// Request tracking
mapping(address => ERC7540_Request) private _pendingDepositRequest;
mapping(address => ERC7540_FilledRequest) private _claimableDepositRequest;
mapping(address => ERC7540_Request) private _pendingRedeemRequest;
mapping(address => ERC7540_FilledRequest) private _claimableRedeemRequest;

// State tracking
mapping(bytes32 => RequestData) public requests;
mapping(address => uint256) public nonces;
mapping(address => uint256) public lastRedeem;
```

#### Withdrawal Queue State

```solidity
/// @dev Internal cache struct to allocate in memory
struct ProcessRedeemRequestCache {
        // List of vauts to withdraw from on each chain
        uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] dstVaults;
        // List of shares to redeem on each vault in each chain
        uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] sharesPerVault;
        // List of assets to withdraw on each vault in each chain
        uint256[WITHDRAWAL_QUEUE_SIZE][N_CHAINS] assetsPerVault;
        // Cache length of list of each chain
        uint256[N_CHAINS] lens;
        // Assets to divest from other vaults
        uint256 amountToWithdraw;
        // Shares actually used
        uint256 sharesFulfilled;
        // Save assets that were withdrawn instantly
        uint256 totalClaimableWithdraw;
        // Cache totalAssets
        uint256 totalAssets;
        // Cache totalIdle
        uint256 totalIdle;
        // Cache totalDebt
        uint256 totalDebt;
        // Convert shares to assets at current price
        uint256 assets;
        // Wether is a single chain or multichain withdrawal
        bool isSingleChain;
        bool isMultiChain;
        // Wether is a single or multivault withdrawal
        bool isMultiVault;
}
```

### Request State Lifecycle

#### Request Configuration

```solidity
/// @param shares to redeem and burn
/// @param controller controller that created the request
/// @param receiver address of the assets receiver in case its a
struct ProcessRedeemRequestConfig {
        uint256 shares;
        address controller;
        SingleXChainSingleVaultWithdraw sXsV;
        SingleXChainMultiVaultWithdraw sXmV;
        MultiXChainSingleVaultWithdraw mXsV;
        MultiXChainMultiVaultWithdraw mXmV;
}
```

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2Fc84dZrDo9x0DVSCf4ui5%2Fimage.png?alt=media&amp;token=08af267c-0769-4693-a7a0-550898d811ff" alt=""><figcaption></figcaption></figure>

#### Initial State → PendingRequest

```solidity
    /// @notice Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.
    /// @param assets the amount of deposit assets to transfer from owner
    /// @param controller the controller of the request who will be able to operate the request
    /// @param owner the source of the deposit assets
    /// @return requestId
    function requestDeposit(
        uint256 assets,
        address controller,
        address owner
    )
        public
        override
        noEmergencyShutdown
        returns (uint256 requestId)
    {
        requestId = super.requestDeposit(assets, controller, owner);
        // fulfill the request directly
        _fulfillDepositRequest(controller, assets, convertToShares(assets));
    }
```

#### PendingRequest → ClaimableRequest

```solidity
    /// @notice Executes the redeem request for a controller
    function _processRedeemRequest(ProcessRedeemRequestConfig memory config) private {
        // Use struct to avoid stack too deep
        ProcessRedeemRequestCache memory cache;
        cache.totalIdle = _totalIdle;
        cache.totalDebt = _totalDebt;
        cache.assets = convertToAssets(config.shares);
        cache.totalAssets = totalAssets();

        // Cannot process more assets than the
        if (cache.assets > cache.totalAssets - gateway.totalpendingXChainInvests()) {
            revert InsufficientAvailableAssets();
        }

        // If totalIdle can covers the amount fulfill directly
        if (cache.totalIdle >= cache.assets) {
            cache.sharesFulfilled = config.shares;
            cache.totalClaimableWithdraw = cache.assets;
        }
        // Otherwise perform Superform withdrawals
        else {
            // Cache amount to withdraw before reducing totalIdle
            cache.amountToWithdraw = cache.assets - cache.totalIdle;
            // Use totalIdle to fulfill the request
            if (cache.totalIdle > 0) {
                cache.totalClaimableWithdraw = cache.totalIdle;
                cache.sharesFulfilled = _convertToShares(cache.totalIdle, cache.totalAssets);
            }
            ///////////////////////////////// PREVIOUS CALCULATIONS ////////////////////////////////
            _prepareWithdrawalRoute(cache);
            //////////////////////////////// WITHDRAW FROM THIS CHAIN ////////////////////////////////
            // Cache chain index
            uint256 chainIndex = chainIndexes[THIS_CHAIN_ID];
            if (cache.lens[chainIndex] > 0) {
                if (cache.lens[chainIndex] == 1) {
                    // shares to redeem
                    uint256 sharesAmount = cache.sharesPerVault[chainIndex][0];
                    // assets to withdraw
                    uint256 assetsAmount = cache.assetsPerVault[chainIndex][0];
                    // superformId(take first element fo the array)
                    uint256 superformId = cache.dstVaults[chainIndex][0];
                    // get actual withdrawn amount
                    uint256 withdrawn = _liquidateSingleDirectSingleVault(
                        vaults[superformId].vaultAddress, sharesAmount, 0, address(this)
                    );
                    // cache shares to burn
                    cache.sharesFulfilled += _convertToShares(assetsAmount, cache.totalAssets);
                    // reduce vault debt
                    vaults[superformId].totalDebt = _sub0(vaults[superformId].totalDebt, assetsAmount).toUint128();
                    // cache instant total withdraw
                    cache.totalClaimableWithdraw += withdrawn;
                    // Increase idle funds
                    cache.totalIdle += withdrawn;
                } else {
                    uint256 len = cache.lens[chainIndex];
                    // Prepare arguments for request using dynamic arrays
                    address[] memory vaultAddresses = new address[](len);
                    uint256[] memory amounts = new uint256[](len);
                    // Calculate requested amount
                    uint256 requestedAssets;

                    // Cast fixed arrays to dynamic ones
                    for (uint256 i = 0; i != len; i++) {
                        vaultAddresses[i] = vaults[cache.dstVaults[chainIndex][i]].vaultAddress;
                        amounts[i] = cache.sharesPerVault[chainIndex][i];
                        // Reduce vault debt individually
                        uint256 superformId = cache.dstVaults[chainIndex][i];
                        // Increase total assets requested
                        requestedAssets += cache.assetsPerVault[chainIndex][i];
                        // Reduce vault debt
                        vaults[superformId].totalDebt =
                            _sub0(vaults[superformId].totalDebt, cache.assetsPerVault[chainIndex][i]).toUint128();
                    }
                    // Withdraw from the vault synchronously
                    uint256 withdrawn = _liquidateSingleDirectMultiVault(
                        vaultAddresses, amounts, _getEmptyuintArray(amounts.length), address(this)
                    );
                    // Increase claimable assets and fulfilled shares by the amount withdran synchronously
                    cache.totalClaimableWithdraw += withdrawn;
                    cache.sharesFulfilled += _convertToShares(requestedAssets, cache.totalAssets);
                    // Increase total idle
                    cache.totalIdle += withdrawn;
                }
            }

            //////////////////////////////// WITHDRAW FROM EXTERNAL CHAINS ////////////////////////////////
            // If its not multichain
            if (!cache.isMultiChain) {
                // If its multivault
                if (!cache.isMultiVault) {
                    uint256 superformId;
                    uint256 amount;
                    uint64 chainId;
                    uint256 chainIndex;

                    for (uint256 i = 0; i < N_CHAINS; ++i) {
                        if (DST_CHAINS[i] == THIS_CHAIN_ID) continue;
                        // The vaults list length should be 1(single-vault)
                        if (cache.lens[i] > 0) {
                            chainId = DST_CHAINS[i];
                            chainIndex = chainIndexes[chainId];
                            superformId = cache.dstVaults[i][0];
                            amount = cache.sharesPerVault[i][0];

                            // Withdraw from one vault asynchronously(crosschain)
                            _liquidateSingleXChainSingleVault(
                                chainId, superformId, amount, config.controller, config.sXsV, cache.assetsPerVault[i][0]
                            );
                            // reduce vault debt
                            vaults[superformId].totalDebt =
                                _sub0(vaults[superformId].totalDebt, cache.assetsPerVault[chainIndex][0]).toUint128();
                            break;
                        }
                    }
                } else {
                    uint256[] memory superformIds;
                    uint256[] memory amounts;
                    uint64 chainId;
                    for (uint256 i = 0; i < N_CHAINS; ++i) {
                        if (DST_CHAINS[i] == THIS_CHAIN_ID) continue;
                        if (cache.lens[i] > 0) {
                            chainId = DST_CHAINS[i];
                            superformIds = _toDynamicUint256Array(cache.dstVaults[i], cache.lens[i]);
                            amounts = _toDynamicUint256Array(cache.sharesPerVault[i], cache.lens[i]);
                            uint256 totalDebtReduction;
                            // reduce vault debt
                            for (uint256 j = 0; j < superformIds.length;) {
                                vaults[superformIds[j]].totalDebt =
                                    _sub0(vaults[superformIds[j]].totalDebt, cache.assetsPerVault[i][j]).toUint128();
                                totalDebtReduction += cache.assetsPerVault[i][j];
                                unchecked {
                                    ++j;
                                }
                            }
                            // Withdraw from multiple vaults asynchronously(crosschain)
                            _liquidateSingleXChainMultiVault(
                                chainId,
                                superformIds,
                                amounts,
                                config.controller,
                                config.sXmV,
                                totalDebtReduction,
                                _toDynamicUint256Array(cache.assetsPerVault[i], cache.lens[i])
                            );
                            break;
                        }
                    }
                }
            }
            // If its multichain
            else {
                // If its single vault
                if (!cache.isMultiVault) {
                    uint256 chainsLen;
                    for (uint256 i = 0; i < cache.lens.length; i++) {
                        if (cache.lens[i] > 0) chainsLen++;
                    }

                    uint8[][] memory ambIds = new uint8[][](chainsLen);
                    uint64[] memory dstChainIds = new uint64[](chainsLen);
                    SingleVaultSFData[] memory singleVaultDatas = new SingleVaultSFData[](chainsLen);
                    uint256 lastChainsIndex;

                    for (uint256 i = 0; i < N_CHAINS; i++) {
                        if (cache.lens[i] > 0) {
                            dstChainIds[lastChainsIndex] = DST_CHAINS[i];
                            ++lastChainsIndex;
                        }
                    }
                    uint256[] memory totalDebtReductions = new uint256[](chainsLen);
                    for (uint256 i = 0; i < N_CHAINS; i++) {
                        totalDebtReductions[i] = cache.assetsPerVault[i][0];
                        singleVaultDatas[i] = SingleVaultSFData({
                            superformId: cache.dstVaults[i][0],
                            amount: cache.sharesPerVault[i][0],
                            outputAmount: config.mXsV.outputAmounts[i],
                            maxSlippage: config.mXsV.maxSlippages[i],
                            liqRequest: config.mXsV.liqRequests[i],
                            permit2data: "",
                            hasDstSwap: config.mXsV.hasDstSwaps[i],
                            retain4626: false,
                            receiverAddress: config.controller,
                            receiverAddressSP: address(0),
                            extraFormData: ""
                        });
                        ambIds[i] = config.mXsV.ambIds[i];
                        vaults[cache.dstVaults[i][0]].totalDebt =
                            _sub0(vaults[cache.dstVaults[i][0]].totalDebt, cache.assetsPerVault[i][0]).toUint128();
                    }
                    _liquidateMultiDstSingleVault(
                        ambIds, dstChainIds, singleVaultDatas, config.mXsV.value, totalDebtReductions
                    );
                }
                // If its multi-vault
                else {
                    // Cache the number of chains we will withdraw from
                    uint256 chainsLen;
                    for (uint256 i = 0; i < cache.lens.length; i++) {
                        if (cache.lens[i] > 0) chainsLen++;
                    }
                    uint8[][] memory ambIds = new uint8[][](chainsLen);
                    // Cacche destination chains
                    uint64[] memory dstChainIds = new uint64[](chainsLen);
                    // Cache multivault calls for each chain
                    MultiVaultSFData[] memory multiVaultDatas = new MultiVaultSFData[](chainsLen);
                    uint256 lastChainsIndex;

                    for (uint256 i = 0; i < N_CHAINS; i++) {
                        if (cache.lens[i] > 0) {
                            dstChainIds[lastChainsIndex] = DST_CHAINS[i];
                            ++lastChainsIndex;
                        }
                    }
                    uint256[] memory totalDebtReductions = new uint256[](chainsLen);
                    uint256[][] memory debtReductionsPerVault = new uint256[][](chainsLen);
                    for (uint256 i = 0; i < N_CHAINS; i++) {
                        bool[] memory emptyBoolArray = _getEmptyBoolArray(cache.lens[i]);
                        uint256[] memory superformIds = _toDynamicUint256Array(cache.dstVaults[i], cache.lens[i]);
                        multiVaultDatas[i] = MultiVaultSFData({
                            superformIds: superformIds,
                            amounts: _toDynamicUint256Array(cache.sharesPerVault[i], cache.lens[i]),
                            outputAmounts: config.mXmV.outputAmounts[i],
                            maxSlippages: config.mXmV.maxSlippages[i],
                            liqRequests: config.mXmV.liqRequests[i],
                            permit2data: "",
                            hasDstSwaps: config.mXmV.hasDstSwaps[i],
                            retain4626s: emptyBoolArray,
                            receiverAddress: config.controller,
                            receiverAddressSP: address(0),
                            extraFormData: ""
                        });
                        ambIds[i] = config.mXmV.ambIds[i];
                        debtReductionsPerVault[i] = _toDynamicUint256Array(cache.sharesPerVault[i], cache.lens[i]);
                        for (uint256 j = 0; j < superformIds.length;) {
                            vaults[superformIds[j]].totalDebt =
                                _sub0(vaults[superformIds[j]].totalDebt, cache.assetsPerVault[i][j]).toUint128();
                            totalDebtReductions[i] += cache.assetsPerVault[i][j];
                            unchecked {
                                ++j;
                            }
                        }
                    }
                    // Withdraw from multiple vaults and chains asynchronously
                    _liquidateMultiDstMultiVault(
                        ambIds,
                        dstChainIds,
                        multiVaultDatas,
                        config.mXmV.value,
                        totalDebtReductions,
                        debtReductionsPerVault
                    );
                }
            }
        }

        // Optimistically deduct all assets to withdraw from the total
        _totalIdle = cache.totalIdle.toUint128();
        _totalIdle -= cache.totalClaimableWithdraw.toUint128();
        _totalDebt = cache.totalDebt.toUint128();

        emit ProcessRedeemRequest(config.controller, config.shares);
        // Burn all shares from this contract(they already have been transferred)
        _burn(address(this), config.shares);
        // Fulfill request with instant withdrawals only
        _fulfillRedeemRequest(cache.sharesFulfilled, cache.totalClaimableWithdraw, config.controller);
    }
```

#### ClaimableRequest → Completed

```solidity
    /// @dev Hook that is called when processing a redeem request and make it claimable.
    /// @dev It assumes user transferred its shares to the contract when requesting a redeem
    function _fulfillRedeemRequest(
        uint256 sharesFulfilled,
        uint256 assetsWithdrawn,
        address controller
    )
        internal
        virtual
    {
        _pendingRedeemRequest[controller] = _pendingRedeemRequest[controller].sub(sharesFulfilled);
        _claimableRedeemRequest[controller].assets += assetsWithdrawn;
        _claimableRedeemRequest[controller].shares += sharesFulfilled;
    }
```

### Cross-Chain State Management

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2F6dsXKaIhuauwVo97TPme%2Fimage.png?alt=media&amp;token=1bc3e9e4-a960-4219-b373-7197a1b3daa8" alt=""><figcaption></figcaption></figure>

#### Investment State Tracking

```solidity
// Pending investment tracking
mapping(uint256 => uint256) public pendingXChainInvests;
uint256 public totalpendingXChainInvests;

// Receiver contract tracking  
mapping(bytes32 => address) public receivers;
```

#### Withdrawal State Tracking

```solidity
// Queue tracking
EnumerableSetLib.Bytes32Set internal _requestsQueue;
uint256 public totalPendingXChainDivests;

// Lock states
mapping(address => bool) public redeemLocked;
mapping(address => uint256) internal _depositLockCheckPoint;
```

### Direct Investment Flow

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2FRMl3bMcftOzg6qfetDRq%2Fimage.png?alt=media&amp;token=9bead1f9-cac9-428b-ae47-4473b385edd7" alt=""><figcaption></figcaption></figure>

#### State Updates

<pre class="language-solidity"><code class="lang-solidity"><strong>    function investSingleDirectSingleVault(
</strong>        address vaultAddress,
        uint256 assets,
        uint256 minSharesOut
    )
        public
        onlyRoles(MANAGER_ROLE)
        returns (uint256 shares)
    {
        // Ensure the target vault is in the approved list
        if (!isVaultListed(vaultAddress)) revert VaultNotListed();

        // Record the balance before deposit to calculate received shares
        uint256 balanceBefore = vaultAddress.balanceOf(address(this));

        // Deposit assets into the target vault
        ERC4626(vaultAddress).deposit(assets, address(this));

        // Calculate the number of shares received
        shares = vaultAddress.balanceOf(address(this)) - balanceBefore;

        // Ensure the received shares meet the minimum expected assets
        if (shares &#x3C; minSharesOut) {
            revert InsufficientAssets();
        }

        // Update the vault's internal accounting
        uint128 amountUint128 = assets.toUint128();
        _totalIdle -= amountUint128;
        _totalDebt += amountUint128;
        vaults[_vaultToSuperformId[vaultAddress]].totalDebt += amountUint128;

        emit Invest(assets);
        return shares;
    }
</code></pre>

### Security Considerations

#### State Locks

```solidity
    // Reentrancy protection
    modifier nonReentrant() {
        require(_locked != 2, "ReentrancyGuard: reentrant call");
        _locked = 2;
        _;
        _locked = 1;
    }
    
    // Emergency shutdown
    modifier noEmergencyShutdown() {
        if (emergencyShutdown) {
            revert VaultShutdown();
        }
        _;
    }
```

#### State Validations

```solidity
    /// @dev Reverts if deposited shares are locked
    /// @param controller shares controller
    function _checkSharesLocked(address controller) private view {
        if (block.timestamp < _depositLockCheckPoint[controller] + sharesLockTime) revert SharesLocked();
    }
```

#### Critical Invariants

1. Total Assets = Idle + Debt + Pending Investments
2. Share Price Watermark ≤ Current Share Price
3. Request Queue Ordering Must Be Maintained
4. Receiver Contracts Must Be Unique Per Request

#### State Recovery

```solidity
    /// @notice Settles a cross-chain liquidation by processing received assets
    /// @dev Pulls assets from the receiver contract and fulfills the settlement in the vault.
    /// Only callable by addresses with RELAYER_ROLE. The key for lookup is generated based on
    /// whether it's a single vault (superformId) or multiple vaults (array of superformIds).
    /// @param key identifier of the receiver contract
    function settleLiquidation(bytes32 key, bool force) external onlyRoles(RELAYER_ROLE) {
        if (!_requestsQueue.contains(key)) revert RequestNotFound();

        RequestData memory data = requests[key];
        if (data.controller == address(0)) revert InvalidController();

        ERC20Receiver receiverContract = ERC20Receiver(getReceiver(key));
        uint256 settledAssets = receiverContract.balance();

        _requestsQueue.remove(key);

        if (!force) {
            if (receiverContract.balance() < receiverContract.minExpectedBalance()) {
                revert MinimumBalanceNotMet();
            }
        }

        receiverContract.pull(settledAssets);
        asset.safeTransfer(address(vault), settledAssets);
        vault.fulfillSettledRequest(data.controller, data.requestedAssets, settledAssets);
        emit RequestSettled(key, data.controller, settledAssets);
    }

    function notifyRefund(uint256 superformId, uint256 value) external {
        bytes32 key = ERC20Receiver(msg.sender).key();
        if (requests[key].receiverAddress != msg.sender) revert();
        RequestData memory req = requests[key];
        uint256 currentExpectedBalance = ERC20Receiver(msg.sender).minExpectedBalance();
        uint256 vaultIndex;
        for (uint256 i = 0; i < req.superformIds.length; ++i) {
            if (req.superformIds[i] == superformId) {
                vaultIndex = i;
                break;
            }
        }
        uint256 vaultRequestedAssets = req.requestedAssetsPerVault[vaultIndex];
        if (req.controller == address(vault)) {
            totalPendingXChainDivests -= vaultRequestedAssets;
        }
        requests[key].requestedAssets -= vaultRequestedAssets;
        ERC20Receiver(msg.sender).setMinExpectedBalance(_sub0(currentExpectedBalance, vaultRequestedAssets));
        superPositions.safeTransferFrom(msg.sender, address(this), superformId, value, "");
        superPositions.safeTransferFrom(
            address(this), address(vault), superformId, value, abi.encode(vaultRequestedAssets)
        );
    }
```


# Asset Management

### Core Asset States

#### Global Asset Tracking

```solidity
uint128 internal _totalIdle;    // Unallocated assets
uint128 internal _totalDebt;    // Allocated assets
uint256 public sharePriceWaterMark; // High watermark for performance

// Cross-chain tracking
uint256 public totalpendingXChainInvests;
uint256 public totalPendingXChainDivests;
```

#### Per-Vault Asset Tracking

```solidity
/// @notice A struct describing the status of an underlying vault
/// @dev Contains data about a vault's chain ID, share price, oracle, and more
struct VaultData {
    /// @dev The ID of the chain where the vault is deployed
    uint64 chainId;
    /// @dev The last reported share price of the vault
    uint256 superformId;
    /// @dev The oracle that provides the share price for the vault
    ISharePriceOracle oracle;
    /// @dev The number of decimals used in the ERC4626 shares
    uint8 decimals;
    /// @dev The total assets invested in the vault
    uint128 totalDebt;
    /// @dev The address of the vault
    address vaultAddress;
}

mapping(uint256 => VaultData) public vaults;
```

### Asset Operations

#### Direct Asset Management

```solidity
    /// @notice Invests assets from this vault into a single target vault within the same chain
    /// @dev Only callable by addresses with the MANAGER_ROLE
    /// @param vaultAddress The address of the target vault to invest in
    /// @param assets The amount of assets to invest
    /// @param minSharesOut The minimum amount of shares expected to receive from the investment
    /// @return shares The number of shares received from the target vault
    function investSingleDirectSingleVault(
        address vaultAddress,
        uint256 assets,
        uint256 minSharesOut
    )
        public
        onlyRoles(MANAGER_ROLE)
        returns (uint256 shares)
    {
        // Ensure the target vault is in the approved list
        if (!isVaultListed(vaultAddress)) revert VaultNotListed();

        // Record the balance before deposit to calculate received shares
        uint256 balanceBefore = vaultAddress.balanceOf(address(this));

        // Deposit assets into the target vault
        ERC4626(vaultAddress).deposit(assets, address(this));

        // Calculate the number of shares received
        shares = vaultAddress.balanceOf(address(this)) - balanceBefore;

        // Ensure the received shares meet the minimum expected assets
        if (shares < minSharesOut) {
            revert InsufficientAssets();
        }

        // Update the vault's internal accounting
        uint128 amountUint128 = assets.toUint128();
        _totalIdle -= amountUint128;
        _totalDebt += amountUint128;
        vaults[_vaultToSuperformId[vaultAddress]].totalDebt += amountUint128;

        emit Invest(assets);
        return shares;
    }
```

#### Cross-Chain Asset Management

<pre class="language-solidity"><code class="lang-solidity"><strong>    /// @notice Invests assets from this vault into a single target vault on a different chain
</strong>    /// @dev Only callable by addresses with the MANAGER_ROLE
    /// @param req Crosschain deposit request
    function investSingleXChainSingleVault(SingleXChainSingleVaultStateReq calldata req)
        external
        payable
        onlyRoles(MANAGER_ROLE)
    {
        gateway.investSingleXChainSingleVault{ value: msg.value }(req);

        // Update the vault's internal accounting
        uint256 amount = req.superformData.amount;
        uint128 amountUint128 = amount.toUint128();
        _totalIdle -= amountUint128;

        emit Invest(amount);
    }
</code></pre>

#### NFT Position Management

```solidity
    function onERC1155Received(
        address operator,
        address from,
        uint256 superformId,
        uint256 value,
        bytes memory data
    ) public returns (bytes4) {
        // Silence compiler warnings
        operator;
        value;
        if (from != address(gateway)) revert Unauthorized();
        if (data.length > 0) {
            uint256 refundedAssets = abi.decode(data, (uint256));
            if (refundedAssets != 0) {
                _totalDebt += refundedAssets.toUint128();
                vaults[superformId].totalDebt += refundedAssets.toUint128();
            }
        }
        return this.onERC1155Received.selector;
    }
```

<pre class="language-solidity"><code class="lang-solidity"><strong>    function _exhaustWithdrawalQueue(
</strong>        ProcessRedeemRequestCache memory cache,
        uint256[WITHDRAWAL_QUEUE_SIZE] memory queue,
        bool resetValues
    )
        private
        view
    {
        // Cache how many chains we need and how many vaults in each chain
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
            // If we exhausted the queue stop
            if (queue[i] == 0) {
                if (resetValues) {
                    // reset values
                    cache.amountToWithdraw = cache.assets - cache.totalIdle;
                }
                break;
            }
            if (resetValues) {
                // If its fulfilled stop
                if (cache.amountToWithdraw == 0) {
                    break;
                }
            }
            // Cache next vault from the withdrawal queue
            VaultData memory vault = vaults[queue[i]];
            // Calcualate the maxWithdraw of the vault
            uint256 maxWithdraw = vault.convertToAssets(_sharesBalance(vault), true);

            // Dont withdraw more than max
            uint256 withdrawAssets = Math.min(maxWithdraw, cache.amountToWithdraw);
            if (withdrawAssets == 0) continue;
            // Cache chain index
            uint256 chainIndex = chainIndexes[vault.chainId];
            // Cache chain length
            uint256 len = cache.lens[chainIndex];
            // Push the superformId to the last index of the array
            cache.dstVaults[chainIndex][len] = vault.superformId;

            uint256 shares;
            if (cache.amountToWithdraw >= maxWithdraw) {
                uint256 balance = _sharesBalance(vault);
                shares = balance;
            } else {
                shares = vault.convertToShares(withdrawAssets, true);
            }

            if (shares == 0) continue;
            // Push the shares to redeeem of that vault
            cache.sharesPerVault[chainIndex][len] = shares;
            // Push the assetse to withdraw of that vault
            cache.assetsPerVault[chainIndex][len] = withdrawAssets;
            // Reduce the total debt by no more than the debt of this vault
            uint256 debtReduction = Math.min(vault.totalDebt, withdrawAssets);
            // Reduce totalDebt
            cache.totalDebt -= debtReduction;
            // Reduce needed assets
            cache.amountToWithdraw -= withdrawAssets;

            // Cache wether is single chain or multichain
            if (vault.chainId != THIS_CHAIN_ID) {
                if (!cache.isSingleChain &#x26;&#x26; !cache.isMultiChain) {
                    // First external chain encountered
                    cache.isSingleChain = true;
                } else if (cache.isSingleChain) {
                    // Find the first external chain ID
                    uint256 firstChainId;
                    for (uint256 j = 0; j &#x3C; N_CHAINS; j++) {
                        if (cache.lens[j] > 0 &#x26;&#x26; j != chainIndexes[THIS_CHAIN_ID]) {
                            firstChainId = j;
                            break;
                        }
                    }
                    // If this vault is from a different chain than the first one, it's multi-chain
                    if (chainIndex != firstChainId) {
                        cache.isSingleChain = false;
                        cache.isMultiChain = true;
                    }
                }
            
                // Check if there are multiple vaults in this chain
                if (cache.lens[chainIndex] >= 1) {
                    cache.isMultiVault = true;
                }
            }
            
            // Increase index for iteration
            unchecked {
                cache.lens[chainIndex]++;
            }
        }
    }

</code></pre>

### Fee Management

#### Fee Structure

```solidity
uint16 public managementFee;    // Base management fee
uint16 public performanceFee;   // Success-based fee
uint16 public oracleFee;        // Price update incentive

mapping(address => uint256) public managementFeeExempt;
mapping(address => uint256) public performanceFeeExempt;
mapping(address => uint256) public oracleFeeExempt;
```

#### Fee Assessment

```solidity
    /// @notice Charges global management, performance, and oracle fees on the vault's total assets
    /// @dev Fee charging mechanism works as follows:
    /// 1. Time-based fees (management & oracle) are charged on total assets, prorated for the time period
    /// 2. Performance fees are only charged if two conditions are met:
    ///    a) Current share price is above the watermark (high water mark)
    ///    b) Returns exceed the hurdle rate
    /// 3. The hurdle rate is asset-specific:
    ///    - For stablecoins (e.g., USDC): typically tied to T-Bill yields
    ///    - For ETH: typically tied to base staking returns (e.g., Lido APY)
    /// 4. Performance fees are only charged on excess returns above both:
    ///    - The watermark (preventing double-charging on same gains)
    ///    - The hurdle rate (ensuring fees only on excess performance)
    /// Example calculation:
    /// - If initial assets = $1M, current assets = $1.08M
    /// - Duration = 180 days, Management = 2%, Oracle = 0.5%, Performance = 20%
    /// - Hurdle = 5% APY
    /// Then:
    /// 1. Management Fee = $1.08M * 2% * (180/365) = $10,628
    /// 2. Oracle Fee = $1.08M * 0.5% * (180/365) = $2,657
    /// 3. Hurdle Return = $1M * 5% * (180/365) = $24,657
    /// 4. Excess Return = ($80,000 - $13,285 - $24,657) = $42,058
    /// 5. Performance Fee = $42,058 * 20% = $8,412
    /// @return uint256 Total fees charged
    function chargeGlobalFees() external updateGlobalWatermark onlyRoles(MANAGER_ROLE) returns (uint256) {
        uint256 currentSharePrice = sharePrice();
        uint256 lastSharePrice = sharePriceWaterMark;
        uint256 duration = block.timestamp - lastFeesCharged;
        uint256 currentTotalAssets = totalAssets();
        uint256 lastTotalAssets = totalSupply().fullMulDiv(lastSharePrice, 10 ** decimals());

        // Calculate time-based fees (management & oracle)
        // These are charged on total assets, prorated for the time period
        uint256 managementFees = (currentTotalAssets * duration).fullMulDiv(managementFee, SECS_PER_YEAR) / MAX_BPS;
        uint256 oracleFees = (currentTotalAssets * duration).fullMulDiv(oracleFee, SECS_PER_YEAR) / MAX_BPS;
        uint256 totalFees = managementFees + oracleFees;
        uint256 performanceFees;

        currentTotalAssets += managementFees + oracleFees;

        lastFeesCharged = block.timestamp;

        // Calculate the asset's value change since entry
        // This gives us the raw profit/loss in asset terms
        int256 assetsDelta = int256(currentTotalAssets) - int256(lastTotalAssets);

        // Only calculate fees if there's a profit
        if (assetsDelta > 0) {
            uint256 excessReturn;

            // Calculate returns relative to hurdle rate
            uint256 hurdleReturn = (lastTotalAssets * hurdleRate()).fullMulDiv(duration, SECS_PER_YEAR) / MAX_BPS;
            uint256 totalReturn = uint256(assetsDelta);

            // Only charge performance fees if:
            // 1. Current share price is not below
            // 2. Returns exceed hurdle rate
            if (currentSharePrice > sharePriceWaterMark && totalReturn > hurdleReturn) {
                // Only charge performance fees on returns above hurdle rate
                excessReturn = totalReturn - hurdleReturn;

                performanceFees = excessReturn * performanceFee / MAX_BPS;
            }

            // Calculate total fees
            totalFees += performanceFees;
        }
        // Transfer fees to treasury if any were charged
        if (totalFees > 0) {
            _mint(treasury, convertToShares(totalFees));
            _afterDeposit(totalFees, 0);
        }
        assembly {
            let m := shr(96, not(0))

            // Emit the {AssessFees} event
            mstore(0x00, managementFees)
            mstore(0x20, performanceFees)
            mstore(0x40, oracleFees)
            log2(0x00, 0x60, 0xa443e1db11cb46c65620e8e21d4830a6b9b444fa4c350f0dd0024b8a5a6b6ef5, and(m, address()))
        }
        return totalFees;
    }
```

### Asset Accounting

```solidity
    /// @dev The withdraw amount is limited by the claimable redeem requests of the user
    function maxWithdraw(address owner) public view virtual override returns (uint256 assets) {
        return convertToAssets(maxRedeem(owner));
    }

    /// @dev The redeem amount is limited by the claimable redeem requests of the user
    function maxRedeem(address owner) public view virtual override returns (uint256 shares) {
        return _claimableRedeemRequest[owner].shares;
    }
```

#### Total Assets Calculation

<pre class="language-solidity"><code class="lang-solidity"><strong>    /// @notice Returns the total amount of the underlying asset managed by the Vault.
</strong>    function totalAssets() public view override returns (uint256 assets) {
        return gateway.totalpendingXChainInvests() + gateway.totalPendingXChainDivests() + totalWithdrawableAssets();
    }

    /// @notice Returns the total amount of the underlying asset that have been deposited into the vault.
    function totalDeposits() public view returns (uint256 assets) {
        return totalIdle() + totalDebt();
    }

    /// @notice Returns the total amount of the underlying assets that are settled.
    function totalWithdrawableAssets() public view returns (uint256 assets) {
        return totalLocalAssets() + totalXChainAssets();
    }

    /// @notice Returns the total amount of the underlying asset that are located on this
    /// same chain and can be transferred synchronously
    function totalLocalAssets() public view returns (uint256 assets) {
        assets = _totalIdle;
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE;) {
            VaultData memory vault = vaults[localWithdrawalQueue[i]];
            if (vault.vaultAddress == address(0)) break;
            assets += vault.convertToAssets(_sharesBalance(vault), asset(), false);
            ++i;
        }
        return assets;
    }

    /// @notice Returns the total amount of the underlying asset that are located on
    /// other chains and need asynchronous transfers
    function totalXChainAssets() public view returns (uint256 assets) {
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE;) {
            VaultData memory vault = vaults[xChainWithdrawalQueue[i]];
            if (vault.vaultAddress == address(0)) break;
            assets += vault.convertToAssets(_sharesBalance(vault), asset(), false);
            ++i;
        }
        return assets;
    }

    /// @notice returns the assets that are sitting idle in this contract
    /// @return assets amount of idle assets
    function totalIdle() public view returns (uint256 assets) {
        return _totalIdle;
    }

    /// @notice returns the total issued debt of underlying vaulrs
    /// @return assets amount assets that are invested in vaults
    function totalDebt() public view returns (uint256 assets) {
        return _totalDebt;
    }
</code></pre>

#### Share Price Updates

```solidity
modifier updateGlobalWatermark() {
    _;
    uint256 sp = sharePrice();
    assembly {
        let spwm := sload(sharePriceWaterMark.slot)
        if lt(spwm, sp) { sstore(sharePriceWaterMark.slot, sp) }
    }
}

function sharePrice() public view returns (uint256) {
    return convertToAssets(10 ** decimals());
}
```

### Asset Safety

#### Critical Invariants

1. Total Assets = Idle + Debt + Pending Investments
2. Share Price Monotonicity (never decreases under normal operation)
3. Fee Calculations Maintain Precision
4. Asset/Share Ratio Consistency
5. Cross-Chain Position Reconciliation

#### Balance Validation

```solidity
// Available assets check
if (cache.assets > cache.totalAssets - gateway.totalpendingXChainInvests()) {
    revert InsufficientAvailableAssets();
}

// Receiver balance validation
if (!force && receiverContract.balance() < receiverContract.minExpectedBalance()) {
    revert MinimumBalanceNotMet();
}

// Slippage protection
if (shares < minSharesOut) {
    revert InsufficientAssets();
}
```

### Oracle Integration

#### Share Price Oracle

```solidity
interface ISharePriceOracle {
    /// @notice Gets the latest share price of a vault
    /// @dev Returns a VaultReport with share price and timestamp
    /// @param chainId Chain ID of the vault
    /// @param vault Address of the vault
    /// @return VaultReport containing latest price data
    function getLatestSharePrice(
        uint64 chainId,
        address vault
    ) external view returns (VaultReport memory);
}
```

#### Hurdle Rate Oracle

```solidity
interface IHurdleRateOracle {
    /// @notice Returns the base hurdle rate for performance fee calculations
    /// @dev The hurdle rate differs by asset:
    /// - For stablecoins (USDC): Typically set to T-Bills yield
    /// - For ETH: Typically set to base staking return
    /// @param asset The asset to get the rate for
    /// @return uint256 The current base hurdle rate in basis points
    function getRate(address asset) external view returns (uint256);
}
```

```solidity
IHurdleRateOracle public _hurdleRateOracle; // Hurdle rate oracle

function setHurdleRateOracle(IHurdleRateOracle hurdleRateOracle) external onlyRoles(ADMIN_ROLE) {
    _hurdleRateOracle = hurdleRateOracle;
}
```


# Settlement Mechanics

### Cross-Chain Settlement Flow

<figure><img src="https://3265373326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmwfjhYrnElpyTqcwrOa0%2Fuploads%2FFovnXyZ0k2y9o7hu3s5L%2Fimage.png?alt=media&amp;token=4319aca0-00ee-4819-9df6-6ea979256489" alt=""><figcaption></figcaption></figure>

#### Settlement Components

```solidity
/// @notice Core state tracking for settlements
struct RequestData {
    address controller;            // Request controller
    uint256[] superformIds;       // Target vaults
    uint256[] requestedAssetsPerVault; // Assets per vault
    uint256 requestedAssets;      // Total requested
    address receiverAddress;      // Settlement receiver
}

// Settlement state tracking
mapping(bytes32 => RequestData) public requests;
EnumerableSetLib.Bytes32Set internal _requestsQueue;

address public receiverImplementation;

// Settlement events
event ReceiverDeployed(bytes32 indexed key, address indexed receiver);
event RequestSettled(bytes32 indexed key, address indexed controller, uint256 settledAmount);
event LiquidateXChain(address indexed controller, uint256[] indexed superformIds, uint256 indexed requestedAssets, bytes32 key);
```

#### Receiver Interface

```solidity
interface ERC20Receiver {
    function initialize(bytes32 key) external;
    function key() external returns (bytes32);
    function balance() external view returns (uint256);
    function minExpectedBalance() external view returns (uint256);
    function setMinExpectedBalance(uint256 amount) external;
    function pull(uint256 amount) external;
}
```

#### Receiver Contract Deployment

```solidity
function getReceiver(bytes32 key) public returns (address receiverAddress) {
    if (key == bytes32(0)) revert InvalidKey();
    address current = receivers[key];
    if (current != address(0)) {
        return current;
    } else {
        receiverAddress = LibClone.clone(receiverImplementation);
        ERC20Receiver(receiverAddress).initialize(key);
        receivers[key] = receiverAddress;
        emit ReceiverDeployed(key, receiverAddress);
    }
}
```

#### Settlement Process

1. Bridge sends assets to Receiver contract
2. Receiver notifies Gateway of balance
3. Gateway pulls assets from Receiver
4. Gateway settles request with MetaVault
5. MetaVault updates states and completes request

#### Settlement Flow

```solidity
function previewSettlement(bytes32 key) external view returns (
    address controller,
    uint256[] memory superformIds,
    uint256 requestedAssets,
    uint256 settledAssets
) {
    RequestData memory data = requests[key];
    address receiverContract = getReceiver(key);
    return (
        data.controller,
        data.superformIds,
        data.requestedAssets,
        ERC20Receiver(receiverContract).balance()
    );
}
```

1. **Assets Reception**

```solidity
function settleLiquidation(bytes32 key, bool force) external onlyRoles(RELAYER_ROLE) {
    if (!_requestsQueue.contains(key)) revert RequestNotFound();

    RequestData memory data = requests[key];
    if (data.controller == address(0)) revert InvalidController();

    ERC20Receiver receiverContract = ERC20Receiver(getReceiver(key));
    uint256 settledAssets = receiverContract.balance();

    _requestsQueue.remove(key);

    if (!force) {
        if (receiverContract.balance() < receiverContract.minExpectedBalance()) {
            revert MinimumBalanceNotMet();
        }
    }

    receiverContract.pull(settledAssets);
    asset.safeTransfer(address(vault), settledAssets);
    vault.fulfillSettledRequest(data.controller, data.requestedAssets, settledAssets);
    emit RequestSettled(key, data.controller, settledAssets);
}
```

2. **Asset Divestment Settlement**

```solidity
function settleDivest(bytes32 key, bool force) external onlyRoles(RELAYER_ROLE) {
    if (!_requestsQueue.contains(key)) revert RequestNotFound();
    RequestData memory data = requests[key];
    _requestsQueue.remove(key);

    ERC20Receiver receiverContract = ERC20Receiver(getReceiver(key));
    if (data.controller != address(vault)) revert();

    if (!force) {
        if (receiverContract.balance() < receiverContract.minExpectedBalance()) {
            revert MinimumBalanceNotMet();
        }
    }

    uint256 settledAssets = receiverContract.balance();
    uint256 requestedAssets = data.requestedAssets;
    receiverContract.pull(settledAssets);
    totalPendingXChainDivests -= settledAssets;
    
    asset.safeTransfer(address(vault), settledAssets);
    vault.settleXChainDivest(requestedAssets);
}
```

#### Refund Handling

```solidity
function notifyRefund(uint256 superformId, uint256 value) external {
    bytes32 key = ERC20Receiver(msg.sender).key();
    if (requests[key].receiverAddress != msg.sender) revert();

    RequestData memory req = requests[key];
    uint256 currentExpectedBalance = ERC20Receiver(msg.sender).minExpectedBalance();

    uint256 vaultIndex;
    for (uint256 i = 0; i < req.superformIds.length; ++i) {
        if (req.superformIds[i] == superformId) {
            vaultIndex = i;
            break;
        }
    }

    uint256 vaultRequestedAssets = req.requestedAssetsPerVault[vaultIndex];
    if (req.controller == address(vault)) {
        totalPendingXChainDivests -= vaultRequestedAssets;
    }

    requests[key].requestedAssets -= vaultRequestedAssets;
    ERC20Receiver(msg.sender).setMinExpectedBalance(
        _sub0(currentExpectedBalance, vaultRequestedAssets)
    );

    superPositions.safeTransferFrom(msg.sender, address(this), superformId, value, "");
    superPositions.safeTransferFrom(
        address(this), 
        address(vault), 
        superformId, 
        value, 
        abi.encode(vaultRequestedAssets)
    );
}
```

#### NFT Settlement

```solidity
function onERC1155Received(
    address operator,
    address from,
    uint256 superformId,
    uint256 value,
    bytes memory data
) public returns (bytes4) {
    operator;
    value;
    if (from != address(gateway)) revert Unauthorized();
    
    if (data.length > 0) {
        uint256 refundedAssets = abi.decode(data, (uint256));
        if (refundedAssets != 0) {
            _totalDebt += refundedAssets.toUint128();
            vaults[superformId].totalDebt += refundedAssets.toUint128();
        }
    }
    return this.onERC1155Received.selector;
}
```

```solidity
function onERC1155BatchReceived(
    address operator,
    address from,
    uint256[] memory superformIds,
    uint256[] memory values,
    bytes memory data
) public returns (bytes4) {
    // Process each NFT individually
    for (uint256 i = 0; i < superformIds.length; ++i) {
        onERC1155Received(address(0), from, superformIds[i], values[i], "");
    }
    return this.onERC1155BatchReceived.selector;
}
```

### Bridge Failure Handling

1. **Timeout Scenarios**
   * Detection mechanisms
   * Recovery procedures
   * State rollback process
2. **Receiver Contract Security**
   * Access control model
   * Balance validation
   * Minimum balance requirements
3. **Recovery Procedures**
   * Force settlement conditions
   * Asset recovery process
   * State reconciliation steps

### Security Considerations

#### Critical Invariants

1. Settled amounts must match or exceed minimum expected
2. Request queue order must be maintained
3. Assets must be properly accounted for across chains
4. Recovery mechanisms must handle all failure cases

#### State Protection

```solidity
modifier onlyRoles(uint256 role) {
    if (!hasRole(role, msg.sender)) revert Unauthorized();
    _;
}

modifier refundGas() {
    uint256 balanceBefore;
    assembly {
        balanceBefore := sub(selfbalance(), callvalue())
    }
    _;
    assembly {
        let balanceAfter := selfbalance()
        switch lt(balanceAfter, balanceBefore)
        case true {
            mstore(0x00, 0x1c26714c) // `InsufficientGas()`
            revert(0x1c, 0x04)
        }
    }
}
```

#### Error Types

```solidity
error RequestNotFound();
error InvalidController();
error MinimumBalanceNotMet();
error Unauthorized();
error InsufficientGas();
error InvalidKey();
```


# 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

```solidity
    // 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

```solidity
    /// @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

```solidity
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

```solidity
    /// @dev Precomputes the withdrawal route following the order of the withdrawal queue
    /// according to the needed assets
    /// @param cache the memory pointer of the cache
    /// @dev writes the route to the cache struct
    ///
    /// Note: First it will try to fulfill the request with idle assets, after that it will
    /// loop through the withdrawal queue and compute the destination chains and vaults on each
    /// destionation chain, plus the shaes to redeem on each vault
    function _prepareWithdrawalRoute(
        ProcessRedeemRequestCache memory cache,
        bool despiseDust    
    ) private view {
        // Use the local vaults first
        _exhaustWithdrawalQueue(cache, localWithdrawalQueue, false, false);
        // Use the crosschain vaults after
        _exhaustWithdrawalQueue(cache, xChainWithdrawalQueue, true, despiseDust);
    }
```

#### Queue Processing Logic

<pre class="language-solidity"><code class="lang-solidity"><strong>    // Withdrawal Queue Processing
</strong>    function _exhaustWithdrawalQueue(
        ProcessRedeemRequestCache memory cache,
        uint256[WITHDRAWAL_QUEUE_SIZE] memory queue,
        bool resetValues
    )
        private
        view
    {
        // Cache how many chains we need and how many vaults in each chain
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE; i++) {
            // If we exhausted the queue stop
            if (queue[i] == 0) {
                if (resetValues) {
                    // reset values
                    cache.amountToWithdraw = cache.assets - cache.totalIdle;
                }
                break;
            }
            if (resetValues) {
                // If its fulfilled stop
                if (cache.amountToWithdraw == 0) {
                    break;
                }
            }
            // Cache next vault from the withdrawal queue
            VaultData memory vault = vaults[queue[i]];
            // Calcualate the maxWithdraw of the vault
            uint256 maxWithdraw = vault.convertToAssets(_sharesBalance(vault), true);

            // Dont withdraw more than max
            uint256 withdrawAssets = Math.min(maxWithdraw, cache.amountToWithdraw);
            if (withdrawAssets == 0) continue;
            // Cache chain index
            uint256 chainIndex = chainIndexes[vault.chainId];
            // Cache chain length
            uint256 len = cache.lens[chainIndex];
            // Push the superformId to the last index of the array
            cache.dstVaults[chainIndex][len] = vault.superformId;

            uint256 shares;
            if (cache.amountToWithdraw >= maxWithdraw) {
                uint256 balance = _sharesBalance(vault);
                shares = balance;
            } else {
                shares = vault.convertToShares(withdrawAssets, true);
            }

            if (shares == 0) continue;
            // Push the shares to redeeem of that vault
            cache.sharesPerVault[chainIndex][len] = shares;
            // Push the assetse to withdraw of that vault
            cache.assetsPerVault[chainIndex][len] = withdrawAssets;
            // Reduce the total debt by no more than the debt of this vault
            uint256 debtReduction = Math.min(vault.totalDebt, withdrawAssets);
            // Reduce totalDebt
            cache.totalDebt -= debtReduction;
            // Reduce needed assets
            cache.amountToWithdraw -= withdrawAssets;

            // Cache wether is single chain or multichain
            if (vault.chainId != THIS_CHAIN_ID) {
                if (!cache.isSingleChain &#x26;&#x26; !cache.isMultiChain) {
                    // First external chain encountered
                    cache.isSingleChain = true;
                } else if (cache.isSingleChain) {
                    // Find the first external chain ID
                    uint256 firstChainId;
                    for (uint256 j = 0; j &#x3C; N_CHAINS; j++) {
                        if (cache.lens[j] > 0 &#x26;&#x26; j != chainIndexes[THIS_CHAIN_ID]) {
                            firstChainId = j;
                            break;
                        }
                    }
                    // If this vault is from a different chain than the first one, it's multi-chain
                    if (chainIndex != firstChainId) {
                        cache.isSingleChain = false;
                        cache.isMultiChain = true;
                    }
                }
            
                // Check if there are multiple vaults in this chain
                if (cache.lens[chainIndex] >= 1) {
                    cache.isMultiVault = true;
                }
            }

            // Increase index for iteration
            unchecked {
                cache.lens[chainIndex]++;
            }
        }
    }
</code></pre>

### Asset Tracking

```solidity
    /// @notice Returns the total amount of the underlying assets that are settled.
    function totalWithdrawableAssets() public view returns (uint256 assets) {
        return totalLocalAssets() + totalXChainAssets();
    }

    /// @notice Returns the total amount of the underlying asset that are located on this
    /// same chain and can be transferred synchronously
    function totalLocalAssets() public view returns (uint256 assets) {
        assets = _totalIdle;
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE;) {
            VaultData memory vault = vaults[localWithdrawalQueue[i]];
            if (vault.vaultAddress == address(0)) break;
            assets += vault.convertToAssets(_sharesBalance(vault), asset(), false);
            ++i;
        }
        return assets;
    }

    /// @notice Returns the total amount of the underlying asset that are located on
    /// other chains and need asynchronous transfers
    function totalXChainAssets() public view returns (uint256 assets) {
        for (uint256 i = 0; i != WITHDRAWAL_QUEUE_SIZE;) {
            VaultData memory vault = vaults[xChainWithdrawalQueue[i]];
            if (vault.vaultAddress == address(0)) break;
            assets += vault.convertToAssets(_sharesBalance(vault), asset(), false);
            ++i;
        }
        return assets;
    }
```

### 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

```solidity
    // In investment/divestment operations
    if (shares < minSharesOut) {
        revert InsufficientAssets();
    }
```

#### Asset Validation

```solidity
    // Available assets check
    if (cache.assets > cache.totalAssets - gateway.totalpendingXChainInvests()) {
        revert InsufficientAvailableAssets();
    }
```

### 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

```solidity
    error VaultAlreadyListed();
    error InvalidSuperformId();
```


# Deployed Addresses

## MetaVault USD

<table><thead><tr><th width="297">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>Metavault</td><td>0x7a63e8FC1d0A5E9BE52f05817E8C49D9e2d6efAe</td></tr><tr><td>Gateway</td><td>0x1c117e6cC629C414377Fdbb427db329fD0821F9a</td></tr><tr><td>Engine</td><td>0x9FDfd9c1e23D687F7a154610816de6E47Fb4FC64</td></tr><tr><td>EngineReader</td><td>0x980699833e4bF90e5C6db7115d614Cef49Fb387E</td></tr><tr><td>EngineSignatures</td><td>0xB19A4abE409F0Cb86E82cBf4E6022d70E42c880A</td></tr><tr><td>AssetManager</td><td>0x9B12700FFd44088930c9409522A77e0D81Ce81fC</td></tr><tr><td>EmergencyAssetsManager</td><td>0x8F93cff9EDF95087447D7BCD8ea1499cE7846d7B</td></tr><tr><td>MetaVaultReader</td><td>0x4D036599A7e99af6d69A3418B42B0A744e7A6FaB</td></tr><tr><td>MetaVaultAdmin</td><td>0x8c8933eF161B9C56955942FF029e31B3C6df51cd</td></tr><tr><td>InvestSuperform</td><td>0xFc1b3050FB8A13e529367f7d812030E9657CC0A4</td></tr><tr><td>DivestSuperform</td><td>0xdE20b21499c637B6eAd44f9480b6B1a9e4f02F3B</td></tr><tr><td>LiquidateSuperform</td><td>0x7f6E472DFa67d78830718E8DFe8EB9358dcb369C</td></tr><tr><td>SuperPositionsReceiver</td><td>0x71b296da7178c4d03246340d66699e208fFf4779</td></tr></tbody></table>

## MetaVault ETH&#x20;

<table><thead><tr><th width="297">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>Metavault</td><td>0xb272e80042634Bca5d3466446b0C48Ba278A8Ae5</td></tr><tr><td>Gateway</td><td>0x4D4B3699DACf5D231bdA915b11097c9D2e8a7FcD</td></tr><tr><td>Engine</td><td>0xDE0D8aB8D020278268dc142E29406B488AFA67fE</td></tr><tr><td>EngineReader</td><td>0x882B26542F2F03209EC4139af36595BE22eD66b5</td></tr><tr><td>EngineSignatures</td><td>0xF73c1829E8Fdb09584Bb879167e21e429C2f7548</td></tr><tr><td>AssetManager</td><td>0x89B747207c54958FD138eB9C34FaA2386aC6ECA5</td></tr><tr><td>EmergencyAssetsManager</td><td>0x7cf4305EAE39Bc11a0386608B4ade2bf4d53f5FE</td></tr><tr><td>MetaVaultReader</td><td>0x1D2e925a7cc0a9615390EA58c9857B2D0D807135</td></tr><tr><td>MetaVaultAdmin</td><td>0x4dB1a41B339C4dC1dff7A446A898b21aD8dB9b0B</td></tr><tr><td>InvestSuperform</td><td>0xe9Ce3D04eD143F6B835D568eD44d930292BBDb49</td></tr><tr><td>DivestSuperform</td><td>0x548915dA8a819D01b8B7667e09284730FA7F044B</td></tr><tr><td>LiquidateSuperform</td><td>0x3bAD3CAb5A015E0cA94C5EFa8EF9fCD99b881219</td></tr><tr><td>SuperPositionsReceiver</td><td>0x55835c3d70F59d51E712ad6d2C976c7DB2Bf0118</td></tr></tbody></table>


# Periphery


# Hurdle Rate Oracle

### Overview

The Hurdle Rate Oracle is a Solidity smart contract designed to fetch and store interest rates for multiple tokens in a gas-efficient manner. It leverages Chainlink Functions to retrieve external data and implements a bitmap-based storage mechanism that allows scaling up to 16 different token rates without increasing operational costs.

The primary focus of this contract is to track rates for liquid staking tokens like Lido and USDY, though it can be extended to support other tokens as well.

Github: <https://github.com/VerisLabs/hurdleRateOracle>

### Key Features

* Fetches and stores rates for multiple tokens using Chainlink Functions
* Uses a bitmap-based storage system for efficient data packing
* Supports up to 16 different token rates in a single storage slot
* Implements security features including reentrancy protection and rate update throttling
* Includes admin controls for managing tokens and configuration

### Architecture

The contract is built on several core components:

1. **Chainlink Functions Integration**: Fetches external data through decentralized oracle networks
2. **Bitmap Storage**: Packs up to 16 different token rates into a single storage slot
3. **Access Control**: Implements ownership controls for administrative functions
4. **Security Measures**: Includes reentrancy protection and rate manipulation prevention

### Contract Inheritance

```
HurdleRateOracle
├── FunctionsClient (Chainlink)
├── ConfirmedOwner (Chainlink)
└── ReentrancyGuard (Solady)
```

### Core Concepts

#### Rate Storage Mechanism

The contract uses an efficient bitmap-based storage system:

* Each token rate occupies 16 bits (2 bytes) in the `currentRates` storage slot
* Rates are stored in basis points (10000 bps = 100%)
* Up to 16 different token rates can be stored in a single storage slot
* Each token is assigned a specific position (0-15) in the bitmap

#### Rate Update Process

1. An external caller triggers the `updateRates()` function
2. The contract makes a Chainlink Functions request using the configured JavaScript source
3. The Chainlink DON (Decentralized Oracle Network) executes the JavaScript code
4. The callback function receives and stores the new rates

#### Rate Retrieval

Rates can be accessed in several ways:

* `getRate(address token)`: Returns the rate for a specific token
* `getAllRates()`: Returns all rates as a packed bitmap
* `getRateByPosition(uint8 position)`: Returns the rate at a specific position

### Setup and Configuration

#### Prerequisites

* Chainlink Functions subscription
* LINK tokens to fund the subscription
* JavaScript source code for rate fetching

#### Initialization

The contract is initialized with:

* Chainlink Functions router address (Base Mainnet: `0xf9B8fc078197181C841c296C876945aaa425B278`)
* Subscription ID (default: `36`)
* JavaScript source code for rate fetching

By default, the contract registers:

* WETH (Base) at position 0 - This will be used for Lido
* USDCe (Base) at position 1 - This will be used for USDY

#### Deployment Script

The contract can be deployed using the provided Foundry script:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Script} from "forge-std/Script.sol";
import {HurdleRateOracle} from "../src/HurdleRateOracle.sol";

contract DeployHurdleRateOracle is Script {
   // Chainlink Functions Router address for Base Mainnet
   address constant ROUTER = 0xf9B8fc078197181C841c296C876945aaa425B278;
   
   string constant DEFAULT_SOURCE = 
       "const apiResponse = await Functions.makeHttpRequest({"
       "url: `https://api.maxapy.io/hurdle-rate`,"
       "headers: {'Content-Type': 'application/json'}"
       "});"
       "if (apiResponse.error) throw Error('API Request Error');"
       "const { data } = apiResponse;"
       "return Functions.encodeUint256(data.bitmap);";

   function run() external returns (HurdleRateOracle) {
       uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
       uint64 subscriptionId = 36;

       vm.startBroadcast(deployerPrivateKey);
       
       HurdleRateOracle oracle = new HurdleRateOracle(
           ROUTER,
           subscriptionId,
           DEFAULT_SOURCE
       );

       vm.stopBroadcast();
       
       return oracle;
   }
}
```

#### Default API Integration

By default, the contract is configured to fetch rates from the Maxapy API endpoint (`https://api.maxapy.io/hurdle-rate`), which returns a pre-formatted bitmap of rates for the registered tokens.

### Administrative Functions

#### Token Management

```solidity
function registerToken(address token, uint8 position) external onlyOwner
```

Registers a new token at a specific position in the bitmap.

#### Configuration

```solidity
function setSource(string memory _source) external onlyOwner
```

Updates the JavaScript source code for Chainlink Functions requests.

```solidity
function setSubscriptionId(uint64 newSubscriptionId) external onlyOwner
```

Updates the Chainlink Functions subscription ID.

```solidity
function setPause(bool _paused) external onlyOwner
```

Pauses or unpauses the contract.

### User Functions

#### Updating Rates

```solidity
function updateRates() external nonReentrant isNotPaused
```

Triggers a rate update via Chainlink Functions. This function can be called by anyone, but is protected by a minimum time interval between updates.

#### Reading Rates

```solidity
function getRate(address token) external view returns (uint16 rate, uint256 timestamp)
```

Returns the current rate for a specific token and the timestamp of the last update.

```solidity
function getAllRates() external view returns (uint256)
```

Returns all current rates as a packed bitmap.

```solidity
function getRateByPosition(uint8 position) external view returns (uint16)
```

Returns the rate at a specific position in the bitmap.

### Security Considerations

The contract implements several security features:

1. **Reentrancy Protection**: Uses the ReentrancyGuard to prevent reentrancy attacks
2. **Rate Update Throttling**: Enforces a minimum time interval between updates to prevent manipulation
3. **Owner Controls**: Administrative functions are restricted to the contract owner
4. **Circuit Breaker**: Includes a pause mechanism to stop operations in emergency situations

### JavaScript Source Requirements

The JavaScript source code for Chainlink Functions must:

1. Return a packed bitmap of rates
2. Format each rate as a uint16 in basis points (0-10000)
3. Position each rate correctly in the bitmap
4. Handle errors gracefully

#### Default Source Code

The contract comes with a default source code that fetches rates from the Maxapy API:

```javascript
const apiResponse = await Functions.makeHttpRequest({
  url: `https://api.maxapy.io/hurdle-rate`,
  headers: {'Content-Type': 'application/json'}
});
if (apiResponse.error) throw Error('API Request Error');
const { data } = apiResponse;
return Functions.encodeUint256(data.bitmap);
```

This source code:

1. Makes an HTTP request to the Maxapy API
2. Checks for errors in the response
3. Extracts the pre-formatted bitmap
4. Encodes it as a uint256 for the contract

#### Custom API Integration

To create a custom API integration, you'll need to ensure your API returns data in a format that can be converted to a bitmap. The expected format is:

```json
{
  "bitmap": "0x0000000000000000000000000000000000000000000000000000000001F401F4"
}
```

Where `bitmap` is a hexadecimal representation of a uint256 with packed rates. For example, the above bitmap represents:

* Position 0: 500 bps (0x01F4)
* Position 1: 500 bps (0x01F4)
* All other positions: 0 bps

### Events

The contract emits the following events:

* `RateUpdateRequested(bytes32 indexed requestId)`: Emitted when a rate update is requested
* `RateUpdateFulfilled(bytes32 indexed requestId, uint256 newRates, uint256 timestamp)`: Emitted when rates are updated
* `TokenRegistered(address indexed token, uint8 position)`: Emitted when a new token is registered
* `RequestFailed(bytes32 indexed requestId, bytes error)`: Emitted when a Chainlink Functions request fails
* `SubscriptionIdUpdated(uint64 oldSubId, uint64 newSubId)`: Emitted when the subscription ID is updated
* `SourceUpdated(string newSource)`: Emitted when the source code is updated
* `PauseStateChanged(bool paused)`: Emitted when the pause state is changed

### Error Handling

The contract uses custom errors to provide clear failure messages:

* `InvalidPosition`: Position is out of range (must be 0-15)
* `RequestNotFound`: Request ID doesn't match any pending request
* `TokenNotRegistered`: Attempted to get rate for unregistered token
* `TokenAlreadyRegistered`: Attempted to register token at occupied position
* `UpdateTooFrequent`: Rate update requested too soon after previous update
* `InvalidRates`: Returned rates are invalid
* `InvalidSubscription`: Subscription ID is invalid
* `RateLimit`: Too many rates provided
* `InvalidSubscriptionId`: Invalid subscription ID provided
* `Paused`: Contract is paused
* `AddressZero`: Zero address provided
* `InvalidSource`: Empty source code provided

### Integration Examples

#### Reading a Token's Rate

```solidity
// Get the current rate for WETH (Lido)
(uint16 rate, uint256 timestamp) = hurdleRateOracle.getRate(0x4200000000000000000000000000000000000006);

// Convert basis points to percentage
uint256 ratePercentage = rate / 100; // e.g. 500 bps = 5.00%
```

#### Checking Multiple Rates

```solidity
// Get all rates at once
uint256 allRates = hurdleRateOracle.getAllRates();

// Extract individual rates
uint16 lidoRate = uint16(allRates & 0xFFFF);
uint16 usdyRate = uint16((allRates >> 16) & 0xFFFF);
```

#### Updating Rates from a Smart Contract

```solidity
// Trigger a rate update
try hurdleRateOracle.updateRates() {
    // Update requested successfully
} catch Error(string memory reason) {
    // Handle error
}
```

#### Updating Rates via JavaScript

You can trigger rate updates using a simple Node.js script:

```javascript
import { ethers } from "ethers";
import dotenv from 'dotenv';
dotenv.config();

async function requestUpdate() { 
  const oracleAddress = "0x5EDd8bD98d96404a2387C2fD37b48d363DF67803";
  
  const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

  const oracleAbi = [
    "function updateRates() external"
  ];

  const oracle = new ethers.Contract(oracleAddress, oracleAbi, wallet);

  try {
    console.log("\nRequesting rate update...");
    const tx = await oracle.updateRates({
      gasLimit: 500000
    });
    
    console.log("Transaction sent! Hash:", tx.hash);
    console.log("\nWaiting for confirmation...");
    
    const receipt = await tx.wait();
    console.log("Transaction confirmed!");
    console.log("Gas used:", receipt.gasUsed.toString());
    
  } catch (error) {
    console.error("Error:", error);
  }
}

requestUpdate().catch(console.error);
```

This script requires an `.env` file with:

* `RPC_URL`: Base network RPC URL
* `PRIVATE_KEY`: Private key of the wallet that will pay for the transaction

### Gas Efficiency

The use of bitmap storage provides significant gas savings:

* Reading rates costs minimal gas due to efficient packing
* Updating all rates costs the same as updating a single rate
* No iteration required to access specific rates

### Limitations

1. Maximum of 16 token rates per contract instance
2. Rate precision limited to basis points (0.01%)
3. Rate updates are limited by the MIN\_UPDATE\_INTERVAL (1 hour)
4. Dependent on Chainlink Functions subscription being funded with LINK

### Appendix

#### Constants

* `MAX_RATE_BPS`: Maximum allowed rate in basis points (10000 = 100%)
* `CALLBACK_GAS_LIMIT`: Gas limit for Chainlink Functions callback (300,000)
* `MIN_UPDATE_INTERVAL`: Minimum time between rate updates (1 hour)

#### Understanding Basis Points

* 1 basis point = 0.01%
* 100 basis points = 1%
* 10000 basis points = 100%


# SharePriceOracle

## Cross-Chain ERC4626 Vault Share Price Oracle

### Overview

SharePriceOracle is a multi-adapter oracle system designed for cross-chain ERC4626 vault share price propagation. The system enables protocols to access and share vault share prices across different blockchains using LayerZero as a messaging layer. It provides a unified interface for fetching accurate price data from various sources and serves as a critical infrastructure for cross-chain vault strategies, yield aggregators, and DeFi protocols.

### Key Features

* **Multi-adapter architecture**: Supports multiple price feed providers (Chainlink, Pyth, API3, Redstone, AMMs)
* **Cross-chain compatibility**: Propagates vault share prices across different blockchains via LayerZero
* **Price normalization**: Converts prices to standardized 18-decimal precision (WAD)
* **Fallback mechanisms**: Implements priority-based fallback for price sources
* **Price validation**: Enforces bounds checking and staleness prevention
* **L2 sequencer awareness**: Handles L2 sequencer downtime gracefully

### System Architecture

The SharePriceOracle system consists of three main components:

1. **SharePriceOracle**: The core contract that serves as the router and price aggregator
2. **Oracle Adapters**: Specialized contracts for interfacing with different price feed providers
3. **MaxLzEndpoint**: LayerZero endpoint for cross-chain communication

#### Data Flow

```
┌───────────────────┐          ┌───────────────────┐
│  SharePriceOracle │          │  SharePriceOracle │
│    (Chain A)      │◄─────────┤    (Chain B)      │
└─────────┬─────────┘          └─────────┬─────────┘
          │                              │
          ▼                              ▼
┌─────────────────────┐      ┌─────────────────────┐
│ Oracle Adapters     │      │ Oracle Adapters     │
│ (Chainlink, Pyth,   │      │ (Chainlink, Pyth,   │
│  UniswapV3, etc.)   │      │  UniswapV3, etc.)   │
└─────────────────────┘      └─────────────────────┘
```

### Core Contracts

#### SharePriceOracle

The SharePriceOracle is the central contract that:

1. Manages a registry of price adapters
2. Handles cross-chain asset mappings
3. Stores and updates share prices
4. Provides normalized price conversion
5. Enforces access control for different operations

```solidity
contract SharePriceOracle is ISharePriceOracle, OwnableRoles {
    // Roles
    uint256 public constant ADMIN_ROLE = _ROLE_0;
    uint256 public constant ENDPOINT_ROLE = _ROLE_1;
    uint256 public constant ADAPTER_ROLE = _ROLE_2;
    
    // Mappings
    mapping(address => mapping(uint8 => LocalAssetConfig)) public localAssetConfigs;
    mapping(address => StoredSharePrice) public storedSharePrices;
    mapping(bytes32 => address) public crossChainAssetMap;
    mapping(bytes32 => VaultReport) public sharePrices;
}
```

Key functions:

* `getSharePrices`: Fetches current share prices for multiple vaults
* `updateSharePrices`: Updates share prices received from other chains
* `getLatestSharePrice`: Gets the latest share price for a specific vault
* `getPrice`: Gets the price of an asset from available adapters
* `setLocalAssetConfig`: Configures a price feed for a local asset
* `setCrossChainAssetMapping`: Maps cross-chain assets to local equivalents

#### MaxLzEndpoint

The MaxLzEndpoint contract handles cross-chain messaging via LayerZero:

1. Sends vault share prices to other chains
2. Receives and processes share price updates
3. Manages messaging options and peers
4. Implements request-response patterns for price updates

```solidity
contract MaxLzEndpoint is ILayerZeroReceiver, Ownable {
    // Message pattern identifiers
    uint8 private constant AB_TYPE = 1;  // Simple send-receive
    uint8 private constant ABA_TYPE = 2; // Request-response pattern
    
    // Mappings
    mapping(uint32 eid => bytes32 peer) public peers;
}
```

Key functions:

* `sendSharePrices`: Sends share prices to a destination chain
* `requestSharePrices`: Requests share prices from a destination chain
* `lzReceive`: Processes incoming messages from LayerZero

### Oracle Adapters

The system supports multiple oracle adapters, each specialized for a different price feed provider:

#### 1. Chainlink Adapter

Fetches price data from Chainlink price feeds with heartbeat validation and price bounds checking.

```solidity
contract ChainlinkAdapter is BaseOracleAdapter {
    function getPrice(address asset, bool inUSD) 
        external view override returns (ISharePriceOracle.PriceReturnData memory);
}
```

#### 2. Pyth Adapter

Integrates with Pyth Network for high-frequency, decentralized price updates.

```solidity
contract PythAdapter is BaseOracleAdapter {
    function getPrice(address asset, bool inUSD) 
        external view override returns (ISharePriceOracle.PriceReturnData memory);
    
    function updateAndGetPrice(address asset, bool inUSD, bytes[] calldata updateData) 
        external payable returns (ISharePriceOracle.PriceReturnData memory);
}
```

#### 3. API3 Adapter

Uses API3's dAPI (data feed) system for price data.

```solidity
contract Api3Adapter is BaseOracleAdapter {
    function getPrice(address asset, bool inUSD) 
        external view override returns (ISharePriceOracle.PriceReturnData memory);
}
```

#### 4. Redstone Adapter

Integrates with Redstone's oracle network for price data.

```solidity
contract RedStoneAdapter is BaseOracleAdapter {
    function getPrice(address asset, bool inUSD) 
        external view override returns (ISharePriceOracle.PriceReturnData memory);
}
```

#### 5. AMM-based Adapters

Several adapters for extracting prices from AMM pools:

* **UniswapV3Adapter**: Uses TWAP (Time-Weighted Average Price) from Uniswap V3 pools
* **BalancerAdapter**: Extracts prices from Balancer weighted pools
* **AerodromeV1Adapter/AerodromeV2Adapter**: Works with Aerodrome pools (Base-specific)
* **Curve2PoolAssetAdapter**: Extracts prices from Curve pools with reentrancy protection

### Key Data Structures

#### VaultReport

Contains vault share price information and metadata for cross-chain communication:

```solidity
struct VaultReport {
    uint256 sharePrice;
    uint64 lastUpdate;
    uint32 chainId;
    address rewardsDelegate;
    address vaultAddress;
    address asset;
    uint256 assetDecimals;
}
```

#### PriceReturnData

Standardized structure for price data returned by adapters:

```solidity
struct PriceReturnData {
    uint240 price;     // Price normalized to WAD (1e18)
    bool hadError;     // Error flag
    bool inUSD;        // Price denomination
}
```

#### LocalAssetConfig

Configuration for local assets (e.g., USDC, WETH):

```solidity
struct LocalAssetConfig {
    address priceFeed; // Priority-ordered price feeds
    bool inUSD;        // Whether price should be in USD
    address adaptor;   // Adapter address
}
```

### Security Considerations

The SharePriceOracle implements several security mechanisms:

1. **Access control**: Role-based permissions for administrative and update operations
2. **Price validation**: Minimum and maximum bounds for prices to prevent manipulation
3. **Staleness prevention**: Timestamp-based checks to ensure price freshness
4. **Sequencer awareness**: Checks for L2 sequencer status before using prices
5. **Multiple price sources**: Fallback mechanism to increase resilience

### Common Workflows

#### Adding a New Vault to Monitor

To start monitoring a new vault's share price:

1. Ensure the vault's underlying asset has a price feed configured
2. Call `getSharePrices()` with the vault address to get its current share price
3. Use `sendSharePrices()` on the MaxLzEndpoint to propagate the price to other chains

#### Configuring a New Price Feed

To add a new price feed for an asset:

1. Deploy and configure the appropriate adapter contract
2. Grant the adapter the ADAPTER\_ROLE
3. Call `setLocalAssetConfig()` to register the asset with the adapter

#### Cross-Chain Asset Mapping

To enable price conversion for cross-chain assets:

1. Identify the local equivalent of the cross-chain asset
2. Call `setCrossChainAssetMapping()` with the source chain ID, source asset, and local asset

### Error Handling

The system uses custom errors to provide clear failure reasons:

* `InvalidAsset`: Asset not supported or not properly configured
* `NoValidPrice`: Unable to get a valid price
* `StalePrice`: Price is too old to be considered valid
* `SequencerUnavailable`: L2 sequencer is down or in grace period
* `MessageAlreadyProcessed`: Prevents duplicate processing of cross-chain messages

### Glossary

* **WAD**: Standard unit representing 1 with 18 decimal places (10^18)
* **EID**: Endpoint ID in LayerZero, representing a specific blockchain
* **TWAP**: Time-Weighted Average Price, used by DEX-based oracles
* **ERC4626**: Token standard for tokenized vaults
* **Share Price**: The price of one vault share expressed in terms of the underlying asset


# Deployed Addresses

## Deployed Addresses

### Base Network

<table><thead><tr><th width="297">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>HurdleRateOracle</td><td>0x5EDd8bD98d96404a2387C2fD37b48d363DF67803</td></tr><tr><td>SharePriceOracle</td><td>0xca3703ccf43c7242055b27ccb6c0751921136e7d</td></tr><tr><td>MaxLzEndpoint</td><td>0xb70bad0da34edba281f6e33e825439a304d4b83b</td></tr><tr><td>Chainlink Adapter</td><td>0xf8bdf75a4008319481e8a3526d0ea9b5a48a03c5</td></tr><tr><td>Api3 Adapter</td><td>0x71f0cd87dfe7236dc8bb80ed8e5e40643c0f1a85</td></tr></tbody></table>

### Optimism Network

<table><thead><tr><th width="297">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>SharePriceOracle</td><td>0x6dca28080cff24390715e8cd691d2565cb1dfd5d</td></tr><tr><td>MaxLzEndpoint</td><td>0x284eA53a1fDd3082F995A59ecf4dDDCe6A4da25D</td></tr></tbody></table>

### Arbitrum Network

<table><thead><tr><th width="296">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>SharePriceOracle</td><td>0x6dca28080cff24390715e8cd691d2565cb1dfd5d</td></tr><tr><td>MaxLzEndpoint</td><td>0x284eA53a1fDd3082F995A59ecf4dDDCe6A4da25D</td></tr></tbody></table>

### Ethereum Network

<table><thead><tr><th width="296">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>SharePriceOracle</td><td>0x989b4131687982777881986bca60603eaa9ed9b6</td></tr><tr><td>MaxLzEndpoint</td><td>0xD6fFa374D78FF5C571905E6ac1b75F83052B058E</td></tr></tbody></table>

### Polygon Network

<table><thead><tr><th width="297">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>SharePriceOracle</td><td>0x6dca28080cff24390715e8cd691d2565cb1dfd5d</td></tr><tr><td>MaxLzEndpoint</td><td>0x284eA53a1fDd3082F995A59ecf4dDDCe6A4da25D</td></tr></tbody></table>

### Binance Network

<table><thead><tr><th width="297">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>SharePriceOracle</td><td>0x6dca28080cff24390715e8cd691d2565cb1dfd5d</td></tr><tr><td>MaxLzEndpoint</td><td>0x284eA53a1fDd3082F995A59ecf4dDDCe6A4da25D</td></tr></tbody></table>

### Avalanche Network

<table><thead><tr><th width="296">Contract Name</th><th>Address</th></tr></thead><tbody><tr><td>SharePriceOracle</td><td>0x6dca28080cff24390715e8cd691d2565cb1dfd5d</td></tr><tr><td>MaxLzEndpoint</td><td>0x0x284eA53a1fDd3082F995A59ecf4dDDCe6A4da25D</td></tr></tbody></table>


# Introduction

In the rapidly evolving world of Decentralized Finance (DeFi), the MaxAPY Protocol emerges as a groundbreaking solution for yield aggregation. Designed to optimize users' returns, maxAPY seamlessly integrates with a wide range of DeFi protocols, harnessing the power of multiple yield-generating strategies. By leveraging the collective wisdom of the DeFi ecosystem, maxAPY offers users a streamlined and efficient approach to maximizing their earnings.

The maxAPY Protocol is built upon a robust modular architecture that ensures flexibility, security, and scalability.&#x20;


# Architecture

The MaxAPY Protocol's architecture is designed to be modular and extensible, allowing for easy integration with various DeFi protocols and the development of new yield-generating strategies. The main components of the architecture are the Vault contract and the Strategy contracts.

## MaxApyVaultV2

The `MaxApyVaultV2` contract serves as the central hub for user interactions and fund management. It is an ERC4626-compatible vault that accepts user deposits, manages the allocation of funds to various strategies, and handles the distribution of profits back to users. The vault incorporates features such as deposit limits, fees, and emergency shutdown mechanisms to ensure the security and stability of user funds.

## BaseStrategy

The `BaseStrategy` contract is the foundation upon which all strategies in the MaxAPY Protocol are built. It defines the core functionality and interfaces that strategies must adhere to, including depositing and withdrawing funds, reporting profits and losses, and adjusting positions based on available capital. The base strategy contract ensures a consistent and secure implementation across all strategies.

## Strategy Implementations

The MaxAPY Protocol offers a diverse range of strategy implementations that integrate with various DeFi protocols to generate yield. Each strategy is responsible for depositing funds into a specific protocol, monitoring the position, and harvesting profits when appropriate. Notable strategy implementations include:

`BaseSommelierStrategy`: Supplies underlying tokens to a Sommelier Vault, earning the vault's yield.

`BaseYearnV3Strategy`: A base contract for strategies that interact with Yearn V3 Vaults, enabling staking of vault shares for additional rewards.

These strategy implementations showcase the maxAPY Protocol's versatility and composability, which allow it to adapt to new opportunities and optimize users' returns.


# Vault


# MaxApyFactory

## Overview

The MaxApyVaultFactory contract is responsible for deploying new MaxApy vaults with deterministic addresses. It manages vault creation and ensures proper initialization with standardized naming conventions.

## Constants

```solidity
uint256 public constant ADMIN_ROLE = _ROLE_0;      // Role for administrative functions
uint256 public constant DEPLOYER_ROLE = _ROLE_1;   // Role for deploying new vaults
address public immutable treasury;                  // MaxApy treasury address
```

## Events

```solidity
event CreateVault(address indexed asset, address vaultAddress);
```

## Functions

### Constructor

```solidity
constructor(address _treasury)
```

Initializes the factory with treasury address and sets up initial roles.

Parameters:

* `_treasury`: Address of the MaxApy treasury

### Deployment Functions

### deploy

```solidity
function deploy(
    address underlyingAsset,
    address vaultAdmin,
    bytes32 salt
) external returns (address deployed)
```

Deploys a new vault with a deterministic address using CREATE3.

Parameters:

* `underlyingAsset`: ERC20 token the vault will accept
* `vaultAdmin`: Admin address for the new vault
* `salt`: Unique salt for deterministic address generation

Returns:

* Address of the deployed vault

### View Functions

### computeAddress

```solidity
function computeAddress(bytes32 salt) external view returns (address)
```

Computes the deterministic deployment address for a given salt.

Parameters:

* `salt`: Salt to use for address computation

Returns:

* Expected deployment address

### Internal Functions

### parseName

```solidity
function parseName(string memory symbol) private pure returns (string memory)
```

Generates standardized vault name from asset symbol.

Parameters:

* `symbol`: Asset symbol

Returns:

* Formatted vault name (e.g., "MaxApy-USDC Vault")

### parseSymbol

```solidity
function parseSymbol(string memory symbol) private pure returns (string memory)
```

Generates standardized vault symbol from asset symbol.

Parameters:

* `symbol`: Asset symbol

Returns:

* Formatted vault symbol (e.g., "maxUSDC")


# MaxApyRouter

## Overview

The MaxApyRouter is a helper contract that provides safe and convenient ways to interact with MaxApy vaults. It supports standard ERC20 deposits, permit-style deposits, and native token operations.

## Constants

```solidity
IWrappedToken public immutable wrappedToken;    // Chain's wrapped native token
```

## Errors

```solidity
error FailedNativeTransfer();          // Native token transfer failed
error InsufficientShares();            // Not enough shares received
error InsufficientAssets();            // Not enough assets received
error ReceiveNotAllowed();             // Unauthorized receive call
error InvalidRecipient();              // Zero address recipient
```

## Functions

### Deposit Functions

### deposit

```solidity
function deposit(
    IMaxApyVault vault,
    uint256 amount,
    address recipient,
    uint256 minSharesOut
) external returns (uint256 sharesOut)
```

Deposits tokens into a vault using standard ERC20 transfers.

Parameters:

* `vault`: Target MaxApy vault
* `amount`: Amount of tokens to deposit
* `recipient`: Address to receive shares
* `minSharesOut`: Minimum shares to receive

Returns:

* Amount of shares minted

### depositWithPermit

```solidity
function depositWithPermit(
    IMaxApyVault vault,
    uint256 amount,
    address recipient,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s,
    uint256 minSharesOut
) external returns (uint256 sharesOut)
```

Deposits tokens using EIP-2612 permit for approval-free deposits.

Parameters:

* `vault`: Target MaxApy vault
* `amount`: Amount of tokens to deposit
* `recipient`: Address to receive shares
* `deadline`: Permit deadline
* `v`: Signature component
* `r`: Signature component
* `s`: Signature component
* `minSharesOut`: Minimum shares to receive

Returns:

* Amount of shares minted

### depositNative

```solidity
function depositNative(
    IMaxApyVault vault,
    address recipient,
    uint256 minSharesOut
) external payable returns (uint256 sharesOut)
```

Deposits native token by wrapping it first.

Parameters:

* `vault`: Target MaxApy vault
* `recipient`: Address to receive shares
* `minSharesOut`: Minimum shares to receive

Returns:

* Amount of shares minted

### Withdrawal Functions

### redeem

```solidity
function redeem(
    IMaxApyVault vault,
    uint256 shares,
    address recipient,
    uint256 minAmountOut
) external returns (uint256 amountOut)
```

Redeems shares for underlying tokens.

Parameters:

* `vault`: Target MaxApy vault
* `shares`: Amount of shares to redeem
* `recipient`: Address to receive assets
* `minAmountOut`: Minimum assets to receive

Returns:

* Amount of assets received

### redeemNative

```solidity
function redeemNative(
    IMaxApyVault vault,
    uint256 shares,
    address recipient,
    uint256 minAmountOut
) external returns (uint256 amountOut)
```

Redeems shares for native tokens.

Parameters:

* `vault`: Target MaxApy vault
* `shares`: Amount of shares to redeem
* `recipient`: Address to receive native tokens
* `minAmountOut`: Minimum assets to receive

Returns:

* Amount of native tokens received

### Helper Functions

### \_approveMax

```solidity
function _approveMax(address _vault, address _token) internal
```

Approves maximum token spending limit if current allowance is zero.

Parameters:

* `_vault`: Vault address to approve
* `_token`: Token to approve spending for


# MaxApyVault

## Overview

The MaxApyVault is an ERC4626-compatible vault contract that serves as the core component of the MaxAPY Protocol. It manages user deposits and strategy allocations to generate yield. The vault accepts deposits of a specific underlying asset, issues share to depositors, and allocates the funds across various yield-generating strategies.

## Constants

```solidity
uint256 public constant MAXIMUM_STRATEGIES = 20;       // Maximum number of strategies the vault can manage
uint256 public constant MAX_BPS = 10_000;             // Base points scale (100%)
uint256 public constant SECS_PER_YEAR = 31_556_952;   // Seconds in a year (365.2425 days)
uint256 public constant AUTOPILOT_HARVEST_INTERVAL = 1 weeks;  // Interval between automated harvests
```

Access Control Roles:

```solidity
uint256 public constant ADMIN_ROLE = _ROLE_0;
uint256 public constant EMERGENCY_ADMIN_ROLE = _ROLE_1;
uint256 public constant STRATEGY_ROLE = _ROLE_2;
```

## Errors

```solidity
error QueueIsFull();                            // Withdrawal queue has reached maximum capacity
error VaultInEmergencyShutdownMode();           // Operation not allowed during emergency shutdown
error StrategyInEmergencyExitMode();            // Strategy is in emergency exit mode
error InvalidZeroAddress();                      // Zero address provided where not allowed
error StrategyAlreadyActive();                  // Attempt to add already active strategy
error StrategyNotActive();                      // Operation attempted on inactive strategy
error InvalidStrategyVault();                   // Strategy's vault address doesn't match
error InvalidStrategyUnderlying();              // Strategy's underlying asset doesn't match
error InvalidDebtRatio();                       // Debt ratio exceeds maximum allowed
error InvalidMinDebtPerHarvest();               // Invalid minimum debt per harvest value
error InvalidPerformanceFee();                  // Performance fee exceeds maximum allowed
error InvalidManagementFee();                   // Management fee exceeds maximum allowed
error StrategyDebtRatioAlreadyZero();          // Strategy's debt ratio is already zero
error InvalidQueueOrder();                      // Invalid withdrawal queue ordering
error VaultDepositLimitExceeded();             // Deposit would exceed vault's limit
error InvalidZeroAmount();                      // Zero amount provided where not allowed
error InvalidZeroShares();                      // Zero shares amount where not allowed
error LossGreaterThanStrategyTotalDebt();      // Reported loss exceeds strategy's total debt
error InvalidReportedGainAndDebtPayment();      // Invalid gain and debt payment reported
error FeesAlreadyAssesed();                    // Fees have already been assessed
```

## Events

### Strategy Management Events

```solidity
event StrategyAdded(
    address indexed newStrategy,
    uint16 strategyDebtRatio,
    uint128 strategyMaxDebtPerHarvest,
    uint128 strategyMinDebtPerHarvest,
    uint16 strategyPerformanceFee
);

event StrategyRemoved(address indexed strategy);
event StrategyRevoked(address indexed strategy);
event StrategyExited(address indexed strategy, uint256 withdrawn);

event StrategyUpdated(
    address indexed strategy,
    uint16 newDebtRatio,
    uint128 newMaxDebtPerHarvest,
    uint128 newMinDebtPerHarvest,
    uint16 newPerformanceFee
);

event StrategyReported(
    address indexed strategy,
    uint256 unrealizedGain,
    uint256 loss,
    uint256 debtPayment,
    uint128 strategyTotalUnrealizedGain,
    uint128 strategyTotalLoss,
    uint128 strategyTotalDebt,
    uint256 credit,
    uint16 strategyDebtRatio
);
```

### Configuration Events

```solidity
event EmergencyShutdownUpdated(bool emergencyShutdown);
event AutopilotEnabled(bool isEnabled);
event WithdrawalQueueUpdated(address[20] withdrawalQueue);
event PerformanceFeeUpdated(uint16 newPerformanceFee);
event ManagementFeeUpdated(uint256 newManagementFee);
event DepositLimitUpdated(uint256 newDepositLimit);
event TreasuryUpdated(address treasury);
```

### Operation Events

```solidity
event WithdrawFromStrategy(address indexed strategy, uint128 strategyTotalDebt, uint128 loss);
event FeesReported(uint256 managementFee, uint16 performanceFee, uint256 strategistFee, uint256 duration);
event ForceHarvestFailed(address indexed strategy, bytes reason);
```

## State Variables

```solidity
bool public emergencyShutdown;                  // Emergency shutdown state
bool public autoPilotEnabled;                   // Automated harvesting state
uint8 private immutable _decimals;              // Underlying token decimals
uint8 public nexHarvestStrategyIndex;           // Next strategy index to harvest
uint256 public depositLimit;                    // Maximum total assets limit
uint256 public debtRatio;                       // Total debt ratio across strategies (in BPS)
uint256 public totalIdle;                       // Tokens held in vault
uint256 public totalDebt;                       // Total tokens allocated to strategies
uint256 public lastReport;                      // Timestamp of last strategy report
uint256 public performanceFee;                  // Performance fee rate (in BPS)
uint256 public managementFee;                   // Management fee rate (in BPS)
address public treasury;                        // Fee recipient address

mapping(address => StrategyData) public strategies;  // Strategy data mapping
address[MAXIMUM_STRATEGIES] public withdrawalQueue;   // Strategy withdrawal order

string private _name;                           // Vault shares token name
string private _symbol;                         // Vault shares token symbol
address private immutable _underlyingAsset;     // Underlying asset address
```

## Functions

### Basic View Functions

### name

```solidity
function name() public view override returns (string memory)
```

Returns the name of the vault shares token.

Returns:

* The token name

### symbol

```solidity
function symbol() public view override returns (string memory)
```

Returns the symbol of the vault shares token.

Returns:

* The token symbol

### asset

```solidity
function asset() public view override returns (address)
```

Returns the address of the underlying token that the vault accepts.

Returns:

* The underlying asset address

### totalAssets

```solidity
function totalAssets() public view override returns (uint256)
```

Returns total assets managed by vault, including idle funds and assets deployed in strategies.

Returns:

* The total assets under management

### totalDeposits

```solidity
function totalDeposits() public view returns (uint256)
```

Returns the sum of idle assets and debt allocated to strategies.

Returns:

* The total accounted assets

### sharePrice

```solidity
function sharePrice() external view returns (uint256)
```

Returns the current price of one vault share regarding the underlying asset.

Returns:

* The current share price

### Asset/Share Conversion Functions

### convertToShares

```solidity
function convertToShares(uint256 assets) public view override returns (uint256)
```

Calculates how many shares would be minted for a given amount of assets.

Parameters:

* `assets`: Amount of underlying assets to convert

Returns:

* The equivalent amount of shares

### convertToAssets

```solidity
function convertToAssets(uint256 shares) public view override returns (uint256)
```

Calculates how many underlying assets a given amount of shares represents.

Parameters:

* `shares`: Amount of shares to convert

Returns:

* The equivalent amount of assets

### Deposit Limit Functions

### maxDeposit

```solidity
function maxDeposit(address to) public view override returns (uint256)
```

Calculates the maximum amount of assets that can be deposited.

Parameters:

* `to`: Address that would receive the shares (unused in calculation)

Returns:

* Maximum deposit amount allowed

### maxMint

```solidity
function maxMint(address to) public view override returns (uint256)
```

Calculates the maximum amount of shares that can be minted.

Parameters:

* `to`: Address that would receive the shares (unused in calculation)

Returns:

* Maximum shares that can be minted

### maxWithdraw

```solidity
function maxWithdraw(address owner) public view override returns (uint256)
```

Returns the maximum amount of assets that an address can withdraw.

Parameters:

* `owner`: Address of the shares owner

Returns:

* Maximum assets that can be withdrawn

### Preview Functions

### previewMint

```solidity
function previewMint(uint256 shares) public view override returns (uint256)
```

Simulates the amount of assets needed to mint a specific amount of shares.

Parameters:

* `shares`: The amount of shares to mint

Returns:

* The amount of assets required

### previewWithdraw

```solidity
function previewWithdraw(uint256 assets) public view override returns (uint256)
```

Simulates the amount of shares needed to withdraw a specific amount of assets.

Parameters:

* `assets`: The amount of assets to withdraw

Returns:

* The amount of shares required

### previewRedeem

```solidity
function previewRedeem(uint256 shares) public view override returns (uint256)
```

Simulates the amount of assets that would be received when redeeming shares.

Parameters:

* `shares`: The amount of shares to redeem

Returns:

* The amount of assets that would be received

### Strategy View Functions

### creditAvailable

```solidity
function creditAvailable(address strategy) external view returns (uint256)
```

Returns the amount of additional funds a strategy can borrow from the vault.

Parameters:

* `strategy`: The strategy address to check

Returns:

* The amount of credit available

### debtOutstanding

```solidity
function debtOutstanding(address strategy) external view returns (uint256)
```

Returns the amount of debt that a strategy needs to repay to the vault.

Parameters:

* `strategy`: The strategy address to check

Returns:

* The amount of outstanding debt

### getStrategyTotalDebt

```solidity
function getStrategyTotalDebt(address strategy) external view returns (uint256)
```

Returns the total debt allocated to a strategy.

Parameters:

* `strategy`: The strategy address to check

Returns:

* The strategy's total debt

### Deposit Functions

### deposit

```solidity
function deposit(uint256 assets, address receiver) public returns (uint256 shares)
```

Deposits underlying assets into the vault and mints shares to the receiver. Only possible when vault is not in emergency shutdown.

Parameters:

* `assets`: Amount of underlying assets to deposit
* `receiver`: Address to receive the minted shares

Returns:

* Amount of shares minted

### depositWithPermit

```solidity
function depositWithPermit(
    address owner,
    uint256 assets,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s,
    address receiver
) public returns (uint256 shares)
```

Deposits assets using an EIP-2612 permit for approval. Prevents extra approve transaction.

Parameters:

* `owner`: Owner of the assets
* `assets`: Amount of assets to deposit
* `deadline`: Timestamp until which the permit is valid
* `v`: Signature parameter
* `r`: Signature parameter
* `s`: Signature parameter
* `receiver`: Address to receive the shares

Returns:

* Amount of shares minted

### mint

```solidity
function mint(uint256 shares, address receiver) public returns (uint256 assets)
```

Mints an exact amount of shares by depositing the necessary amount of assets.

Parameters:

* `shares`: Amount of shares to mint
* `receiver`: Address to receive the shares

Returns:

* Amount of assets deposited

### mintWithPermit

```solidity
function mintWithPermit(
    address owner,
    uint256 shares,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s,
    address receiver
) public returns (uint256 assets)
```

Mints exact shares using an EIP-2612 permit for approval.

Parameters:

* `owner`: Owner of the assets
* `shares`: Amount of shares to mint
* `deadline`: Timestamp until which the permit is valid
* `v`: Signature parameter
* `r`: Signature parameter
* `s`: Signature parameter
* `receiver`: Address to receive the shares

Returns:

* Amount of assets deposited

### Withdrawal Functions

### withdraw

```solidity
function withdraw(
    uint256 assets,
    address receiver,
    address owner
) public returns (uint256 shares)
```

Withdraws exact assets by burning the required amount of shares.

Parameters:

* `assets`: Amount of assets to withdraw
* `receiver`: Address to receive the assets
* `owner`: Owner of the shares

Returns:

* Amount of shares burned

### redeem

```solidity
function redeem(
    uint256 shares,
    address receiver,
    address owner
) public returns (uint256 assets)
```

Burns exact shares for underlying assets.

Parameters:

* `shares`: Amount of shares to redeem
* `receiver`: Address to receive the assets
* `owner`: Owner of the shares

Returns:

* Amount of assets withdrawn

### Strategy Management Functions

### addStrategy

```solidity
function addStrategy(
    address strategy,
    uint256 debtRatio,
    uint256 maxDebtPerHarvest,
    uint256 minDebtPerHarvest,
    uint256 performanceFee
) external
```

Adds a new strategy to the vault. Can only be called by admin and not during emergency shutdown.

Parameters:

* `strategy`: Address of the strategy to add
* `debtRatio`: Percentage of vault's total assets that strategy can manage (in BPS)
* `maxDebtPerHarvest`: Maximum debt the strategy can take on in a single harvest
* `minDebtPerHarvest`: Minimum debt the strategy should take in a single harvest
* `performanceFee`: Performance fee for the strategy (in BPS)

### removeStrategy

```solidity
function removeStrategy(address strategy) external
```

Removes a strategy from the vault's withdrawal queue. Can only be called by admin and not during emergency shutdown.

Parameters:

* `strategy`: Address of the strategy to remove

### revokeStrategy

```solidity
function revokeStrategy(address strategy) external
```

Revokes a strategy by setting its debt ratio to 0 and preventing future deposits. Can only be called by admin.

Parameters:

* `strategy`: Address of the strategy to revoke

### exitStrategy

```solidity
function exitStrategy(address strategy) external
```

Fully exits a strategy by liquidating all positions and removing it from the withdrawal queue. Can only be called by admin.

Parameters:

* `strategy`: Address of the strategy to exit

### updateStrategyData

```solidity
function updateStrategyData(
    address strategy,
    uint256 newDebtRatio,
    uint256 newMaxDebtPerHarvest,
    uint256 newMinDebtPerHarvest,
    uint256 newPerformanceFee
) external
```

Updates a strategy's configuration parameters. Can only be called by admin.

Parameters:

* `strategy`: Address of the strategy to update
* `newDebtRatio`: New debt ratio (in BPS)
* `newMaxDebtPerHarvest`: New maximum debt per harvest
* `newMinDebtPerHarvest`: New minimum debt per harvest
* `newPerformanceFee`: New performance fee (in BPS)

### Reporting Functions

### report

```solidity
function report(
    uint128 realizedGain,
    uint128 unrealizedGain,
    uint128 loss,
    uint128 debtPayment,
    address managementFeeReceiver
) external returns (uint256)
```

Reports strategy performance and handles profit/loss accounting. Can only be called by strategies.

Parameters:

* `realizedGain`: Realized profit
* `unrealizedGain`: Unrealized profit
* `loss`: Amount of losses
* `debtPayment`: Amount of debt being repaid
* `managementFeeReceiver`: Address to receive management fees

Returns:

* Updated debt outstanding

### Configuration Functions

### setWithdrawalQueue

```solidity
function setWithdrawalQueue(address[MAXIMUM_STRATEGIES] calldata queue) external
```

Sets the order of strategies for withdrawals. Can only be called by admin.

Parameters:

* `queue`: Array of strategy addresses in withdrawal order

### setPerformanceFee

```solidity
function setPerformanceFee(uint256 _performanceFee) external
```

Updates the vault's performance fee. Can only be called by admin.

Parameters:

* `_performanceFee`: New performance fee (in BPS)

### setManagementFee

```solidity
function setManagementFee(uint256 _managementFee) external
```

Updates the vault's management fee. Can only be called by admin.

Parameters:

* `_managementFee`: New management fee (in BPS)

### setDepositLimit

```solidity
function setDepositLimit(uint256 _depositLimit) external
```

Sets the maximum total assets the vault can accept. Can only be called by admin.

Parameters:

* `_depositLimit`: New deposit limit

### setEmergencyShutdown

```solidity
function setEmergencyShutdown(bool _emergencyShutdown) external
```

Enables/disables emergency shutdown mode. Can only be called by emergency admin.

Parameters:

* `_emergencyShutdown`: True to enable shutdown, false to disable

### setTreasury

```solidity
function setTreasury(address _treasury) external
```

Updates the treasury address that receives fees. Can only be called by admin.

Parameters:

* `_treasury`: New treasury address

### setAutopilotEnabled

```solidity
function setAutopilotEnabled(bool _autoPilotEnabled) external
```

Enables/disables automated strategy harvesting. Can only be called by admin.

Parameters:

* `_autoPilotEnabled`: True to enable autopilot, false to disable

### setAutoPilot

```solidity
function setAutoPilot(bool _autoPilot) external
```

Sets autopilot mode for a specific strategy. Can only be called by strategies.

Parameters:

* `_autoPilot`: True to enable autopilot for the strategy

### Internal Functions

### \_forceOneHarvest

```solidity
function _forceOneHarvest(address harvester) internal returns (address strategy, bool success, bytes memory reason)
```

Forces a harvest of the next strategy in autopilot mode.

Parameters:

* `harvester`: Address that will receive extra shares for harvesting

Returns:

* `strategy`: Address of the harvested strategy
* `success`: Whether the harvest was successful
* `reason`: Error reason if harvest failed

### \_reportLoss

```solidity
function _reportLoss(address strategy, uint256 loss) internal
```

Handles strategy loss reporting by adjusting debt ratios and total debt.

Parameters:

* `strategy`: Strategy reporting the loss
* `loss`: Amount of loss to report

### \_assessFees

```solidity
function _assessFees(address strategy, uint256 gain, address managementFeeReceiver) internal returns (uint256)
```

Calculates and distributes performance, management, and strategist fees.

Parameters:

* `strategy`: Strategy the fees are being assessed for
* `gain`: Amount of profit to assess fees on
* `managementFeeReceiver`: Address to receive management fees

Returns:

* Total amount of fees assessed

### \_creditAvailable

```solidity
function _creditAvailable(address strategy) internal view returns (uint256)
```

Calculates available credit line for a strategy.

Parameters:

* `strategy`: Strategy to check credit for

Returns:

* Amount of credit available

### \_computeDebtLimit

```solidity
function _computeDebtLimit(uint256 _debtRatio, uint256 totalAssets_) internal pure returns (uint256 debtLimit)
```

Calculates maximum debt limit based on debt ratio and total assets.

Parameters:

* `_debtRatio`: Debt ratio to use (in BPS)
* `totalAssets_`: Total assets to base calculation on

Returns:

* Calculated debt limit

### \_debtOutstanding

```solidity
function _debtOutstanding(address strategy) internal view returns (uint256)
```

Calculates how much debt a strategy needs to pay back.

Parameters:

* `strategy`: Strategy to check debt for

Returns:

* Amount of outstanding debt

### \_organizeWithdrawalQueue

```solidity
function _organizeWithdrawalQueue() internal
```

Reorganizes withdrawal queue by removing gaps and maintaining relative order.

### \_revokeStrategy

```solidity
function _revokeStrategy(address strategy, uint256 strategyDebtRatio) internal
```

Internal function to revoke a strategy and update debt ratios.

Parameters:

* `strategy`: Strategy to revoke
* `strategyDebtRatio`: Current debt ratio of the strategy

### \_issueSharesForAmount

```solidity
function _issueSharesForAmount(address to, uint256 amount) internal returns (uint256 shares)
```

Calculates and mints shares for a given amount of assets.

Parameters:

* `to`: Address to receive shares
* `amount`: Amount of assets to convert to shares

Returns:

* Amount of shares minted

### Helper Functions

### *eitherIsZero*

```solidity
function _eitherIsZero_(uint256 a, uint256 b) internal pure returns (bool)
```

Checks if either of two values is zero.

Parameters:

* `a`: First value to check
* `b`: Second value to check

Returns:

* True if either value is zero

### *inc*

```solidity
function _inc_(uint256 x) internal pure returns (uint256)
```

Returns value plus one.

Parameters:

* `x`: Value to increment

Returns:

* Incremented value

### \_sub0

```solidity
function _sub0(uint256 a, uint256 b) internal pure returns (uint256)
```

Safely subtracts b from a, returning 0 if result would be negative.

Parameters:

* `a`: Value to subtract from
* `b`: Value to subtract

Returns:

* Result of subtraction or 0

### ERC4626 Override Functions

### \_underlyingDecimals

```solidity
function _underlyingDecimals() internal view override returns (uint8)
```

Returns decimals of the underlying token.

Returns:

* Number of decimals

### \_decimalsOffset

```solidity
function _decimalsOffset() internal pure override returns (uint8)
```

Returns decimal offset used to prevent inflation attacks.

Returns:

* Decimal offset value (6)

### \_totalAssets

```solidity
function _totalAssets() internal view returns (uint256)
```

Calculates total assets including idle funds and strategy positions.

Returns:

* Total assets under management

### \_totalDeposits

```solidity
function _totalDeposits() internal view returns (uint256)
```

Returns sum of idle assets and total debt.

Returns:

* Total deposited assets

### \_deposit

```solidity
function _deposit(address by, address to, uint256 assets, uint256 shares) internal override
```

Internal deposit implementation with additional checks.

Parameters:

* `by`: Address depositing assets
* `to`: Address receiving shares
* `assets`: Amount of assets being deposited
* `shares`: Amount of shares to mint

### \_withdraw

```solidity
function _withdraw(address by, address to, address owner, uint256 assets) private returns (uint256 shares)
```

Internal withdraw implementation handling liquidations.

Parameters:

* `by`: Address initiating withdrawal
* `to`: Address receiving assets
* `owner`: Owner of the shares
* `assets`: Amount of assets to withdraw

Returns:

* Amount of shares burned

### \_redeem

```solidity
function _redeem(address by, address to, address owner, uint256 shares) private returns (uint256 assets)
```

Internal redeem implementation handling liquidations.

Parameters:

* `by`: Address initiating redemption
* `to`: Address receiving assets
* `owner`: Owner of the shares
* `shares`: Amount of shares to redeem

Returns:

* Amount of assets returned


# Periphery


# MaxApyHarvester

## Overview

The MaxApyHarvester contract serves as an internal mechanism to execute harvests atomically. It manages strategy allocations and harvests for the MaxApy protocol, handling batch operations for multiple strategies.

## Constants

```solidity
uint256 public constant ADMIN_ROLE = _ROLE_0;     // Role for administrative functions
uint256 public constant KEEPER_ROLE = _ROLE_1;    // Role for keeper functions
address public constant DEFAULT_HARVESTER = address(0);  // Default harvester address
```

## Errors

```solidity
error AddStrategyFailed();           // Strategy addition failed
error CantReceiveETH();             // Contract cannot receive ETH
error Fallback();                   // Fallback function called
error HarvestFailed();              // Harvest operation failed
error NotOwner();                   // Caller is not the owner
error MaximumStrategiesReached();   // Maximum strategy limit reached
```

## State Variables

```solidity
IStrategy strategy;    // Reference to the current strategy being processed
```

## Structs

```solidity
struct AllocationData {
    address strategyAddress;        // Address of the strategy
    uint256 debtRatio;             // Debt ratio for the strategy
    uint256 maxDebtPerHarvest;     // Maximum debt per harvest
    uint256 minDebtPerHarvest;     // Minimum debt per harvest
    uint256 performanceFee;        // Performance fee percentage
}

struct HarvestData {
    address strategyAddress;           // Strategy address to harvest
    uint256 minExpectedBalance;        // Minimum expected balance after harvest
    uint256 minOutputAfterInvestment;  // Minimum output after investment
    uint256 deadline;                  // Deadline for harvest operation
}
```

## Functions

### Constructor

```solidity
constructor(address admin, address[] memory keepers)
```

Initializes the contract with admin and keeper roles.

Parameters:

* `admin`: Address of the admin
* `keepers`: Array of keeper addresses to be granted roles

### Fallback Functions

### fallback

```solidity
fallback() external payable
```

Reverts any direct calls to the contract.

### receive

```solidity
receive() external payable
```

Reverts any ETH transfers to the contract.

### Core Functions

### batchAllocate

```solidity
function batchAllocate(IMaxApyVault vault, AllocationData[] calldata strategies) public checkRoles(KEEPER_ROLE)
```

Executes batch strategy allocation for the MaxApy protocol.

Parameters:

* `vault`: MaxApyVault contract instance
* `strategies`: Array of strategy allocation data

### batchHarvest

```solidity
function batchHarvest(IMaxApyVault vault, HarvestData[] calldata harvests) public checkRoles(KEEPER_ROLE)
```

Executes batch harvesting operations for multiple strategies.

Parameters:

* `vault`: MaxApyVault contract instance
* `harvests`: Array of harvest data for strategies

### batchAllocateAndHarvest

```solidity
function batchAllocateAndHarvest(
    IMaxApyVault vault,
    AllocationData[] calldata allocations,
    HarvestData[] calldata harvests
) external returns (bool)
```

Combines batch allocation and harvesting in a single transaction.

Parameters:

* `vault`: MaxApyVault contract instance
* `allocations`: Array of strategy allocation data
* `harvests`: Array of harvest data

Returns:

* Boolean indicating success

### Simulation Functions

### \_simulateBatchAllocateAndHarvest

```solidity
solidityCopyfunction _simulateBatchAllocateAndHarvest(
    IMaxApyVault vault,
    AllocationData[] calldata allocations,
    HarvestData[] calldata harvests
) public
```

Internal function that performs a dry-run of batch allocation and harvest operations. It simulates the entire process of adding new strategies and harvesting, capturing the state changes without permanently altering the blockchain state.

This function works by:

1. Recording initial total assets
2. Simulating strategy allocations
3. Simulating harvests for each strategy
4. Collecting detailed simulation results
5. Reverting with encoded data containing all simulation outcomes

Parameters:

* `vault`: MaxApyVault contract instance
* `allocations`: Array of strategy allocation data
* `harvests`: Array of harvest data

### simulateBatchAllocateAndHarvest

```solidity
solidityCopyfunction simulateBatchAllocateAndHarvest(
    IMaxApyVault vault,
    AllocationData[] calldata allocations,
    HarvestData[] calldata harvests
) external returns (
    uint256 totalAssetsBefore,
    uint256 totalAssetsAfter,
    bytes[] memory simulationResults
)
```

An external function that provides a safe way to preview the outcomes of strategy changes and harvests before actually executing them. This function is crucial for risk management and optimization of strategy allocations.

Key benefits:

* Allows analysis of potential returns before committing funds
* It helps in comparing different strategy combinations
* Provides insights into expected asset value changes
* Enables validation of allocation decisions before execution
* Assists in optimizing harvest parameters

Parameters:

* `vault`: MaxApyVault contract instance
* `allocations`: Array of strategy allocation data
* `harvests`: Array of harvest data

Returns:

* `totalAssetsBefore`: Total vault assets before simulated operations
* `totalAssetsAfter`: Projected total assets after operations
* `simulationResults`: Detailed results for each strategy, including:
  * Expected balances
  * Investment outputs
  * Intended vs actual invest/divest amounts
  * Strategy-specific performance metrics

Usage: This simulation mechanism is essential for protocol management, allowing operators to:

1. Test new strategy combinations safely
2. Validate allocation ratios
3. Preview harvest outcomes
4. Optimize timing and parameters of operations
5. Minimize risks when adjusting strategy allocations

### Modifiers

### checkRoles

```solidity
modifier checkRoles(uint256 roles)
```

Ensures caller has required roles.

Parameters:

* `roles`: Required role permissions


# Base Strategies


# BaseStrategy

## Overview

The BaseStrategy is the foundational abstract contract that all MaxApy strategies inherit from. Adapted from Yearn's v2 BaseStrategy, it defines core functionality and interfaces that strategies must implement for interacting with the MaxApy vault and external protocols.

## Constants

```solidity
uint256 public constant ADMIN_ROLE = _ROLE_0;             // Admin role identifier
uint256 public constant EMERGENCY_ADMIN_ROLE = _ROLE_1;   // Emergency admin role identifier
uint256 public constant VAULT_ROLE = _ROLE_2;             // Vault role identifier
uint256 public constant KEEPER_ROLE = _ROLE_3;            // Keeper role identifier
uint256 public constant MAX_BPS = 10_000;                 // Maximum basis points (100%)
```

## Events

```solidity
event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);
event StrategyEmergencyExitUpdated(address indexed strategy, uint256 emergencyExitStatus);
event StrategistUpdated(address indexed strategy, address newStrategist);
event StrategyAutopilotUpdated(address indexed strategy, bool autoPilotStatus);
```

## State Variables

```solidity
IMaxApyVault public vault;                  // Associated MaxApy vault
address public underlyingAsset;             // Strategy's underlying asset
uint256 public emergencyExit;               // Emergency shutdown state
bytes32 public strategyName;                // Strategy identifier
address public strategist;                  // Strategy manager address
uint256 public lastEstimatedTotalAssets;    // Last recorded total assets
uint256[20] private __gap;                  // Upgradeability gap
```

## Functions

### Initialization Functions

### \_\_BaseStrategy\_init

```solidity
function __BaseStrategy_init(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist
) internal virtual
```

Initializes the strategy with necessary components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Strategy identifier
* `_strategist`: Strategist address

### Core Functions

### liquidate

```solidity
function liquidate(uint256 amountNeeded) external virtual returns (uint256 loss)
```

Withdraws assets up to requested amount.

Parameters:

* `amountNeeded`: Amount of assets to withdraw

Returns:

* Amount of loss incurred

### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external virtual returns (uint256 loss)
```

Withdraws exact amount of assets.

Parameters:

* `amountNeeded`: Exact amount of assets to withdraw

Returns:

* Amount of loss incurred to achieve exact withdrawal

### harvest

```solidity
function harvest(
    uint256 minExpectedBalance,
    uint256 minOutputAfterInvestment,
    address harvester,
    uint256 deadline
) external
```

Harvests gains and reinvests.

Parameters:

* `minExpectedBalance`: Minimum balance expected after operations
* `minOutputAfterInvestment`: Minimum expected output from reinvestment
* `harvester`: Address to receive management fees
* `deadline`: Transaction deadline

### Configuration Functions

### setEmergencyExit

```solidity
function setEmergencyExit(uint256 _emergencyExit) external
```

Sets emergency exit mode.

Parameters:

* `_emergencyExit`: Exit mode state (1=inactive, 2=active)

### setStrategist

```solidity
function setStrategist(address _newStrategist) external
```

Updates strategist address.

Parameters:

* `_newStrategist`: New strategist address

### setAutopilot

```solidity
function setAutopilot(bool _autoPilot) external
```

Enables/disables automated harvesting.

Parameters:

* `_autoPilot`: Autopilot state

### View Functions

### estimatedTotalAssets

```solidity
function estimatedTotalAssets() public view returns (uint256)
```

Returns total assets under management.

Returns:

* Current total assets value

### isActive

```solidity
function isActive() public view returns (bool)
```

Checks if strategy is actively managing positions.

Returns:

* True if strategy is active

### unharvestedAmount

```solidity
function unharvestedAmount() external view virtual returns (int256)
```

Calculates unrealized gains/losses since last harvest.

Returns:

* Net unrealized profit/loss

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual returns (uint256)
```

Simulates withdrawal including losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* Expected output amount

### Required Virtual Functions

These functions must be implemented by inheriting strategies:

```solidity
function _adjustPosition(uint256 debtOutstanding, uint256 minOutputAfterInvestment) internal virtual;
function _liquidatePosition(uint256 amountNeeded) internal virtual returns (uint256 liquidatedAmount, uint256 loss);
function _liquidateAllPositions() internal virtual returns (uint256 amountFreed);
function _prepareReturn(uint256 debtOutstanding, uint256 minExpectedBalance) internal virtual returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment);
function _estimatedTotalAssets() internal view virtual returns (uint256);
function previewLiquidate(uint256 requestedAmount) public view virtual returns (uint256);
function previewLiquidateExact(uint256 liquidatedAmount) public view virtual returns (uint256);
function maxLiquidate() public view virtual returns (uint256);
function maxLiquidateExact() public view virtual returns (uint256);
```


# BaseSommelierStrategy

## Overview

The BaseSommelierStrategy contract serves as the foundation for strategies that interact with Sommelier protocol in the MaxAPY ecosystem. It manages deposits into Sommelier Cellars, handles reward collection, and executes withdrawals.

## Errors

```solidity
error NotEnoughFundsToInvest();        // Insufficient funds for investment
error CellarIsPaused();                // Sommelier Cellar is paused
error InvalidZeroAddress();             // Zero address provided
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 requestedShares, uint256 amountDivested);
event MinSingleTradeUpdated(uint256 minSingleTrade);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
```

## State Variables

```solidity
ICellar public cellar;                 // Sommelier Cellar contract
uint256 public maxSingleTrade;         // Maximum size for a single trade
uint256 public minSingleTrade;         // Minimum size for a single trade
```

## Functions

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICellar _cellar
) public virtual initializer
```

Initializes the strategy with Sommelier components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_cellar`: Sommelier Cellar address

### Core Functions

### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external returns (uint256 loss)
```

Withdraws exact amount of assets from Cellar.

Parameters:

* `amountNeeded`: Amount of assets to withdraw

Returns:

* Amount of loss incurred

### View Functions

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view returns (uint256)
```

Calculates expected output for a withdrawal.

Parameters:

* `requestedAmount`: Amount requested to withdraw

Returns:

* Expected liquidated amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view returns (uint256)
```

Calculates input needed for desired withdrawal amount.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* Required input amount

### maxLiquidate

```solidity
function maxLiquidate() public view returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view returns (uint256)
```

Returns maximum withdrawable amount before losses.

Returns:

* Maximum withdrawable amount before losses

### Configuration Functions

### setMinSingleTrade

```solidity
function setMinSingleTrade(uint256 _minSingleTrade) external
```

Sets minimum trade size for the strategy.

Parameters:

* `_minSingleTrade`: New minimum trade size

### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external
```

Sets maximum trade size for the strategy.

Parameters:

* `_maxSingleTrade`: New maximum trade size

### Internal Functions

### \_prepareReturn

```solidity
function _prepareReturn(
    uint256 debtOutstanding,
    uint256 minExpectedBalance
) internal returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment)
```

Prepares strategy returns and handles profits/losses.

Parameters:

* `debtOutstanding`: Outstanding debt amount
* `minExpectedBalance`: Minimum expected balance

Returns:

* `unrealizedProfit`: Unrealized profit amount
* `loss`: Loss amount
* `debtPayment`: Debt payment amount

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal returns (uint256)
```

Deposits assets into Sommelier Cellar.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* Amount of deposits received

### \_divest

```solidity
function _divest(uint256 shares) internal returns (uint256)
```

Withdraws assets from Sommelier Cellar.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* Amount of assets received

### Internal View Functions

### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view returns (uint256)
```

Calculates underlying value of Cellar shares.

Parameters:

* `shares`: Amount of shares

Returns:

* Underlying asset value

### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view returns (uint256)
```

Calculates shares needed for given amount.

Parameters:

* `amount`: Amount of underlying assets

Returns:

* Required shares amount

### \_shareBalance

```solidity
function _shareBalance() internal view returns (uint256)
```

Returns strategy's Cellar share balance.

Returns:

* Current share balance

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view returns (uint256)
```

Calculates total assets under management.

Returns:

* Total assets value


# BaseYearnV3Strategy

## Overview

The BaseYearnV3Strategy contract is the base implementation for strategies interacting with Yearn v3 vaults in the MaxAPY ecosystem. It handles deposits into Yearn vaults, manages share calculations, and provides core functionality for vault interactions.

## Constants

No internal constants defined in this contract.

## Errors

```solidity
error NotEnoughFundsToInvest();    // Insufficient funds for investment
error InvalidZeroAddress();         // Zero address provided
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 requestedShares, uint256 amountDivested);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
event MinSingleTradeUpdated(uint256 minSingleTrade);
```

## State Variables

```solidity
IYVaultV3 public yVault;         // Yearn vault reference
uint256 public maxSingleTrade;   // Maximum trade size
uint256 public minSingleTrade;   // Minimum trade size
```

## Functions

### Initialization Functions

#### constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual initializer
```

Initializes the strategy with Yearn components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external returns (uint256 loss)
```

Withdraws exactly amountNeeded to vault. Can only be called by vault.

#### Parameters:

* `amountNeeded`: Amount of underlying asset to withdraw

#### Returns:

* `loss`: Amount of loss realized during withdrawal

### Configuration Functions

#### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external checkRoles(ADMIN_ROLE)
```

Sets the maximum amount allowed for a single trade.

Parameters:

* `_maxSingleTrade`: New maximum trade size

#### setMinSingleTrade

```solidity
function setMinSingleTrade(uint256 _minSingleTrade) external checkRoles(ADMIN_ROLE)
```

Sets the minimum amount required for a single trade.

Parameters:

* `_minSingleTrade`: New minimum trade size

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual override returns (uint256 liquidatedAmount)
```

Simulates withdrawal including potential losses.

Parameters:

* `requestedAmount`: Amount requested to withdraw

Returns:

* `liquidatedAmount`: Expected output amount after losses

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view virtual override returns (uint256 requestedAmount)
```

Calculates input amount needed for exact output.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

#### maxLiquidate

```solidity
function maxLiquidate() public view virtual override returns (uint256)
```

Returns maximum withdrawable amount considering potential losses.

Returns:

* Maximum amount that can be withdrawn

#### maxLiquidateExact

```solidity
function maxLiquidateExact() public view virtual override returns (uint256)
```

Returns maximum withdrawable amount before considering losses.

Returns:

* Maximum amount that can be withdrawn before losses

### Internal Functions

#### \_prepareReturn

```solidity
function _prepareReturn(
    uint256 debtOutstanding,
    uint256 minExpectedBalance
) internal virtual override returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment)
```

Prepares strategy returns and handles debt repayment.

Parameters:

* `debtOutstanding`: Amount of debt that needs to be repaid
* `minExpectedBalance`: Minimum balance expected after operation

Returns:

* `unrealizedProfit`: Amount of profit generated
* `loss`: Amount of losses incurred
* `debtPayment`: Amount of debt repaid

#### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal virtual override
```

Adjusts strategy positions based on available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output after investment

#### \_invest

```solidity
function _invest(
    uint256 amount,
    uint256 minOutputAfterInvestment
) internal virtual returns (uint256 depositedAmount)
```

Deposits assets into Yearn vault.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens successfully invested

#### \_divest

```solidity
function _divest(uint256 shares) internal virtual returns (uint256 withdrawn)
```

Withdraws assets from Yearn vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

#### \_liquidatePosition

```solidity
function _liquidatePosition(uint256 amountNeeded) internal virtual override returns (uint256 liquidatedAmount, uint256 loss)
```

Liquidates position up to requested amount.

Parameters:

* `amountNeeded`: Amount needed to liquidate

Returns:

* `liquidatedAmount`: Amount actually liquidated
* `loss`: Amount of losses incurred

#### \_liquidateAllPositions

```solidity
function _liquidateAllPositions() internal virtual override returns (uint256 amountFreed)
```

Liquidates all positions, used during emergency exit.

Returns:

* `amountFreed`: Total amount freed from positions

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view virtual returns (uint256 _assets)
```

Calculates the underlying value of shares.

Parameters:

* `shares`: Amount of shares to value

Returns:

* `_assets`: Value in underlying asset terms

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view virtual returns (uint256 _shares)
```

Calculates shares needed for a given amount of assets.

Parameters:

* `amount`: Amount of assets

Returns:

* `_shares`: Required number of shares

#### \_shareBalance

```solidity
function _shareBalance() internal view virtual returns (uint256 _balance)
```

Returns the strategy's current Yearn vault share balance.

Returns:

* `_balance`: Current share balance

#### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view virtual override returns (uint256)
```

Calculates total value of all assets under management.

Returns:

* Total value of assets in underlying terms

#### \_simulateHarvest

```solidity
function _simulateHarvest() public override
```

Simulates a harvest operation and reverts with simulation data. Used for testing and verification.


# BaseYearnV2Strategy

## Overview

The BaseYearnV2Strategy contract is the base implementation for strategies interacting with Yearn v2 vaults in the MaxAPY ecosystem. It handles deposits into Yearn vaults, manages share calculations, and handles locked profit mechanics.

## Constants

```solidity
uint256 internal constant DEGRADATION_COEFFICIENT = 10 ** 18;  // Coefficient for profit unlocking
```

## Errors

```solidity
error NotEnoughFundsToInvest();    // Insufficient funds for investment
error InvalidZeroAddress();         // Zero address provided
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 requestedShares, uint256 amountDivested);
event MinSingleTradeUpdated(uint256 minSingleTrade);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
```

## State Variables

```solidity
IYVault public yVault;             // Yearn vault reference
uint256 public minSingleTrade;     // Minimum trade size
uint256 public maxSingleTrade;     // Maximum trade size
```

## Functions

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVault _yVault
) public virtual initializer
```

Initializes the strategy with Yearn components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn vault address

### Configuration Functions

### setMinSingleTrade

```solidity
function setMinSingleTrade(uint256 _minSingleTrade) external
```

Sets minimum trade size.

Parameters:

* `_minSingleTrade`: New minimum trade size

### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external
```

Sets maximum trade size.

Parameters:

* `_maxSingleTrade`: New maximum trade size

### View Functions

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view returns (uint256)
```

Simulates withdrawal including losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* Expected output amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view returns (uint256)
```

Calculates input needed for exact output.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* Required input amount

### maxLiquidate

```solidity
function maxLiquidate() public view returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view returns (uint256)
```

Returns maximum withdrawable amount before losses.

Returns:

* Maximum withdrawable amount before losses

### Internal Functions

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal returns (uint256)
```

Deposits assets into Yearn vault.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* Amount of tokens received

### \_divest

```solidity
function _divest(uint256 shares) internal returns (uint256)
```

Withdraws assets from Yearn vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* Amount of assets received

### Internal View Functions

### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view returns (uint256)
```

Calculates underlying value of Yearn shares.

Parameters:

* `shares`: Amount of shares

Returns:

* Underlying asset value

### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view returns (uint256)
```

Calculates shares needed for given amount.

Parameters:

* `amount`: Amount of assets

Returns:

* Required shares amount

### \_freeFunds

```solidity
function _freeFunds() internal view returns (uint256)
```

Calculates available assets in Yearn vault.

Returns:

* Available funds amount

### \_calculateLockedProfit

```solidity
function _calculateLockedProfit() internal view returns (uint256)
```

Calculates locked profit in Yearn vault.

Returns:

* Locked profit amount

### \_shareBalance

```solidity
function _shareBalance() internal view returns (uint256)
```

Returns strategy's Yearn share balance.

Returns:

* Current share balance

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view returns (uint256)
```

Calculates total assets under management.

Returns:

* Total assets value


# BaseConvexStrategy

## Overview

The BaseConvexStrategy contract serves as the foundation for strategies that interact with Convex protocols in the MaxAPY ecosystem. It provides the core functionality for depositing assets into Convex pools, managing rewards, and handling withdrawals.

## Constants

```solidity
uint256 internal constant DEGRADATION_COEFFICIENT = 10 ** 18;
```

## Errors

```solidity
error ConvexPoolShutdown();                        // Convex pool has been shut down
error InvalidCoinIndex();                          // Invalid coin index provided
error NotEnoughFundsToInvest();                    // Insufficient funds for investment
error InvalidZeroAddress();                        // Zero address provided
error CurveWithdrawAdminFeesFailed();             // Failed to withdraw admin fees
error InvalidHarvestedProfit();                    // Invalid profit amount reported
error MinOutputAmountNotReached();                 // Minimum output not achieved
error InvalidZeroAmount();                         // Zero amount provided
error MinExpectedBalanceAfterSwapNotReached();     // Minimum balance not reached after swap
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 amountDivested);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
event MinSwapCrvUpdated(uint256 newMinSwapCrv);
event MinSwapCvxUpdated(uint256 newMinSwapCvx);
event RouterUpdated(address newRouter);
```

## State Variables

```solidity
IConvexRewards public convexRewardPool;      // Main Convex reward contract
address public convexLpToken;                // Convex pool's LP token address
address public rewardToken;                  // Main reward token
uint256 public maxSingleTrade;              // Maximum size for a single trade
uint256 public minSwapCrv;                  // Minimum amount for CRV swaps
uint256 public minSwapCvx;                  // Minimum amount for CVX swaps
```

## Functions

### View Functions

### stakedBalance

```solidity
function stakedBalance() external view returns (uint256)
```

Returns the amount of Curve LP tokens staked in Convex.

Returns:

* The amount of staked LP tokens

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual returns (uint256)
```

Calculates estimated withdrawal amount including potential losses.

Parameters:

* `requestedAmount`: The amount of assets requested to withdraw

Returns:

* The expected liquidated amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view returns (uint256)
```

Calculates the amount needed to request for desired withdrawal amount.

Parameters:

* `liquidatedAmount`: The desired amount to receive

Returns:

* The amount that needs to be requested

### maxLiquidate

```solidity
function maxLiquidate() public view returns (uint256)
```

Returns maximum amount that can be withdrawn after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view returns (uint256)
```

Returns maximum amount that can be withdrawn before losses.

Returns:

* Maximum withdrawable amount before losses

### Configuration Functions

### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external
```

Sets maximum allowed size for a single trade.

Parameters:

* `_maxSingleTrade`: New maximum trade size

### setMinSwapCrv

```solidity
function setMinSwapCrv(uint256 _minSwapCrv) external
```

Sets minimum amount for CRV token swaps.

Parameters:

* `_minSwapCrv`: New minimum swap amount

### setMinSwapCvx

```solidity
function setMinSwapCvx(uint256 _minSwapCvx) external
```

Sets minimum amount for CVX token swaps.

Parameters:

* `_minSwapCvx`: New minimum swap amount

### Core Internal Functions

### \_prepareReturn

```solidity
function _prepareReturn(
    uint256 debtOutstanding,
    uint256 minExpectedBalance
) internal returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment)
```

Prepares strategy returns and handles profits/losses.

Parameters:

* `debtOutstanding`: Amount of debt to be repaid
* `minExpectedBalance`: Minimum balance expected after operations

Returns:

* `unrealizedProfit`: Unrealized profit amount
* `loss`: Loss amount
* `debtPayment`: Debt payment amount

### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal virtual
```

Adjusts strategy position with available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output after investment

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal virtual returns (uint256)
```

Invests assets into Convex pool.

Parameters:

* `amount`: Amount of assets to invest
* `minOutputAfterInvestment`: Minimum expected output

Returns:

* Amount of tokens received

### \_divest

```solidity
function _divest(uint256 amount) internal virtual returns (uint256)
```

Withdraws assets from Convex pool.

Parameters:

* `amount`: Amount of LP tokens to withdraw

Returns:

* Amount of underlying assets received

### Internal View Functions

### \_cvxBalance

```solidity
function _cvxBalance() internal view returns (uint256)
```

Returns CVX token balance of strategy.

Returns:

* CVX balance

### \_crvBalance

```solidity
function _crvBalance() internal view returns (uint256)
```

Returns CRV token balance of strategy.

Returns:

* CRV balance

### \_stakedBalance

```solidity
function _stakedBalance(IConvexRewards rewardPool) internal view returns (uint256)
```

Returns LP tokens staked in Convex.

Parameters:

* `rewardPool`: Convex reward pool address

Returns:

* Staked LP token amount

### \_lpValue

```solidity
function _lpValue(uint256 lp) internal view returns (uint256)
```

Calculates underlying value of LP tokens.

Parameters:

* `lp`: Amount of LP tokens

Returns:

* Underlying value

### \_lpForAmount

```solidity
function _lpForAmount(uint256 amount) internal view returns (uint256)
```

Calculates LP tokens needed for underlying amount.

Parameters:

* `amount`: Amount of underlying assets

Returns:

* Required LP tokens

### Abstract Functions

### \_lpPrice

```solidity
function _lpPrice() internal view virtual returns (uint256)
```

Returns estimated price of Convex LP token.

Returns:

* LP token price

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view returns (uint256)
```

Returns total value of strategy's assets.

Returns:

* Total assets value

### \_crv

```solidity
function _crv() internal pure virtual returns (address)
```

Returns CRV token address.

Returns:

* CRV token address

### \_cvx

```solidity
function _cvx() internal pure virtual returns (address)
```

Returns CVX token address.

Returns:

* CVX token address


# BaseConvexStrategyPolygon

## Overview

The BaseConvexStrategyPolygon contract serves as the foundation for Polygon-based strategies that interact with Convex protocols in the MaxAPY ecosystem. This contract provides core functionality for depositing assets, managing rewards, and handling withdrawals on Polygon network.

## Errors

```solidity
error ConvexPoolShutdown();                        // Convex pool has been shut down
error InvalidCoinIndex();                          // Invalid coin index provided
error NotEnoughFundsToInvest();                    // Insufficient funds for investment
error InvalidZeroAddress();                        // Zero address provided
error CurveWithdrawAdminFeesFailed();             // Failed to withdraw admin fees
error InvalidHarvestedProfit();                    // Invalid profit amount reported
error MinOutputAmountNotReached();                 // Minimum output not achieved
error InvalidZeroAmount();                         // Zero amount provided
error MinExpectedBalanceAfterSwapNotReached();     // Minimum balance not reached after swap
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 amountDivested);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
event MinSwapCrvUpdated(uint256 newMinSwapCrv);
event RouterUpdated(address newRouter);
```

## State Variables

```solidity
IConvexRewardsPolygon public convexRewardPool;    // Main Convex reward contract
address public convexLpToken;                      // Convex pool's LP token address
address public rewardToken;                        // Main reward token
uint256 public maxSingleTrade;                    // Maximum size for a single trade
uint256 public minSwapCrv;                        // Minimum amount for CRV swaps
```

## Functions

### View Functions

### stakedBalance

```solidity
function stakedBalance() external view returns (uint256)
```

Returns the amount of Curve LP tokens staked in Convex.

Returns:

* The amount of staked LP tokens

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual returns (uint256)
```

Calculates estimated withdrawal amount including potential losses.

Parameters:

* `requestedAmount`: The amount of assets requested to withdraw

Returns:

* The expected liquidated amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view returns (uint256)
```

Calculates the amount needed to request for desired withdrawal amount.

Parameters:

* `liquidatedAmount`: The desired amount to receive

Returns:

* The amount that needs to be requested

### maxLiquidate

```solidity
function maxLiquidate() public view returns (uint256)
```

Returns maximum amount that can be withdrawn after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view returns (uint256)
```

Returns maximum amount that can be withdrawn before losses.

Returns:

* Maximum withdrawable amount before losses

### Configuration Functions

### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external
```

Sets maximum allowed size for a single trade.

Parameters:

* `_maxSingleTrade`: New maximum trade size

### setMinSwapCrv

```solidity
function setMinSwapCrv(uint256 _minSwapCrv) external
```

Sets minimum amount for CRV token swaps.

Parameters:

* `_minSwapCrv`: New minimum swap amount

### Core Internal Functions

### \_prepareReturn

```solidity
function _prepareReturn(
    uint256 debtOutstanding,
    uint256 minExpectedBalance
) internal returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment)
```

Prepares strategy returns and handles profits/losses.

Parameters:

* `debtOutstanding`: Amount of debt to be repaid
* `minExpectedBalance`: Minimum balance expected after operations

Returns:

* `unrealizedProfit`: Unrealized profit amount
* `loss`: Loss amount
* `debtPayment`: Debt payment amount

### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal virtual
```

Adjusts strategy position with available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output after investment

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal virtual returns (uint256)
```

Invests assets into Convex pool.

Parameters:

* `amount`: Amount of assets to invest
* `minOutputAfterInvestment`: Minimum expected output

Returns:

* Amount of tokens received

### \_divest

```solidity
function _divest(uint256 amount) internal virtual returns (uint256)
```

Withdraws assets from Convex pool.

Parameters:

* `amount`: Amount of LP tokens to withdraw

Returns:

* Amount of underlying assets received

### Internal Helper Functions

### \_crvBalance

```solidity
function _crvBalance() internal view returns (uint256)
```

Returns CRV token balance of strategy.

Returns:

* CRV balance

### \_stakedBalance

```solidity
function _stakedBalance(IConvexRewardsPolygon rewardPool) internal view returns (uint256)
```

Returns LP tokens staked in Convex.

Parameters:

* `rewardPool`: Convex reward pool address

Returns:

* Staked LP token amount

### \_lpValue

```solidity
function _lpValue(uint256 lp) internal view returns (uint256)
```

Calculates underlying value of LP tokens.

Parameters:

* `lp`: Amount of LP tokens

Returns:

* Underlying value

### \_lpForAmount

```solidity
function _lpForAmount(uint256 amount) internal view returns (uint256)
```

Calculates LP tokens needed for underlying amount.

Parameters:

* `amount`: Amount of underlying assets

Returns:

* Required LP tokens

### Abstract Functions

### \_lpPrice

```solidity
function _lpPrice() internal view virtual returns (uint256)
```

Returns estimated price of Convex LP token.

Returns:

* LP token price

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view returns (uint256)
```

Returns total value of strategy's assets.

Returns:

* Total assets value

### \_crv

```solidity
function _crv() internal pure virtual returns (address)
```

Returns CRV token address.

Returns:

* CRV token address

### \_unwindRewards

```solidity
function _unwindRewards(IConvexRewardsPolygon rewardPool) internal virtual
```

Claims and processes rewards from Convex.

Parameters:

* `rewardPool`: Convex reward pool to claim from


# BaseBeefyStrategy

## Overview

The BaseBeefyStrategy contract serves as the foundation for strategies that interact with Beefy Finance protocols in the MaxAPY ecosystem. It provides core functionality for depositing assets into Beefy vaults, managing positions, and handling withdrawals.

## Errors

```solidity
error NotEnoughFundsToInvest();        // Insufficient funds for investment
error InvalidZeroAddress();             // Zero address provided
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 requestedShares, uint256 amountDivested);
event MinSingleTradeUpdated(uint256 minSingleTrade);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
```

## State Variables

```solidity
IBeefyVault public beefyVault;        // Beefy vault contract reference
uint256 public maxSingleTrade;        // Maximum size for a single trade
uint256 public minSingleTrade;        // Minimum size for a single trade
```

## Functions

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IBeefyVault _beefyVault
) public virtual initializer
```

Initializes the strategy with required parameters.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_beefyVault`: Beefy vault address

### Configuration Functions

### setMinSingleTrade

```solidity
function setMinSingleTrade(uint256 _minSingleTrade) external
```

Sets minimum trade size for the strategy.

Parameters:

* `_minSingleTrade`: New minimum trade size

### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external
```

Sets maximum trade size for the strategy.

Parameters:

* `_maxSingleTrade`: New maximum trade size

### View Functions

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view returns (uint256)
```

Calculates expected output for a withdrawal.

Parameters:

* `requestedAmount`: Amount requested to withdraw

Returns:

* Expected liquidated amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view returns (uint256)
```

Calculates input needed for desired withdrawal amount.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* Required input amount

### maxLiquidate

```solidity
function maxLiquidate() public view returns (uint256)
```

Returns maximum amount that can be withdrawn after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view returns (uint256)
```

Returns maximum amount that can be withdrawn before losses.

Returns:

* Maximum withdrawable amount before losses

### Internal Functions

### \_prepareReturn

```solidity
function _prepareReturn(
    uint256 debtOutstanding,
    uint256 minExpectedBalance
) internal returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment)
```

Prepares strategy returns and handles profits/losses.

Parameters:

* `debtOutstanding`: Outstanding debt amount
* `minExpectedBalance`: Minimum expected balance after operations

Returns:

* `unrealizedProfit`: Unrealized profit amount
* `loss`: Loss amount
* `debtPayment`: Debt payment amount

### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal virtual
```

Adjusts strategy position with available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output after investment

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal virtual returns (uint256)
```

Deposits assets into Beefy vault.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected output

Returns:

* Amount of tokens received

### \_divest

```solidity
function _divest(uint256 shares) internal virtual returns (uint256)
```

Withdraws assets from Beefy vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* Amount of underlying assets received

### \_liquidatePosition

```solidity
function _liquidatePosition(uint256 amountNeeded) internal returns (uint256 liquidatedAmount, uint256 loss)
```

Liquidates position to meet withdrawal request.

Parameters:

* `amountNeeded`: Amount requested to liquidate

Returns:

* `liquidatedAmount`: Amount actually liquidated
* `loss`: Any losses incurred

### Internal View Functions

### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view virtual returns (uint256)
```

Calculates underlying value of vault shares.

Parameters:

* `shares`: Amount of shares

Returns:

* Underlying asset value

### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view virtual returns (uint256)
```

Calculates shares needed for given amount.

Parameters:

* `amount`: Amount of underlying assets

Returns:

* Required shares amount

### \_shareBalance

```solidity
function _shareBalance() internal view returns (uint256)
```

Returns strategy's Beefy vault share balance.

Returns:

* Current share balance

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view returns (uint256)
```

Calculates total assets under management.

Returns:

* Total assets value


# BaseHopStrategy

## Overview

The BaseHopStrategy contract serves as the foundation for strategies that interact with Hop Protocol in the MaxAPY ecosystem. It handles deposits into Hop pools, managing LP positions, and executing withdrawals for cross-chain liquidity provision.

## Errors

```solidity
error NotEnoughFundsToInvest();            // Insufficient funds for investment
error InvalidZeroAddress();                 // Zero address provided
```

## Events

```solidity
event Invested(address indexed strategy, uint256 amountInvested);
event Divested(address indexed strategy, uint256 requestedShares, uint256 amountDivested);
event MinSingleTradeUpdated(uint256 minSingleTrade);
event MaxSingleTradeUpdated(uint256 maxSingleTrade);
```

## State Variables

```solidity
ISwap public hopPool;                // Hop exchange pool contract
ERC20Burnable public hopLPToken;     // Hop LP token contract
uint256 public maxSingleTrade;       // Maximum size for a single trade
uint256 public minSingleTrade;       // Minimum size for a single trade
```

## Functions

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ISwap _hopPool,
    ERC20Burnable _hopLPToken
) public virtual initializer
```

Initializes the strategy with Hop Protocol components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_hopPool`: Hop exchange pool address
* `_hopLPToken`: Hop LP token address

### Configuration Functions

### setMinSingleTrade

```solidity
function setMinSingleTrade(uint256 _minSingleTrade) external
```

Sets minimum trade size for the strategy.

Parameters:

* `_minSingleTrade`: New minimum trade size

### setMaxSingleTrade

```solidity
function setMaxSingleTrade(uint256 _maxSingleTrade) external
```

Sets maximum trade size for the strategy.

Parameters:

* `_maxSingleTrade`: New maximum trade size

### View Functions

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view returns (uint256)
```

Calculates expected output for a withdrawal.

Parameters:

* `requestedAmount`: Amount requested to withdraw

Returns:

* Expected liquidated amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view returns (uint256)
```

Calculates input needed for desired withdrawal amount.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* Required input amount

### maxLiquidate

```solidity
function maxLiquidate() public view returns (uint256)
```

Returns maximum amount that can be withdrawn after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view returns (uint256)
```

Returns maximum amount that can be withdrawn before losses.

Returns:

* Maximum withdrawable amount before losses

### Core Internal Functions

### \_prepareReturn

```solidity
function _prepareReturn(
    uint256 debtOutstanding,
    uint256 minExpectedBalance
) internal returns (uint256 unrealizedProfit, uint256 loss, uint256 debtPayment)
```

Prepares strategy returns and handles profits/losses.

Parameters:

* `debtOutstanding`: Outstanding debt amount
* `minExpectedBalance`: Minimum expected balance after operations

Returns:

* `unrealizedProfit`: Unrealized profit amount
* `loss`: Loss amount
* `debtPayment`: Debt payment amount

### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal virtual
```

Adjusts strategy position with available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output after investment

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal virtual returns (uint256)
```

Adds liquidity to Hop pool.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected LP tokens

Returns:

* Amount of LP tokens received

### \_divest

```solidity
function _divest(uint256 shares) internal virtual returns (uint256)
```

Removes liquidity from Hop pool.

Parameters:

* `shares`: Amount of LP tokens to withdraw

Returns:

* Amount of underlying assets received

### Internal View Functions

### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view virtual returns (uint256)
```

Calculates underlying value of LP tokens.

Parameters:

* `shares`: Amount of LP tokens

Returns:

* Underlying asset value

### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view virtual returns (uint256)
```

Calculates LP tokens needed for given amount.

Parameters:

* `amount`: Amount of underlying assets

Returns:

* Required LP tokens

### \_shareBalance

```solidity
function _shareBalance() internal view returns (uint256)
```

Returns strategy's Hop LP token balance.

Returns:

* Current LP token balance

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view returns (uint256)
```

Calculates total assets under management.

Returns:

* Total assets value


# BaseBeefyCurveStrategy

## Overview

The BaseBeefyCurveStrategy contract extends BaseBeefyStrategy to provide functionality for strategies that interact with both Beefy Finance and Curve protocols. It supplies underlying tokens into a Curve pool, then deposits the Curve LP tokens into a Beefy vault for additional yield.

## State Variables

```solidity
ICurveLpPool public curveLpPool;     // Main Curve pool for this strategy
```

## Functions

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICurveLpPool _curveLpPool,
    IBeefyVault _beefyVault
) public virtual initializer
```

Initializes the strategy with Curve and Beefy components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_curveLpPool`: Curve LP pool address
* `_beefyVault`: Beefy vault address

### Core Functions

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal virtual override returns (uint256)
```

Invests assets by adding liquidity to Curve and depositing LP tokens to Beefy.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected Beefy shares

Returns:

* Amount of Beefy shares received

### \_divest

```solidity
function _divest(uint256 amount) internal virtual override returns (uint256)
```

Withdraws assets from Beefy and removes liquidity from Curve.

Parameters:

* `amount`: Amount of Beefy shares to withdraw

Returns:

* Amount of underlying assets received

### View Functions

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual override returns (uint256)
```

Calculates expected output for withdrawal through both Beefy and Curve.

Parameters:

* `requestedAmount`: Amount requested to withdraw

Returns:

* Expected liquidated amount

### Internal View Functions

### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view virtual override returns (uint256)
```

Calculates underlying value of shares considering both Beefy and Curve conversion.

Parameters:

* `shares`: Amount of Beefy shares

Returns:

* Underlying asset value

### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view virtual override returns (uint256)
```

Calculates Beefy shares needed for given amount, considering Curve conversion.

Parameters:

* `amount`: Amount of underlying assets

Returns:

* Required Beefy shares

### \_lpPrice

```solidity
function _lpPrice() internal view returns (uint256)
```

Returns estimated price of Curve LP token.

Returns:

* LP token price


# Strategies


# Ethereum - WETH


# Convex


# ConvexdETHFrxETHStrategy

## Overview

The ConvexdETHFrxETHStrategy contract is a specialized strategy that supplies ETH into the dETH-frxETH pool in Curve, then stakes the curve LP tokens in Convex to maximize yield. It handles the complex interactions between Curve pools and Convex staking.

## Constants

```solidity
address public constant crv = CRV_MAINNET;             // Ethereum mainnet's CRV Token
address public constant cvx = CVX_MAINNET;             // Ethereum mainnet's CVX Token
address public constant frxETH = FRXETH_MAINNET;       // Ethereum mainnet's frxETH Token
uint256 public constant DETH_FRXETH_CONVEX_POOL_ID = CONVEX_DETH_FRXETH_CONVEX_POOL_ID_MAINNET;  // Convex pool identifier
```

## State Variables

```solidity
IConvexBooster public constant convexBooster;     // Main Convex's deposit contract
IRouter public router;                            // Router for CRV-WETH swaps
ICurveLpPool public constant cvxWethPool;        // CVX-WETH pool in Curve
ICurveLpPool public curveLpPool;                 // Main Curve pool for Strategy
ICurveLpPool public curveEthFrxEthPool;          // Curve's ETH-frxETH pool
```

## Functions

### Initialization Functions

#### constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICurveLpPool _curveLpPool,
    ICurveLpPool _curveEthFrxEthPool,
    IRouter _router
) public initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_curveLpPool`: Address of main Curve pool (dETH-frxETH)
* `_curveEthFrxEthPool`: Address of Curve's ETH-frxETH pool
* `_router`: Router address for swaps

### Configuration Functions

#### setRouter

```solidity
function setRouter(address _newRouter) external checkRoles(ADMIN_ROLE)
```

Updates the router used for token swaps.

Parameters:

* `_newRouter`: New router address

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256)
```

Invests ETH into the Convex pool through a series of steps:

1. Unwraps WETH
2. Swaps ETH for frxETH
3. Adds liquidity to dETH-frxETH pool
4. Stakes LP tokens in Convex

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected LP tokens Returns:
* Amount of tokens received in underlying terms

#### \_divest

```solidity
function _divest(uint256 amount) internal override returns (uint256)
```

Withdraws assets from Convex and Curve pools:

1. Withdraws from Convex
2. Removes liquidity from Curve
3. Swaps frxETH back to ETH
4. Wraps ETH to WETH

Parameters:

* `amount`: LP tokens to divest Returns:
* Amount of WETH received

#### \_unwindRewards

```solidity
function _unwindRewards(IConvexRewards rewardPool) internal override
```

Claims and converts reward tokens to underlying asset:

1. Claims CRV and CVX rewards
2. Swaps CRV for WETH
3. Swaps CVX for WETH

Parameters:

* `rewardPool`: Convex rewards pool to claim from

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual override returns (uint256)
```

Simulates withdrawal including potential losses.

Parameters:

* `requestedAmount`: Amount to withdraw Returns:
* Expected output amount after losses

### Internal View Functions

#### \_lpPrice

```solidity
function _lpPrice() internal view override returns (uint256)
```

Calculates the estimated price for the strategy's Convex LP token.

Returns:

* Estimated LP token price

#### \_crv

```solidity
function _crv() internal pure override returns (address)
```

Returns the CRV token address.

Returns:

* CRV token address

#### \_cvx

```solidity
function _cvx() internal pure override returns (address)
```

Returns the CVX token address.

Returns:

* CVX token address

### Receive Function

```solidity
receive() external payable
```

Enables the contract to receive ETH.

### Simulation Functions

#### \_simulateHarvest

```solidity
function _simulateHarvest() public override
```

Internal simulation function that calculates expected outcomes of harvesting operations including:

1. Investment/divestment amounts
2. Profit/loss calculations
3. Debt management
4. Balance changes


# Sommelier


# SommelierMorphoEthMaximizerStrategy

## Overview

The SommelierMorphoEthMaximizerStrategy contract is a specialized strategy that supplies an underlying token into a Sommelier Vault to earn yield. This strategy is adapted from the yearn-steth-acc repository and optimizes ETH returns through Morpho integration.

## Constants

```solidity
address constant wstEth = WSTETH_MAINNET;                                      // Wrapped stETH token address
IUniswapV3Router constant router = IUniswapV3Router(UNISWAP_V3_ROUTER_MAINNET); // Uniswap V3 router
```

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICellar _cellar
) public override initializer
```

Initializes the strategy with Sommelier components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_cellar`: Sommelier Turbo-stETH cellar address

### Core Functions

### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external virtual override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exactly amountNeeded to vault. Can only be called by vault.

Parameters:

* `amountNeeded`: Amount of underlying asset to withdraw

Returns:

* `loss`: Amount of loss realized during withdrawal

### Internal Core Functions

### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets from Cellar Vault, handling potential losses.

Parameters:

* `shares`: Amount of cellar shares to divest

Returns:

* `withdrawn`: Amount of assets received after withdrawal

### \_swapWstEth

```solidity
function _swapWstEth(uint256 amountIn) internal returns (uint256)
```

Swaps wstETH to underlying WETH using Uniswap V3.

Parameters:

* `amountIn`: Amount of wstETH to swap

Returns:

* Amount of WETH received

### Internal View Functions

### \_wstEthBalance

```solidity
function _wstEthBalance() internal view returns (uint256)
```

Retrieves the contract's wstETH balance.

Returns:

* Current wstETH balance

### Key Features

1. Integrates with Sommelier's Turbo-stETH cellar for yield optimization
2. Handles wstETH/ETH conversions through Uniswap V3
3. Implements safety checks for pause conditions and minimum trade sizes
4. Manages exact liquidations for vault withdrawals
5. Monitors and handles potential losses during withdrawals


# SommelierStEthDepositTurboStEthStrategy

## Overview

The SommelierStEthDepositTurboStEthStrategy contract is a specialized strategy that supplies an underlying token into a generic Sommelier Vault to earn yield. It handles conversions between ETH and stETH using Curve pools.

## Constants

```solidity
address public constant stEth = STETH_MAINNET;                                      // Ethereum mainnet's StETH Token
ICurveLpPool public constant pool = ICurveLpPool(CURVE_ETH_STETH_POOL_MAINNET);    // Curve ETH-stETH pool
```

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

### Constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICellar _cellar
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_cellar`: Sommelier Turbo-stETH cellar address

### Core Functions

### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exactly amountNeeded to vault.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### View Functions

### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view override returns (uint256 liquidatedAmount)
```

Simulates withdrawal including potential losses.

Parameters:

* `requestedAmount`: Amount requested to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view override returns (uint256 requestedAmount)
```

Calculates required input for exact output.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

### maxLiquidate

```solidity
function maxLiquidate() public view override returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view override returns (uint256)
```

Returns maximum withdrawable amount before losses.

Returns:

* Maximum withdrawable amount before losses

### Internal Core Functions

### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal override
```

Adjusts strategy positions based on available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets into Cellar Vault through stETH conversion.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets from Cellar Vault and converts back to ETH.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Receive Function

```solidity
receive() external payable
```

Allows contract to receive native ETH.


# SommelierTurboDivEthStrategy

## Overview

The SommelierTurboDivEthStrategy contract is a specialized strategy that supplies tokens into a Sommelier Vault while managing liquidity through Balancer pools. It handles conversions between ETH and rETH using Balancer's stable pools.

## Constants

```solidity
address public constant rEth = RETH_MAINNET;                                       // Ethereum mainnet's rETH Token
address public constant balancerLpPool = 0x1E19CF2D73a72Ef1332C882F20534B6519Be0276;  // Balancer rETH-WETH pool
bytes32 public constant balancerPoolId = 0x1e19cf2d73a72ef1332c882f20534b6519be0276000200000000000000000112;  // Pool ID
IBalancerVault public constant balancerVault = IBalancerVault(BALANCER_VAULT_MAINNET);  // Balancer Vault
```

## Functions

### Constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

### Initialization Functions

### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICellar _cellar
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_cellar`: Sommelier cellar address

### Core Functions

### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exactly amountNeeded to vault.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### View Functions

### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view override returns (uint256 requestedAmount)
```

Calculates input needed for exact output.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

### maxLiquidate

```solidity
function maxLiquidate() public view override returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

### maxLiquidateExact

```solidity
function maxLiquidateExact() public view override returns (uint256)
```

Returns maximum withdrawable amount before losses.

Returns:

* Maximum withdrawable amount before losses

### Internal Core Functions

### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets in Cellar Vault through Balancer.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets from Cellar Vault through Balancer.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### \_liquidatePosition

```solidity
function _liquidatePosition(uint256 amountNeeded) internal override returns (uint256 liquidatedAmount, uint256 loss)
```

Liquidates position up to requested amount.

Parameters:

* `amountNeeded`: Amount to liquidate

Returns:

* `liquidatedAmount`: Amount actually liquidated
* `loss`: Amount of losses incurred

### Internal View Functions

### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256 _assets)
```

Calculates underlying value of shares.

Parameters:

* `shares`: Amount of shares

Returns:

* `_assets`: Asset value

### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 _shares)
```

Calculates shares needed for amount.

Parameters:

* `amount`: Amount of assets

Returns:

* `_shares`: Required shares

### \_shareBalance

```solidity
function _shareBalance() internal view override returns (uint256 _balance)
```

Returns strategy's Cellar share balance.

Returns:

* Current share balance

### \_lpValue

```solidity
function _lpValue(uint256 amount) internal view returns (uint256)
```

Calculates value of LP tokens.

Parameters:

* `amount`: LP token amount

Returns:

* Underlying value

### \_lpPrice

```solidity
function _lpPrice() internal view returns (uint256)
```

Returns Balancer LP token price.

Returns:

* LP token price

### \_lpBalance

```solidity
function _lpBalance() internal view returns (uint256)
```

Returns Balancer LP token balance.

Returns:

* LP token balance

### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view virtual override returns (uint256)
```

Calculates total assets under management.

Returns:

* Total assets value

### \_getAssets

```solidity
function _getAssets() internal view returns (IAsset[] memory)
```

Returns ordered array of pool assets.

Returns:

* Array of pool assets

### Internal Helper Functions

### \_joinPool

```solidity
function _joinPool(uint256 _wethIn) internal returns (uint256)
```

Adds single-sided liquidity to Balancer pool.

Parameters:

* `_wethIn`: Amount of WETH to add

Returns:

* Amount of LP tokens minted

### \_exitPool

```solidity
function _exitPool(uint256 _lpTokens) internal returns (uint256)
```

Removes liquidity from Balancer pool.

Parameters:

* `_lpTokens`: Amount of LP tokens to remove

Returns:

* Amount of WETH received


# SommelierTurboEEthV2Strategy

## Overview

The SommelierTurboEEthV2Strategy contract is a simple pass-through strategy that inherits directly from BaseSommelierStrategy with no additional functionality. It supplies underlying tokens into a Sommelier Vault to earn yield, using all the base functionality provided by BaseSommelierStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

All functionality is inherited from BaseSommelierStrategy with no overrides or additional functions.


# SommelierTurboEthXStrategy

## Overview

The SommelierTurboEthXStrategy contract is a strategy that supplies an underlying token into a Sommelier Vault to earn yield, with specific handling for ethX token conversions through Uniswap V3.

## Constants

```solidity
address constant ethX = ETHX_MAINNET;                                             // EthX token address
IUniswapV3Router constant router = IUniswapV3Router(UNISWAP_V3_ROUTER_MAINNET);  // Uniswap V3 router
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICellar _cellar
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_cellar`: Sommelier cellar address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external virtual override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exactly amountNeeded to vault.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### Internal Core Functions

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets from Cellar Vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

#### \_swapEthX

```solidity
function _swapEthX(uint256 amountIn) internal returns (uint256)
```

Swaps ethX tokens to underlying WETH using Uniswap V3.

Parameters:

* `amountIn`: Amount of ethX to swap

Returns:

* Amount of WETH received

### Internal View Functions

#### \_ethXBalance

```solidity
function _ethXBalance() internal view returns (uint256)
```

Returns the contract's ethX balance.

Returns:

* Current ethX balance


# SommelierTurboEzEthStrategy

## Overview

The SommelierTurboEzEthStrategy contract is a simple pass-through strategy that inherits directly from BaseSommelierStrategy with no additional functionality. It supplies underlying tokens into a Sommelier Vault to earn yield, using all the base functionality provided by BaseSommelierStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

All functionality is inherited from BaseSommelierStrategy with no overrides or additional functions.


# SommelierTurboRsEthStrategy

## Overview

The SommelierTurboRsEthStrategy contract is a simple pass-through strategy that inherits directly from BaseSommelierStrategy with no additional functionality. It supplies underlying tokens into a Sommelier Vault to earn yield, using all the base functionality provided by BaseSommelierStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

All functionality is inherited from BaseSommelierStrategy with no overrides or additional functions.


# SommelierTurboStEthStrategy

## Overview

The SommelierTurboStEthStrategy contract is a simple pass-through strategy that inherits directly from BaseSommelierStrategy with no additional functionality. It supplies underlying tokens into a Sommelier Vault to earn yield, using all the base functionality provided by BaseSommelierStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

All functionality is inherited from BaseSommelierStrategy with no overrides or additional functions.


# SommelierTurboSwEthStrategy

## Overview

The SommelierTurboSwEthStrategy contract is a simple pass-through strategy that inherits directly from BaseSommelierStrategy with no additional functionality. It supplies underlying tokens into a Sommelier Vault to earn yield, using all the base functionality provided by BaseSommelierStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseSommelierStrategy.

## Functions

All functionality is inherited from BaseSommelierStrategy with no overrides or additional functions.


# Yearn


# YearnAaveV3WETHLenderStrategy

## Overview

The YearnAaveV3WETHLenderStrategy contract is a strategy that supplies WETH into a Yearn Vault to earn yield. It inherits from BaseYearnV3Strategy and provides specific initialization for Yearn's Aave V3 WETH lending vault.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components and sets up unlimited trading amounts.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnAjnaWETHStakingStrategy

## Overview

The YearnAjnaWETHStakingStrategy contract is a strategy that supplies WETH into a Yearn V3 Vault and stakes the vault shares to earn additional AJNA rewards. It manages the conversion of AJNA rewards back to WETH through Uniswap V3.

## Constants

```solidity
address public constant ajna = AJNA_MAINNET;                                   // AJNA token address
IRouter public constant router = IRouter(UNISWAP_V3_ROUTER_MAINNET);          // Uniswap V3 router
IStakingRewardsMulti public constant yearnStakingRewards =                    // Yearn staking rewards contract
    IStakingRewardsMulti(0x0Ed535037c013c3628512980C169Ed59Eb805B49);
```

## State Variables

```solidity
uint256 public minSwapAjna;    // Minimum amount of AJNA to swap
```

## Functions

### Constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount to vault and re-stakes any remaining shares.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### Internal Core Functions

#### \_beforePrepareReturn

```solidity
function _beforePrepareReturn() internal override
```

Claims and processes staking rewards before preparing return.

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets and stakes the received shares.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Unstakes and withdraws assets from vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

#### \_liquidatePosition

```solidity
function _liquidatePosition(uint256 amountNeeded) internal override returns (uint256 liquidatedAmount, uint256 loss)
```

Liquidates position up to requested amount.

Parameters:

* `amountNeeded`: Amount to liquidate

Returns:

* `liquidatedAmount`: Amount actually liquidated
* `loss`: Amount of losses incurred

#### \_unwindRewards

```solidity
function _unwindRewards(IStakingRewardsMulti _yearnStakingRewards) internal
```

Claims AJNA rewards and converts them to WETH.

Parameters:

* `_yearnStakingRewards`: Staking rewards contract

### Internal View Functions

#### \_ajnaBalance

```solidity
function _ajnaBalance() internal view returns (uint256)
```

Returns strategy's AJNA token balance.

Returns:

* Current AJNA balance

#### \_shareBalance

```solidity
function _shareBalance() internal view override returns (uint256 _balance)
```

Returns strategy's staked vault share balance.

Returns:

* Current staked share balance


# YearnCompoundV3WETHLenderStrategy

## Overview

The YearnCompoundV3WETHLenderStrategy contract is a strategy that supplies WETH into a Yearn Vault to earn yield. It inherits from BaseYearnV3Strategy and provides specific initialization for Yearn's Compound V3 WETH lending vault.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components and sets up unlimited trading amounts.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnV3WETH2Strategy

## Overview

The YearnV3WETH2Strategy contract is a strategy that supplies WETH into a Yearn V3 Vault to earn yield. It inherits from BaseYearnV3Strategy and provides specific initialization for Yearn's V3 WETH vault.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components and sets up unlimited trading amounts.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy

All other functionality is inherited from BaseYearnV3Strategy with no overrides or additional functions.


# YearnV3WETHStrategy

## Overview

The YearnV3WETHStrategy contract is a strategy that supplies WETH into a Yearn V3 Vault to earn yield. It inherits from BaseYearnV3Strategy and provides specific initialization for Yearn's V3 WETH vault.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components and sets up unlimited trading amounts.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnWETHStrategy

## Overview

The YearnWETHStrategy contract is a strategy that supplies WETH into a Yearn V2 Vault to earn yield. It inherits from BaseYearnV2Strategy and provides specific initialization for Yearn's V2 WETH vault.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV2Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVault _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V2 components and sets up trading limits.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V2 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets minimum trade size to 0.01 tokens
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV2Strategy


# Ethereum - USDC


# Convex


# ConvexCrvUSDWethCollateralStrategy

## Overview

The ConvexCrvUSDWethCollateralStrategy contract is a sophisticated strategy that supplies CrvUSD into the CrvUSD(WETH Collateral) lending pool in Curve, then stakes the curve LP tokens in Convex to maximize yield. It manages multiple token conversions and interactions between Curve lending pools and Convex staking.

## Constants

```solidity
address public constant weth = WETH_MAINNET;                   // WETH token address
address public constant crv = CRV_MAINNET;                     // CRV token address
address public constant cvx = CVX_MAINNET;                     // CVX token address
address public constant crvUsd = CRVUSD_MAINNET;              // crvUSD token address
uint256 public constant CRVUSD_WETH_COLLATERAL_POOL_ID = CONVEX_CRVUSD_WETH_COLLATERAL_POOL_ID_MAINNET;  // Convex pool ID
IRouter public constant router = IRouter(UNISWAP_V3_ROUTER_MAINNET);  // Uniswap V3 router
IConvexBooster public constant convexBooster = IConvexBooster(CONVEX_BOOSTER_MAINNET);  // Convex booster
```

## State Variables

```solidity
ICurveLendingPool public curveLendingPool;      // Main Curve lending pool
ICurveLpPool public curveUsdcCrvUsdPool;        // Curve's USDC-crvUSD pool
```

## Functions

### Initialization Functions

#### constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICurveLendingPool _curveLendingPool,
    ICurveLpPool _curveUsdcCrvUsdPool
) public initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_curveLendingPool`: Curve lending pool address
* `_curveUsdcCrvUsdPool`: Curve USDC-crvUSD pool address

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256)
```

Invests assets through multiple steps:

1. Swaps USDC for crvUSD
2. Adds liquidity to lending pool
3. Stakes LP tokens in Convex

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected LP tokens

Returns:

* Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 amount) internal override returns (uint256)
```

Withdraws assets through multiple steps:

1. Withdraws from Convex
2. Removes liquidity from lending pool
3. Swaps crvUSD for USDC

Parameters:

* `amount`: Amount of LP tokens to divest

Returns:

* Amount of USDC received

#### \_unwindRewards

```solidity
function _unwindRewards(IConvexRewards rewardPool) internal override
```

Claims and converts rewards to underlying:

1. Claims CRV and CVX rewards
2. Swaps CVX for CRV
3. Swaps CRV for USDC through WETH

Parameters:

* `rewardPool`: Convex rewards pool

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual override returns (uint256)
```

Simulates withdrawal including losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* Expected output amount

### Internal View Functions

#### \_lpValue

```solidity
function _lpValue(uint256 lp) internal view override returns (uint256)
```

Calculates underlying value of LP tokens.

Parameters:

* `lp`: Amount of LP tokens

Returns:

* Underlying value

#### \_lpForAmount

```solidity
function _lpForAmount(uint256 amount) internal view override returns (uint256)
```

Calculates LP tokens needed for given amount.

Parameters:

* `amount`: Amount of underlying

Returns:

* Required LP tokens

#### \_lpPrice

```solidity
function _lpPrice() internal view override returns (uint256)
```

Empty implementation for LP price.

#### \_crv

```solidity
function _crv() internal pure override returns (address)
```

Returns CRV token address.

#### \_cvx

```solidity
function _cvx() internal pure override returns (address)
```

Returns CVX token address.

#### \_simulateHarvest

```solidity
function _simulateHarvest() public override
```

Simulates harvest operation with detailed result reporting.


# Sommelier


# SommelierTurboGHOStrategy

## Overview

The SommelierTurboGHOStrategy contract is a strategy that supplies tokens into a Sommelier Vault to earn yield, with specific handling for GHO token conversions through Uniswap V3.

## Constants

```solidity
address constant gho = GHO_MAINNET;                                            // GHO token address
IUniswapV3Router constant router = IUniswapV3Router(UNISWAP_V3_ROUTER_MAINNET);  // Uniswap V3 router
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICellar _cellar
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_cellar`: Sommelier cellar address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external virtual override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exactly amountNeeded to vault.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### Internal Core Functions

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets from Cellar Vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

#### \_swapGho

```solidity
function _swapGho(uint256 amountIn) internal returns (uint256)
```

Swaps GHO tokens to underlying using Uniswap V3.

Parameters:

* `amountIn`: Amount of GHO to swap

Returns:

* Amount received after swap

### Internal View Functions

#### \_ghoBalance

```solidity
function _ghoBalance() internal view returns (uint256)
```

Returns the contract's GHO balance.

Returns:

* Current GHO balance


# Yearn


# YearnAjnaDAIStakingStrategy

## Overview

The YearnAjnaDAIStakingStrategy contract is a strategy that supplies DAI into a Yearn V3 Vault and stakes the vault shares to earn additional AJNA rewards. It manages token conversions through Curve's 3pool and Uniswap V3.

## Constants

```solidity
address public constant ajna = AJNA_MAINNET;                                      // AJNA token address
address public constant weth = WETH_MAINNET;                                      // WETH token address
address public constant dai = DAI_MAINNET;                                        // DAI token address
IRouter public constant router = IRouter(UNISWAP_V3_ROUTER_MAINNET);             // Uniswap V3 router
ICurveTriPool public constant triPool = ICurveTriPool(CURVE_3POOL_POOL_MAINNET); // Curve 3pool
IStakingRewardsMulti public constant yearnStakingRewards =                       // Yearn staking rewards
    IStakingRewardsMulti(0x54C6b2b293297e65b1d163C3E8dbc45338bfE443);
```

## State Variables

```solidity
uint256 public minSwapAjna;    // Minimum amount of AJNA to swap
```

## Functions

### Constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount to vault and re-stakes any remaining shares.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

#### maxLiquidateExact

```solidity
function maxLiquidateExact() public view virtual override returns (uint256)
```

Returns maximum withdrawable amount before losses.

Returns:

* Maximum withdrawable amount

### Internal Core Functions

#### \_beforePrepareReturn

```solidity
function _beforePrepareReturn() internal override
```

Claims and processes staking rewards before preparing return.

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by swapping to DAI and staking in Yearn.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Unstakes and withdraws assets, converting back to underlying.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

#### \_liquidatePosition

```solidity
function _liquidatePosition(uint256 amountNeeded) internal override returns (uint256 liquidatedAmount, uint256 loss)
```

Liquidates position up to requested amount.

Parameters:

* `amountNeeded`: Amount to liquidate

Returns:

* `liquidatedAmount`: Amount actually liquidated
* `loss`: Amount of losses incurred

#### \_liquidateAllPositions

```solidity
function _liquidateAllPositions() internal override returns (uint256 amountFreed)
```

Liquidates all positions during emergency exit.

Returns:

* `amountFreed`: Amount freed

#### \_unwindRewards

```solidity
function _unwindRewards(IStakingRewardsMulti _yearnStakingRewards) internal
```

Claims AJNA rewards and converts them to underlying.

Parameters:

* `_yearnStakingRewards`: Staking rewards contract

### Internal View Functions

#### \_ajnaBalance

```solidity
function _ajnaBalance() internal view returns (uint256)
```

Returns strategy's AJNA token balance.

Returns:

* Current AJNA balance

#### \_shareBalance

```solidity
function _shareBalance() internal view override returns (uint256 _balance)
```

Returns strategy's staked vault share balance.

Returns:

* Current staked share balance

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256)
```

Calculates underlying value of shares including conversion rates.

Parameters:

* `shares`: Share amount

Returns:

* Underlying value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 shares)
```

Calculates shares needed for amount including conversion rates.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares


# YearnDAIStrategy

## Overview

The YearnDAIStrategy contract is a strategy that supplies DAI into a Yearn V2 Vault to earn yield. It handles conversions between the underlying asset and DAI through Curve's 3pool.

## Constants

```solidity
ICurveTriPool public constant triPool = ICurveTriPool(CURVE_3POOL_POOL_MAINNET);  // Curve's 3pool
address constant dai = DAI_MAINNET;                                                // DAI token address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVault _yVault
) public virtual override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V2 vault address

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Swapping underlying to DAI through Curve
2. Depositing DAI into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Withdrawing DAI from Yearn vault
2. Swapping DAI to underlying through Curve

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256)
```

Calculates underlying value of shares including Curve conversion rate.

Parameters:

* `shares`: Share amount

Returns:

* Underlying value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 shares)
```

Calculates shares needed for amount including Curve conversion rate.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

Key Features:

* Uses Curve's 3pool for token conversions
* Sets 1M DAI maximum trade size
* Sets minimum trade size to 0.01 token units
* Handles token conversions during deposits and withdrawals


# YearnLUSDStrategy

## Overview

The YearnLUSDStrategy contract is a strategy that supplies LUSD into a Yearn V2 Vault to earn yield. It handles conversions between USDC and LUSD through Uniswap V3, using TWAP oracles for price calculations.

## Constants

```solidity
address public constant lusd = LUSD_MAINNET;                                  // LUSD token address
IRouter public constant router = IRouter(UNISWAP_V3_ROUTER_MAINNET);         // Uniswap V3 router
address public constant pool = UNISWAP_V3_USDC_LUSD_POOL_MAINNET;           // USDC-LUSD pool address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVault _yVault
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V2 vault address

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual override returns (uint256 liquidatedAmount)
```

Simulates withdrawal with 1% safety margin.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view virtual override returns (uint256 requestedAmount)
```

Calculates input needed with 1% buffer.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Swapping USDC to LUSD
2. Depositing LUSD into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Withdrawing LUSD from Yearn vault
2. Swapping LUSD to USDC

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256)
```

Calculates underlying value using TWAP oracle.

Parameters:

* `shares`: Share amount

Returns:

* Underlying value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 shares)
```

Calculates shares needed using TWAP oracle.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

#### \_lusdBalance

```solidity
function _lusdBalance() internal view returns (uint256)
```

Returns strategy's LUSD balance.

Returns:

* Current LUSD balance

#### \_estimateAmountOut

```solidity
function _estimateAmountOut(
    address tokenIn,
    address tokenOut,
    uint128 amountIn,
    uint32 secondsAgo
) internal view returns (uint256 amountOut)
```

Estimates swap output using Uniswap V3 TWAP.

Parameters:

* `tokenIn`: Input token address
* `tokenOut`: Output token address
* `amountIn`: Input amount
* `secondsAgo`: TWAP interval in seconds

Returns:

* Estimated output amount


# YearnUSDCStrategy

## Overview

The YearnUSDCStrategy contract is a simple pass-through strategy that supplies USDC directly into a Yearn V2 Vault to earn yield. It inherits from BaseYearnV2Strategy with minimal customization for USDC handling.

## Constants

No additional constants defined in this contract.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVault _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V2 components and sets up trading limits.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V2 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets minimum trade size to 0.01 USDC
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV2Strategy


# YearnUSDTStrategy

## Overview

The YearnUSDTStrategy contract is a strategy that supplies USDT into a Yearn V2 Vault to earn yield. It handles conversions between the underlying asset and USDT through Curve's 3pool and includes safety margins for liquidations.

## Constants

```solidity
ICurveTriPool public constant triPool = ICurveTriPool(CURVE_3POOL_POOL_MAINNET);  // Curve's 3pool
address constant usdt = USDT_MAINNET;                                              // USDT token address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVault _yVault
) public virtual override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V2 vault address

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view override returns (uint256 liquidatedAmount)
```

Simulates withdrawal with 1% safety margin.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view virtual override returns (uint256 requestedAmount)
```

Calculates input needed with 2% buffer.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Swapping underlying to USDT through Curve
2. Depositing USDT into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Withdrawing USDT from Yearn vault
2. Swapping USDT to underlying through Curve

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256)
```

Calculates underlying value including Curve conversion.

Parameters:

* `shares`: Share amount

Returns:

* Underlying value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 shares)
```

Calculates shares needed including Curve conversion.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

Key Features:

* Uses Curve's 3pool for token conversions
* Sets 1M USD maximum trade size
* Sets minimum trade size to 0.01 token units
* Includes safety margins for withdrawals
* Handles conversions between USDT and underlying asset


# Polygon - WETH


# Hop


# HopETHStrategy

## Overview

The HopETHStrategy contract is a simple pass-through strategy that inherits directly from BaseHopStrategy with no additional functionality. It supplies ETH into a Hop Protocol liquidity pool to earn yield, using all the base functionality provided by BaseHopStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseHopStrategy.

## Functions

All functionality is inherited from BaseHopStrategy with no overrides or additional functions.


# Polygon - USDC.e


# Convex


# ConvexUSDCCrvUSDStrategy

## Overview

The ConvexUSDCCrvUSDStrategy contract is a strategy that supplies USDC into the crvUSD-USDC pool in Curve on Polygon, then stakes the curve LP tokens in Convex to maximize yield. It handles multiple token conversions and uses TWAP oracles for price calculations.

## Constants

```solidity
address public constant crvUsd = CRV_USD_POLYGON;                                 // CRVUSD token address
address public constant wpol = WPOL_POLYGON;                                      // Wrapped MATIC address
address public constant crv = CRV_POLYGON;                                        // CRV token address
address public constant usdc = USDC_POLYGON;                                      // USDC token address
uint256 public constant CRVUSD_USDC_CONVEX_POOL_ID = CRVUSD_USDC_CONVEX_POOL_ID_POLYGON;  // Convex pool ID
address public constant pool = UNISWAP_V3_USDC_USDCE_POOL_POLYGON;              // Uniswap V3 pool
address public constant triCryptoPool = TRI_CRYPTO_POOL_POLYGON;                 // CrvTricrypto pool
```

## State Variables

```solidity
IRouter public router;                           // Router for swaps
ICurveLpPool public curveLpPool;                // Main Curve pool
IConvexBoosterPolygon public constant convexBooster = IConvexBoosterPolygon(CONVEX_BOOSTER_POLYGON);  // Convex booster
ICurveAtriCryptoZapper public constant zapper = ICurveAtriCryptoZapper(CURVE_CRV_ATRICRYPTO_ZAPPER_POLYGON);  // Curve zapper
```

## Functions

### Initialization Functions

#### constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICurveLpPool _curveLpPool,
    IRouter _router
) public initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_curveLpPool`: Curve LP pool address
* `_router`: Router address for swaps

### Configuration Functions

#### setRouter

```solidity
function setRouter(address _newRouter) external checkRoles(ADMIN_ROLE)
```

Updates the router used for token swaps.

Parameters:

* `_newRouter`: New router address

### Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256)
```

Invests assets through:

1. Swapping base asset to USDC
2. Adding liquidity to crvUSD-USDC pool
3. Staking LP tokens in Convex

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected LP tokens

Returns:

* Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 amount) internal override returns (uint256)
```

Withdraws assets through:

1. Withdrawing from Convex
2. Removing liquidity from Curve
3. Swapping USDC to base asset

Parameters:

* `amount`: LP tokens to divest

Returns:

* Amount received after withdrawals and swaps

#### \_unwindRewards

```solidity
function _unwindRewards(IConvexRewardsPolygon rewardPool) internal override
```

Claims and converts rewards:

1. Claims CRV rewards
2. Swaps CRV through TriCrypto pool
3. Swaps crvUSD through multiple hops

Parameters:

* `rewardPool`: Convex rewards pool

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view virtual override returns (uint256)
```

Simulates withdrawal including potential losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* Expected output amount

### Internal View Functions

#### \_lpValue

```solidity
function _lpValue(uint256 lp) internal view override returns (uint256)
```

Calculates underlying value of LP tokens using TWAP.

Parameters:

* `lp`: LP token amount

Returns:

* Underlying value

#### \_lpForAmount

```solidity
function _lpForAmount(uint256 amount) internal view override returns (uint256)
```

Calculates LP tokens needed for amount using TWAP.

Parameters:

* `amount`: Asset amount

Returns:

* Required LP tokens

#### \_lpPrice

```solidity
function _lpPrice() internal view override returns (uint256)
```

Calculates LP token price.

Returns:

* LP token price

#### \_estimateAmountOut

```solidity
function _estimateAmountOut(address tokenIn, address tokenOut, uint128 amountIn, uint32 secondsAgo) internal view returns (uint256)
```

Calculates swap output using TWAP oracle.

Parameters:

* `tokenIn`: Input token
* `tokenOut`: Output token
* `amountIn`: Input amount
* `secondsAgo`: TWAP period

Returns:

* Estimated output amount

#### \_crv

```solidity
function _crv() internal pure override returns (address)
```

Returns CRV token address.

#### \_crvUsdBalance

```solidity
function _crvUsdBalance() internal view returns (uint256)
```

Returns strategy's crvUSD balance.

#### \_simulateHarvest

```solidity
function _simulateHarvest() public override
```

Simulates harvest operation and reverts with simulation data.


# ConvexUSDTCrvUSDStrategy

## Overview

The ConvexUSDTCrvUSDStrategy contract is a strategy that supplies USDT into the crvUSD-USDT pool in Curve on Polygon, then stakes the curve LP tokens in Convex to maximize yield. It manages conversions between USDT and other tokens using Curve's AtriCrypto zapper.

## Constants

```solidity
address public constant crvUsd = CRV_USD_POLYGON;                                 // CRVUSD token address
address public constant wpol = WPOL_POLYGON;                                      // Wrapped MATIC address
address public constant crv = CRV_POLYGON;                                        // CRV token address
address public constant usdt = USDT_POLYGON;                                      // USDT token address
uint256 public constant CRVUSD_USDT_CONVEX_POOL_ID = CRVUSD_USDT_CONVEX_POOL_ID_POLYGON;  // Convex pool ID
IConvexBoosterPolygon public constant convexBooster = IConvexBoosterPolygon(CONVEX_BOOSTER_POLYGON);  // Convex booster
ICurveAtriCryptoZapper constant zapper = ICurveAtriCryptoZapper(CURVE_AAVE_ATRICRYPTO_ZAPPER_POLYGON);  // Curve zapper
```

## State Variables

```solidity
IRouter public router;                           // Router for swaps
ICurveLpPool public curveLpPool;                // Main Curve pool
```

## Functions

### Initialization Functions

#### constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    ICurveLpPool _curveLpPool,
    IRouter _router
) public initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_curveLpPool`: Curve LP pool address
* `_router`: Router address for swaps

### Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256)
```

Invests assets through:

1. Converting USDCe to USDT via zapper
2. Adding USDT to crvUSD-USDT pool
3. Staking LP tokens in Convex

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected LP tokens

Returns:

* Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 amount) internal override returns (uint256)
```

Withdraws assets through:

1. Withdrawing from Convex
2. Removing liquidity from Curve
3. Converting USDT to USDCe via zapper

Parameters:

* `amount`: LP tokens to divest

Returns:

* Amount received after withdrawals and conversions

#### \_unwindRewards

```solidity
function _unwindRewards(IConvexRewardsPolygon rewardPool) internal override
```

Claims and converts rewards:

1. Claims CRV rewards
2. Swaps CRV through multiple hops
3. Converts crvUSD through Curve pool

Parameters:

* `rewardPool`: Convex rewards pool

### Internal View Functions

#### \_convertUsdtToUsdce

```solidity
function _convertUsdtToUsdce(uint256 usdtAmount) internal view returns (uint256)
```

Converts USDT to USDCe using zapper.

Parameters:

* `usdtAmount`: USDT amount

Returns:

* Equivalent USDCe amount

#### \_convertUsdceToUsdt

```solidity
function _convertUsdceToUsdt(uint256 usdceAmount) internal view returns (uint256)
```

Converts USDCe to USDT using zapper.

Parameters:

* `usdceAmount`: USDCe amount

Returns:

* Equivalent USDT amount

#### \_lpValue

```solidity
function _lpValue(uint256 lp) internal view override returns (uint256)
```

Calculates underlying value of LP tokens.

Parameters:

* `lp`: LP token amount

Returns:

* USDCe value

#### \_lpForAmount

```solidity
function _lpForAmount(uint256 amount) internal view override returns (uint256)
```

Calculates LP tokens needed for amount.

Parameters:

* `amount`: USDCe amount

Returns:

* Required LP tokens

#### \_estimatedTotalAssets

```solidity
function _estimatedTotalAssets() internal view override returns (uint256)
```

Calculates total strategy value including conversions.

Returns:

* Total value in USDCe

#### \_lpPrice

```solidity
function _lpPrice() internal view override returns (uint256)
```

Returns Curve LP token price.

#### \_crv

```solidity
function _crv() internal pure override returns (address)
```

Returns CRV token address.

#### \_crvUsdBalance

```solidity
function _crvUsdBalance() internal view returns (uint256)
```

Returns strategy's crvUSD balance.

#### \_simulateHarvest

```solidity
function _simulateHarvest() public override
```

Simulates harvest operation and reverts with simulation data.


# Beefy


# BeefyCrvUSDUSDCeStrategy

## Overview

The BeefyCrvUSDUSDCeStrategy contract is a simple pass-through strategy that inherits from BaseBeefyCurveStrategy with no additional functionality. It supplies tokens into a Beefy Vault specifically for the crvUSD-USDCe Curve pool to earn yield, using all the base functionality provided by BaseBeefyCurveStrategy without modifications.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseBeefyCurveStrategy.

## Functions

All functionality is inherited from BaseBeefyCurveStrategy with no overrides or additional functions.

Key Features:

* Uses Beefy Vault for yield generation
* Handles Curve LP tokens for crvUSD-USDCe pool
* Inherits Curve pool interactions from BaseBeefyCurveStrategy
* Inherits Beefy Vault interactions from BaseBeefyStrategy


# BeefyMaiUSDCeStrategy

## Overview

The BeefyMaiUSDCeStrategy contract is a strategy that supplies USDCe into the MAI-USDCe Curve pool and stakes the LP tokens in a Beefy Vault to earn yield. It inherits from BaseBeefyCurveStrategy and provides custom implementation for investment logic.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseBeefyCurveStrategy.

## Functions

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256)
```

Invests assets through multiple steps:

1. Validates investment amount
2. Adds liquidity to MAI-USDCe Curve pool
3. Stakes LP tokens in Beefy vault

Parameters:

* `amount`: Amount of USDCe to invest
* `minOutputAfterInvestment`: Minimum expected Beefy vault shares

Returns:

* Amount of Beefy vault shares received

Key Features:

* Uses Curve's add\_liquidity function with USDCe
* Enforces maximum single trade limit
* Verifies minimum output requirements
* Tracks share balances before/after deposit
* Emits investment events


# BeefyUSDCeDAIStrategy

## Overview

The BeefyUSDCeDAIStrategy contract is a sophisticated strategy that manages USDCe-DAI positions through Gamma's Hypervisor (concentrated liquidity positions) and stakes them in a Beefy Vault. It handles complex liquidity calculations and token conversions through Curve's AtriCrypto zapper.

## Constants

```solidity
address public constant usdce = USDCE_POLYGON;               // USDCe token address
address public constant dai = DAI_POLYGON;                   // DAI token address
uint256 constant _1_USDCE = 1e6;                            // One USDCe unit
uint256 constant _1_DAI = 1 ether;                          // One DAI unit
ICurveAtriCryptoZapper constant zapper =                    // Curve zapper for stable swaps
    ICurveAtriCryptoZapper(CURVE_AAVE_ATRICRYPTO_ZAPPER_POLYGON);
```

## State Variables

```solidity
IUniProxy public uniProxy;              // Gamma's deposit proxy
IHypervisor public hypervisor;          // Gamma's hypervisor contract
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IUniProxy _uniProxy,
    IHypervisor _hypervisor,
    IBeefyVault _beefyVault
) public initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_uniProxy`: Gamma's UniProxy contract
* `_hypervisor`: Gamma's Hypervisor contract
* `_beefyVault`: Beefy vault address

### Core Functions

#### calculateUSDCeToSwap

```solidity
function calculateUSDCeToSwap(uint256 totalUSDCe, uint256 ratio) public view returns (uint256 usdceToSwap)
```

Calculates optimal USDCe amount to swap for balanced liquidity provision.

Parameters:

* `totalUSDCe`: Total USDCe amount
* `ratio`: Target ratio

Returns:

* Amount of USDCe to swap

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256)
```

Complex investment process:

1. Calculates optimal token ratio
2. Swaps portion of USDCe to DAI
3. Deposits into Gamma Hypervisor
4. Stakes LP tokens in Beefy

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* Amount of shares received

#### \_divest

```solidity
function _divest(uint256 amount) internal override returns (uint256)
```

Withdrawal process:

1. Withdraws from Beefy
2. Removes liquidity from Hypervisor
3. Converts tokens back to USDCe

Parameters:

* `amount`: Amount of Beefy shares to divest

Returns:

* Amount of USDCe received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256)
```

Calculates underlying value including:

* Base and limit range positions
* Unused token balances
* Fee accumulation

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256)
```

Calculates shares for amount considering:

* Current token ratios
* Liquidity distribution
* Price calculations

#### \_convertUsdceToDai

```solidity
function _convertUsdceToDai(uint256 usdceAmount) internal view returns (uint256)
```

Calculates DAI equivalent of USDCe amount.

#### Gamma Helper Functions

**computeLiquidityFromShares**

```solidity
function computeLiquidityFromShares(int24 tickLower, int24 tickUpper, uint256 shares) internal view returns (uint128)
```

Calculates liquidity amount for given share position.

**getPositionInfo**

```solidity
function getPositionInfo(int24 tickLower, int24 tickUpper) internal view returns (uint128 liquidity, uint128 tokensOwed0, uint128 tokensOwed1)
```

Retrieves position information including:

* Current liquidity
* Accumulated fees

**\_CalcBurnLiquidity**

```solidity
function _CalcBurnLiquidity(int24 tickLower, int24 tickUpper, uint128 liquidity) public view returns (uint256 amount0, uint256 amount1)
```

Calculates token amounts from burning liquidity position.


# Yearn


# YearnAaveV3USDTLenderStrategy

## Overview

The YearnAaveV3USDTLenderStrategy contract is a strategy that supplies USDT into a Yearn V3 Vault for AAVE v3 lending. It manages conversions between USDCe and USDT through Curve's AtriCrypto zapper and includes safety margins for liquidations.

## Constants

```solidity
ICurveAtriCryptoZapper constant zapper = ICurveAtriCryptoZapper(CURVE_AAVE_ATRICRYPTO_ZAPPER_POLYGON);  // Curve zapper
address public constant usdt = USDT_POLYGON;                                                              // USDT address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy and sets up trading limits.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount to vault with loss calculation.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view override returns (uint256 liquidatedAmount)
```

Simulates withdrawal including losses and conversion rates.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view override returns (uint256 requestedAmount)
```

Calculates input needed with 1% safety margin.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

#### maxLiquidate

```solidity
function maxLiquidate() public view override returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

#### maxLiquidateExact

```solidity
function maxLiquidateExact() public view override returns (uint256)
```

Returns maximum withdrawable amount with safety margin.

Returns:

* Maximum withdrawable amount before losses

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Converting USDCe to USDT through zapper
2. Depositing USDT into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Redeeming from Yearn vault
2. Converting USDT to USDCe through zapper

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256 _assets)
```

Calculates underlying value including conversion rate.

Parameters:

* `shares`: Share amount

Returns:

* Underlying asset value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 _shares)
```

Calculates shares needed including spot price conversion.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

#### \_spotPriceDy

```solidity
function _spotPriceDy(uint256 i, uint256 amount) internal view returns (uint256 _spotDy)
```

Calculates spot price conversion without slippage.

Parameters:

* `i`: Direction (1: USDC->USDT, 2: USDT->USDC)
* `amount`: Amount to convert

Returns:

* Converted amount at spot price


# YearnAjnaUSDCStrategy

## Overview

The YearnAjnaUSDCStrategy contract is a simple pass-through strategy that inherits from BaseYearnV3Strategy to supply USDC into a Yearn V3 Vault for Ajna lending. It provides minimal customization with unlimited trading size.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnCompoundUSDCeLenderStrategy

## Overview

The YearnCompoundUSDCeLenderStrategy contract is a simple pass-through strategy that inherits from BaseYearnV3Strategy to supply USDCe into a Yearn V3 Vault for Compound lending. It provides minimal customization with unlimited trading size.

## Constants

No additional constants defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnDAILenderStrategy

## Overview

The YearnDAILenderStrategy contract is a strategy that supplies DAI into a Yearn V3 Vault for lending. It manages conversions between USDCe and DAI through Curve's AtriCrypto zapper and handles decimal scaling between tokens.

## Constants

```solidity
ICurveAtriCryptoZapper constant zapper = ICurveAtriCryptoZapper(CURVE_AAVE_ATRICRYPTO_ZAPPER_POLYGON);  // Curve zapper
address public constant dai = DAI_POLYGON;                                                                // DAI address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with trading limits.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount to vault with loss calculation.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view override returns (uint256 liquidatedAmount)
```

Simulates withdrawal including losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view override returns (uint256 requestedAmount)
```

Calculates input needed with 1% buffer.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

#### maxLiquidate

```solidity
function maxLiquidate() public view override returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

#### maxLiquidateExact

```solidity
function maxLiquidateExact() public view override returns (uint256)
```

Returns maximum withdrawable amount with safety margin.

Returns:

* Maximum withdrawable amount before losses

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Scaling amounts for 18 decimals
2. Converting USDCe to DAI through zapper
3. Depositing into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Redeeming from Yearn vault
2. Converting DAI to USDCe through zapper

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256 _assets)
```

Calculates underlying value including conversion.

Parameters:

* `shares`: Share amount

Returns:

* Underlying asset value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 _shares)
```

Calculates shares needed including spot price.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

#### \_spotPriceDy

```solidity
function _spotPriceDy(uint256 i, uint256 amount) internal view returns (uint256 _spotDy)
```

Calculates spot price conversion without slippage.

Parameters:

* `i`: Direction (0: DAI->USDC, 1: USDC->DAI)
* `amount`: Amount to convert

Returns:

* Converted amount at spot price


# YearnDAIStrategy

## Overview

The YearnDAIStrategy contract is a strategy that supplies DAI into a Yearn V3 Vault. It manages conversions between USDCe and DAI through Curve's AtriCrypto zapper and handles decimal scaling between the 6-decimal USDCe and 18-decimal DAI tokens.

## Constants

```solidity
ICurveAtriCryptoZapper constant zapper = ICurveAtriCryptoZapper(CURVE_AAVE_ATRICRYPTO_ZAPPER_POLYGON);  // Curve zapper
address public constant dai = DAI_POLYGON;                                                                // DAI address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with trading limits.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount to vault with loss calculation.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view override returns (uint256 liquidatedAmount)
```

Simulates withdrawal including losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view override returns (uint256 requestedAmount)
```

Calculates input needed with 1% buffer.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

#### maxLiquidate

```solidity
function maxLiquidate() public view override returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

#### maxLiquidateExact

```solidity
function maxLiquidateExact() public view override returns (uint256)
```

Returns maximum withdrawable amount with 1% safety margin.

Returns:

* Maximum withdrawable amount before losses

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Scaling between 6 and 18 decimals
2. Converting USDCe to DAI through zapper
3. Depositing DAI into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Redeeming from Yearn vault
2. Converting DAI to USDCe through zapper

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256 _assets)
```

Calculates underlying value including conversion.

Parameters:

* `shares`: Share amount

Returns:

* Underlying asset value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 _shares)
```

Calculates shares needed including spot price.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

#### \_spotPriceDy

```solidity
function _spotPriceDy(uint256 i, uint256 amount) internal view returns (uint256 _spotDy)
```

Calculates spot price conversion without slippage.

Parameters:

* `i`: Direction (0: DAI->USDC, 1: USDC->DAI)
* `amount`: Amount to convert

Returns:

* Converted amount at spot price


# YearnMaticUSDCStakingStrategy

## Overview

The YearnMaticUSDCStakingStrategy contract is a strategy that supplies USDC into a Yearn V3 Vault and stakes the vault shares to earn additional WMATIC rewards. It manages reward claiming and conversion through Uniswap V3.

## Constants

```solidity
address public constant wpol = WPOL_POLYGON;                                      // WMATIC token address
IRouter public constant router = IRouter(UNISWAP_V3_ROUTER_POLYGON);             // Uniswap V3 router
IStakingRewardsMulti public constant yearnStakingRewards =                       // Yearn staking rewards
    IStakingRewardsMulti(0x602920E7e0a335137E02DF139CdF8D1381DAdBfD);
```

## State Variables

```solidity
uint256 public minSwapMatic;    // Minimum amount of WMATIC to swap
```

## Functions

### Initialization Functions

#### constructor

```solidity
constructor() initializer
```

Empty constructor marked as initializer.

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public override initializer
```

Initializes the strategy with required components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount and re-stakes remaining shares.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### Internal Core Functions

#### \_beforePrepareReturn

```solidity
function _beforePrepareReturn() internal override
```

Claims and processes staking rewards before preparing return.

#### \_adjustPosition

```solidity
function _adjustPosition(uint256, uint256 minOutputAfterInvestment) internal override
```

Adjusts strategy positions based on available capital.

Parameters:

* `minOutputAfterInvestment`: Minimum expected output

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets and stakes received shares.

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets from staking and vault.

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

#### \_liquidatePosition

```solidity
function _liquidatePosition(uint256 amountNeeded) internal override returns (uint256 liquidatedAmount, uint256 loss)
```

Liquidates position up to requested amount.

Parameters:

* `amountNeeded`: Amount to liquidate

Returns:

* `liquidatedAmount`: Amount actually liquidated
* `loss`: Amount of losses incurred

#### \_unwindRewards

```solidity
function _unwindRewards(IStakingRewardsMulti _yearnStakingRewards) internal
```

Claims WMATIC rewards and converts to USDC.

Parameters:

* `_yearnStakingRewards`: Staking rewards contract

### Internal View Functions

#### \_wpolBalance

```solidity
function _wpolBalance() internal view returns (uint256)
```

Returns strategy's WMATIC balance.

Returns:

* Current WMATIC balance

#### \_shareBalance

```solidity
function _shareBalance() internal view override returns (uint256 _balance)
```

Returns strategy's staked vault share balance.

Returns:

* Current staked share balance


# YearnUSDCeLenderStrategy

## Overview

The YearnUSDCeLenderStrategy contract is a simple pass-through strategy that inherits from BaseYearnV3Strategy to supply USDCe directly into a Yearn V3 Vault for lending. It provides minimal customization with unlimited trading size.

## Constants

No additional constants are defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnUSDCeStrategy

## Overview

The YearnUSDCeStrategy contract is a simple pass-through strategy that inherits from BaseYearnV3Strategy to supply USDCe directly into a Yearn V3 Vault. It provides minimal customization with unlimited trading size.

## Constants

No additional constants are defined in this contract.

## State Variables

No additional state variables beyond those inherited from BaseYearnV3Strategy.

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with Yearn V3 components.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

Key Features:

* Approves unlimited spending for Yearn vault
* Sets unlimited maximum trade size
* Inherits all core functionality from BaseYearnV3Strategy


# YearnUSDTStrategy

## Overview

The YearnUSDTStrategy contract is a strategy that supplies USDT into a Yearn V3 Vault. It manages conversions between USDCe and USDT through Curve's AtriCrypto zapper and includes safety margins for liquidations.

## Constants

```solidity
ICurveAtriCryptoZapper constant zapper = ICurveAtriCryptoZapper(CURVE_AAVE_ATRICRYPTO_ZAPPER_POLYGON);  // Curve zapper
address public constant usdt = USDT_POLYGON;                                                              // USDT address
```

## Functions

### Initialization Functions

#### initialize

```solidity
function initialize(
    IMaxApyVault _vault,
    address[] calldata _keepers,
    bytes32 _strategyName,
    address _strategist,
    IYVaultV3 _yVault
) public virtual override initializer
```

Initializes the strategy with trading limits.

Parameters:

* `_vault`: MaxApy vault address
* `_keepers`: Array of keeper addresses
* `_strategyName`: Name of the strategy
* `_strategist`: Strategist address
* `_yVault`: Yearn V3 vault address

### Core Functions

#### liquidateExact

```solidity
function liquidateExact(uint256 amountNeeded) external override checkRoles(VAULT_ROLE) returns (uint256 loss)
```

Withdraws exact amount to vault with loss calculation.

Parameters:

* `amountNeeded`: Amount to withdraw

Returns:

* `loss`: Amount of realized loss

### View Functions

#### previewLiquidate

```solidity
function previewLiquidate(uint256 requestedAmount) public view override returns (uint256 liquidatedAmount)
```

Simulates withdrawal including losses.

Parameters:

* `requestedAmount`: Amount to withdraw

Returns:

* `liquidatedAmount`: Expected output amount

#### previewLiquidateExact

```solidity
function previewLiquidateExact(uint256 liquidatedAmount) public view override returns (uint256 requestedAmount)
```

Calculates input needed with 1% buffer.

Parameters:

* `liquidatedAmount`: Desired output amount

Returns:

* `requestedAmount`: Required input amount

#### maxLiquidate

```solidity
function maxLiquidate() public view override returns (uint256)
```

Returns maximum withdrawable amount after losses.

Returns:

* Maximum withdrawable amount

#### maxLiquidateExact

```solidity
function maxLiquidateExact() public view override returns (uint256)
```

Returns maximum withdrawable amount with 1% safety margin.

Returns:

* Maximum withdrawable amount before losses

### Internal Core Functions

#### \_invest

```solidity
function _invest(uint256 amount, uint256 minOutputAfterInvestment) internal override returns (uint256 depositedAmount)
```

Invests assets by:

1. Converting USDCe to USDT through zapper
2. Depositing into Yearn vault

Parameters:

* `amount`: Amount to invest
* `minOutputAfterInvestment`: Minimum expected shares

Returns:

* `depositedAmount`: Amount of tokens received

#### \_divest

```solidity
function _divest(uint256 shares) internal override returns (uint256 withdrawn)
```

Withdraws assets by:

1. Redeeming from Yearn vault
2. Converting USDT to USDCe through zapper

Parameters:

* `shares`: Amount of shares to withdraw

Returns:

* `withdrawn`: Amount of assets received

### Internal View Functions

#### \_shareValue

```solidity
function _shareValue(uint256 shares) internal view override returns (uint256 _assets)
```

Calculates underlying value including conversion.

Parameters:

* `shares`: Share amount

Returns:

* Underlying asset value

#### \_sharesForAmount

```solidity
function _sharesForAmount(uint256 amount) internal view override returns (uint256 _shares)
```

Calculates shares needed including spot price.

Parameters:

* `amount`: Asset amount

Returns:

* Required shares

#### \_spotPriceDy

```solidity
function _spotPriceDy(uint256 i, uint256 amount) internal view returns (uint256 _spotDy)
```

Calculates spot price conversion without slippage.

Parameters:

* `i`: Direction (1: USDC->USDT, 2: USDT->USDC)
* `amount`: Amount to convert

Returns:

* Converted amount at spot price


# Subgraph


# Overview

The maxAPY subgraph indexes protocol data from both Ethereum and Polygon networks, providing a GraphQL API for querying historical and real-time protocol data. Both networks share identical schemas, ensuring consistent data access across chains.

### Deployments

Ethereum:\
[https://subgraph.satsuma-prod.com/](https://subgraph.satsuma-prod.com/bb7d5107614b/unlockd/maxapy-ethereum-mainnet/api)[bb7d5107614b](https://subgraph.satsuma-prod.com/bb7d5107614b/unlockd/maxapy-ethereum-mainnet/api)[/unlockd/maxapy-ethereum-mainnet/api](https://subgraph.satsuma-prod.com/bb7d5107614b/unlockd/maxapy-ethereum-mainnet/api)\
\
Polygon:\
[https://subgraph.satsuma-prod.com/](https://subgraph.satsuma-prod.com/bb7d5107614b/unlockd/maxapy-polygon-mainnet/api)[bb7d5107614b](https://subgraph.satsuma-prod.com/bb7d5107614b/unlockd/maxapy-polygon-mainnet/api)[/unlockd/maxapy-polygon-mainnet/api](https://subgraph.satsuma-prod.com/bb7d5107614b/unlockd/maxapy-polygon-mainnet/api)


# Schema

<details>

<summary>Full schema</summary>

{% code fullWidth="true" %}

```json
{
    "data": {
        "__schema": {
            "types": [
                {
                    "name": "Account",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vaultBalances",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "deposits",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "withdrawals",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "sentTransfers",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "receivedTransfers",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "AccountVaultBalance",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "account",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vault",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "netDeposits",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalDeposited",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalWithdrawn",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalSent",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalReceived",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "shareBalance",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "AccountVaultBalance_filter",
                    "fields": null
                },
                {
                    "name": "AccountVaultBalance_orderBy",
                    "fields": null
                },
                {
                    "name": "Account_filter",
                    "fields": null
                },
                {
                    "name": "Account_orderBy",
                    "fields": null
                },
                {
                    "name": "Aggregation_interval",
                    "fields": null
                },
                {
                    "name": "BigDecimal",
                    "fields": null
                },
                {
                    "name": "BigInt",
                    "fields": null
                },
                {
                    "name": "BlockChangedFilter",
                    "fields": null
                },
                {
                    "name": "Block_height",
                    "fields": null
                },
                {
                    "name": "Boolean",
                    "fields": null
                },
                {
                    "name": "Bytes",
                    "fields": null
                },
                {
                    "name": "Deposit",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vault",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "account",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "amount",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "shares",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "timestamp",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transaction",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Deposit_filter",
                    "fields": null
                },
                {
                    "name": "Deposit_orderBy",
                    "fields": null
                },
                {
                    "name": "Float",
                    "fields": null
                },
                {
                    "name": "Harvest",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vault",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "strategy",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "timestamp",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "gain",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "loss",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "debt",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "pricePerShare",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vaultTotalSupply",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vaultTotalAssets",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transaction",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Harvest_filter",
                    "fields": null
                },
                {
                    "name": "Harvest_orderBy",
                    "fields": null
                },
                {
                    "name": "ID",
                    "fields": null
                },
                {
                    "name": "Int",
                    "fields": null
                },
                {
                    "name": "Int8",
                    "fields": null
                },
                {
                    "name": "OrderDirection",
                    "fields": null
                },
                {
                    "name": "Query",
                    "fields": [
                        {
                            "name": "vault",
                            "type": {
                                "name": "Vault",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "vaults",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "strategy",
                            "type": {
                                "name": "Strategy",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "strategies",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "accountVaultBalance",
                            "type": {
                                "name": "AccountVaultBalance",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "accountVaultBalances",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "account",
                            "type": {
                                "name": "Account",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "accounts",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "deposit",
                            "type": {
                                "name": "Deposit",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "deposits",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "withdraw",
                            "type": {
                                "name": "Withdraw",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "withdraws",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transfer",
                            "type": {
                                "name": "Transfer",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "transfers",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "harvest",
                            "type": {
                                "name": "Harvest",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "harvests",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transaction",
                            "type": {
                                "name": "Transaction",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "transactions",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "token",
                            "type": {
                                "name": "Token",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "tokens",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "_meta",
                            "type": {
                                "name": "_Meta_",
                                "kind": "OBJECT"
                            }
                        }
                    ]
                },
                {
                    "name": "Strategy",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "name",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vault",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "debtRatio",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "maxDebtPerHarvest",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "minDebtPerHarvest",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "performanceFee",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "isActive",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "firstReport",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "lastReport",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalDebt",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalGain",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalLoss",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "unrealizedGain",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "debtPayment",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "credit",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "loss",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Strategy_filter",
                    "fields": null
                },
                {
                    "name": "Strategy_orderBy",
                    "fields": null
                },
                {
                    "name": "String",
                    "fields": null
                },
                {
                    "name": "Subscription",
                    "fields": [
                        {
                            "name": "vault",
                            "type": {
                                "name": "Vault",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "vaults",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "strategy",
                            "type": {
                                "name": "Strategy",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "strategies",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "accountVaultBalance",
                            "type": {
                                "name": "AccountVaultBalance",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "accountVaultBalances",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "account",
                            "type": {
                                "name": "Account",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "accounts",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "deposit",
                            "type": {
                                "name": "Deposit",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "deposits",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "withdraw",
                            "type": {
                                "name": "Withdraw",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "withdraws",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transfer",
                            "type": {
                                "name": "Transfer",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "transfers",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "harvest",
                            "type": {
                                "name": "Harvest",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "harvests",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transaction",
                            "type": {
                                "name": "Transaction",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "transactions",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "token",
                            "type": {
                                "name": "Token",
                                "kind": "OBJECT"
                            }
                        },
                        {
                            "name": "tokens",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "_meta",
                            "type": {
                                "name": "_Meta_",
                                "kind": "OBJECT"
                            }
                        }
                    ]
                },
                {
                    "name": "Timestamp",
                    "fields": null
                },
                {
                    "name": "Token",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "address",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "decimals",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "name",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "symbol",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "isShare",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "isWrapped",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Token_filter",
                    "fields": null
                },
                {
                    "name": "Token_orderBy",
                    "fields": null
                },
                {
                    "name": "Transaction",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "timestamp",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "blockNumber",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transactionHash",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Transaction_filter",
                    "fields": null
                },
                {
                    "name": "Transaction_orderBy",
                    "fields": null
                },
                {
                    "name": "Transfer",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "from",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "to",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vault",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "amount",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "shares",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "timestamp",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transaction",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Transfer_filter",
                    "fields": null
                },
                {
                    "name": "Transfer_orderBy",
                    "fields": null
                },
                {
                    "name": "Vault",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "underlyingToken",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "shareToken",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "strategies",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "pricePerShare",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalSupply",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "totalAssets",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "idleAssets",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "debtOutstanding",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "creditAvailable",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "depositLimit",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "emergencyShutdown",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "performanceFee",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "managementFee",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "lastReport",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "Treasury",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "withdrawalQueue",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "accountVaultBalances",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "deposits",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "withdrawals",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transfers",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "harvests",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Vault_filter",
                    "fields": null
                },
                {
                    "name": "Vault_orderBy",
                    "fields": null
                },
                {
                    "name": "Withdraw",
                    "fields": [
                        {
                            "name": "id",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "vault",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "account",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "amount",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "shares",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "timestamp",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "transaction",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "Withdraw_filter",
                    "fields": null
                },
                {
                    "name": "Withdraw_orderBy",
                    "fields": null
                },
                {
                    "name": "_Block_",
                    "fields": [
                        {
                            "name": "hash",
                            "type": {
                                "name": "Bytes",
                                "kind": "SCALAR"
                            }
                        },
                        {
                            "name": "number",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "timestamp",
                            "type": {
                                "name": "Int",
                                "kind": "SCALAR"
                            }
                        },
                        {
                            "name": "parentHash",
                            "type": {
                                "name": "Bytes",
                                "kind": "SCALAR"
                            }
                        }
                    ]
                },
                {
                    "name": "_Meta_",
                    "fields": [
                        {
                            "name": "block",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "deployment",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        },
                        {
                            "name": "hasIndexingErrors",
                            "type": {
                                "name": null,
                                "kind": "NON_NULL"
                            }
                        }
                    ]
                },
                {
                    "name": "_SubgraphErrorPolicy_",
                    "fields": null
                }
            ]
        }
    }
}
```

{% endcode %}

</details>

## Core Entities

### Vault

Represents a maxAPY vault that holds user deposits and manages strategies.

```graphql
type Vault @entity {
  id: ID!
  underlyingToken: Token!
  shareToken: Token!
  strategies: [Strategy!]!
  pricePerShare: BigDecimal!
  totalSupply: BigDecimal!
  totalAssets: BigDecimal!
  idleAssets: BigDecimal!
  debtOutstanding: BigDecimal!
  creditAvailable: BigDecimal!
  depositLimit: BigDecimal!
  emergencyShutdown: Boolean!
  performanceFee: BigInt!
  managementFee: BigInt!
  lastReport: BigInt!
  Treasury: Bytes!
  withdrawalQueue: [Bytes!]!
  accountVaultBalances: [AccountVaultBalance!]!
  deposits: [Deposit!]!
  withdrawals: [Withdraw!]!
  transfers: [Transfer!]!
  harvests: [Harvest!]!
}
```

### Strategy

Tracks individual yield strategies and their performance metrics.

```graphql
type Strategy @entity {
  id: ID!
  name: String!
  vault: Vault!
  debtRatio: BigInt!
  maxDebtPerHarvest: BigInt!
  minDebtPerHarvest: BigInt!
  performanceFee: BigInt!
  isActive: Boolean!
  firstReport: BigInt!
  lastReport: BigInt!
  totalDebt: BigInt!
  totalGain: BigInt!
  totalLoss: BigInt!
  unrealizedGain: BigInt!
  debtPayment: BigInt!
  credit: BigInt!
  loss: BigInt!
}
```

### Account

Represents a user account and their interactions with the protocol.

```graphql
type Account @entity {
  id: ID!
  vaultBalances: [AccountVaultBalance!]!
  deposits: [Deposit!]!
  withdrawals: [Withdraw!]!
  sentTransfers: [Transfer!]!
  receivedTransfers: [Transfer!]!
}
```

## Transaction Entities

### Deposit

Records deposit transactions into vaults.

```graphql
type Deposit @entity {
  id: ID!
  vault: Vault!
  account: Account!
  amount: BigDecimal!
  shares: BigDecimal!
  timestamp: BigInt!
  transaction: Transaction!
}
```

### Withdraw

Records withdrawal transactions from vaults.

```graphql
type Withdraw @entity {
  id: ID!
  vault: Vault!
  account: Account!
  amount: BigDecimal!
  shares: BigDecimal!
  timestamp: BigInt!
  transaction: Transaction!
}
```

### Harvest

Records strategy harvest events and performance metrics.

```graphql
type Harvest @entity {
  id: ID!
  vault: Vault!
  strategy: Strategy!
  timestamp: BigInt!
  gain: BigDecimal!
  loss: BigDecimal!
  debt: BigDecimal!
  pricePerShare: BigDecimal!
  vaultTotalSupply: BigDecimal!
  vaultTotalAssets: BigDecimal!
  transaction: Transaction!
}
```

***


# Query Guide

## Common Queries <a href="#common-queries" id="common-queries"></a>

### Query Vault Data <a href="#query-vault-data" id="query-vault-data"></a>

```graphql
query getVaultData($vaultId: ID!) {
  vault(id: $vaultId) {
    id
    totalAssets
    pricePerShare
    strategies {
      id
      name
      totalDebt
      totalGain
      isActive
    }
    harvests(orderBy: timestamp, orderDirection: desc, first: 10) {
      timestamp
      gain
      loss
    }
  }
}
```

### Query User Account Data <a href="#query-user-account-data" id="query-user-account-data"></a>

```graphql
query getUserData($accountId: ID!) {
  account(id: $accountId) {
    id
    vaultBalances {
      vault {
        id
        underlyingToken {
          symbol
        }
      }
      shareBalance
      netDeposits
    }
    deposits(orderBy: timestamp, orderDirection: desc) {
      amount
      timestamp
    }
  }
}
```

### Query Strategy Performance <a href="#query-strategy-performance" id="query-strategy-performance"></a>

```
query getStrategyPerformance($strategyId: ID!) {
  strategy(id: $strategyId) {
    id
    name
    totalGain
    totalLoss
    isActive
    vault {
      id
      totalAssets
    }
  }
}
```

***

## Developer Resources <a href="#developer-resources" id="developer-resources"></a>

### Real-time Updates <a href="#real-time-updates" id="real-time-updates"></a>

Subscribe to real-time updates using GraphQL subscriptions:

```graphql
subscription onHarvest {
  harvest(orderBy: timestamp, orderDirection: desc) {
    id
    strategy {
      name
    }
    gain
    loss
    timestamp
  }
}
```

### Error Handling <a href="#error-handling" id="error-handling"></a>

The subgraph API uses the standard GraphQL error format. Common error scenarios:

1. Entity Not Found: Returns null for the requested entity
2. Invalid Query: Returns a GraphQL validation error
3. Network Issues: Check the `_meta` field for indexing status

Example error check:

```graphql
query checkIndexingStatus {
  _meta {
    hasIndexingErrors
    block {
      number
    }
  }
}
```

### Rate Limits and Best Practices <a href="#rate-limits-and-best-practices" id="rate-limits-and-best-practices"></a>

1. Implement pagination for large result sets using `first` and `skip` parameters
2. Use specific field selection instead of requesting all fields
3. Cache frequently accessed data client-side
4. Monitor your query complexity and response times
5. Consider implementing retry logic for failed queries

### SDK Integration <a href="#sdk-integration" id="sdk-integration"></a>

For TypeScript/JavaScript applications, you can generate typed clients using:

* GraphQL Code Generator
* Apollo Codegen
* URQL Codegen

Example type generation command:

```bash
graphql-codegen --config codegen.yml
```


