🐸
maxAPY for Devs
  • maxAPY ERC7540
    • MetaVault
      • Introduction
      • Architecture
      • Core Operations
      • State Management & Operations
      • Asset Management
      • Settlement Mechanics
      • Withdrawal Queue Mechanics
      • Deployed Addresses
  • Periphery
    • Hurdle Rate Oracle
    • SharePriceOracle
    • Deployed Addresses
  • maxAPY ERC4626
    • Introduction
    • Architecture
    • Vault
      • MaxApyFactory
      • MaxApyRouter
      • MaxApyVault
    • Periphery
      • MaxApyHarvester
    • Base Strategies
      • BaseStrategy
      • BaseSommelierStrategy
      • BaseYearnV3Strategy
      • BaseYearnV2Strategy
      • BaseConvexStrategy
      • BaseConvexStrategyPolygon
      • BaseBeefyStrategy
      • BaseHopStrategy
      • BaseBeefyCurveStrategy
    • Strategies
      • Ethereum - WETH
        • Convex
          • ConvexdETHFrxETHStrategy
        • Sommelier
          • SommelierMorphoEthMaximizerStrategy
          • SommelierStEthDepositTurboStEthStrategy
          • SommelierTurboDivEthStrategy
          • SommelierTurboEEthV2Strategy
          • SommelierTurboEthXStrategy
          • SommelierTurboEzEthStrategy
          • SommelierTurboRsEthStrategy
          • SommelierTurboStEthStrategy
          • SommelierTurboSwEthStrategy
        • Yearn
          • YearnAaveV3WETHLenderStrategy
          • YearnAjnaWETHStakingStrategy
          • YearnCompoundV3WETHLenderStrategy
          • YearnV3WETH2Strategy
          • YearnV3WETHStrategy
          • YearnWETHStrategy
      • Ethereum - USDC
        • Convex
          • ConvexCrvUSDWethCollateralStrategy
        • Sommelier
          • SommelierTurboGHOStrategy
        • Yearn
          • YearnAjnaDAIStakingStrategy
          • YearnDAIStrategy
          • YearnLUSDStrategy
          • YearnUSDCStrategy
          • YearnUSDTStrategy
      • Polygon - WETH
        • Hop
          • HopETHStrategy
      • Polygon - USDC.e
        • Convex
          • ConvexUSDCCrvUSDStrategy
          • ConvexUSDTCrvUSDStrategy
        • Beefy
          • BeefyCrvUSDUSDCeStrategy
          • BeefyMaiUSDCeStrategy
          • BeefyUSDCeDAIStrategy
        • Yearn
          • YearnAaveV3USDTLenderStrategy
          • YearnAjnaUSDCStrategy
          • YearnCompoundUSDCeLenderStrategy
          • YearnDAILenderStrategy
          • YearnDAIStrategy
          • YearnMaticUSDCStakingStrategy
          • YearnUSDCeLenderStrategy
          • YearnUSDCeStrategy
          • YearnUSDTStrategy
    • Subgraph
      • Overview
      • Schema
      • Query Guide
Powered by GitBook
On this page
  • Cross-Chain Settlement Flow
  • Bridge Failure Handling
  • Security Considerations
  1. maxAPY ERC7540
  2. MetaVault

Settlement Mechanics

PreviousAsset ManagementNextWithdrawal Queue Mechanics

Last updated 4 months ago

Cross-Chain Settlement Flow

Settlement Components

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

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

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

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

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);
}
  1. Asset Divestment Settlement

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

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

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;
}
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

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

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