POL Price: $0.693263 (+0.63%)
 

Overview

POL Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 POL

POL Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Push Incoming Or...595546432024-07-19 15:04:52139 days ago1721401492IN
0x8dD78e46...0bd6B444F
0 POL0.0071252936.62692873
Push Orders595546302024-07-19 15:04:20139 days ago1721401460IN
0x8dD78e46...0bd6B444F
0 POL0.0023219536.65456368
Push Incoming Or...572208082024-05-21 11:39:32198 days ago1716291572IN
0x8dD78e46...0bd6B444F
0 POL0.0060015536.44239261
Push Incoming Or...571893572024-05-20 15:53:47199 days ago1716220427IN
0x8dD78e46...0bd6B444F
0 POL0.006551739.79173847
Push Orders571892492024-05-20 15:49:31199 days ago1716220171IN
0x8dD78e46...0bd6B444F
0 POL0.0025281939.91031604

Latest 11 internal transactions

Parent Transaction Hash Block From To
595550062024-07-19 15:17:46139 days ago1721402266
0x8dD78e46...0bd6B444F
0.73069026 POL
595550062024-07-19 15:17:46139 days ago1721402266
0x8dD78e46...0bd6B444F
0.73069026 POL
595495032024-07-19 12:00:36139 days ago1721390436
0x8dD78e46...0bd6B444F
0.7113005 POL
595495032024-07-19 12:00:36139 days ago1721390436
0x8dD78e46...0bd6B444F
0.7113005 POL
572208842024-05-21 11:42:46198 days ago1716291766
0x8dD78e46...0bd6B444F
0.54842419 POL
572208842024-05-21 11:42:46198 days ago1716291766
0x8dD78e46...0bd6B444F
0.54842419 POL
571893852024-05-20 15:55:07199 days ago1716220507
0x8dD78e46...0bd6B444F
0.50690328 POL
571893852024-05-20 15:55:07199 days ago1716220507
0x8dD78e46...0bd6B444F
0.50690328 POL
571880002024-05-20 14:59:58199 days ago1716217198
0x8dD78e46...0bd6B444F
0.53155518 POL
571880002024-05-20 14:59:58199 days ago1716217198
0x8dD78e46...0bd6B444F
0.53155518 POL
571865002024-05-20 14:00:56199 days ago1716213656
0x8dD78e46...0bd6B444F
 Contract Creation0 POL
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RemoteOmnichainMessenger

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 39 : RemoteOmnichainMessenger.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import {IOrderBook} from "./interfaces/IOrderBook.sol";
import {IPhutureOnMessageCallback} from "./interfaces/IPhutureOnMessageCallback.sol";
import {IRemoteOmnichainMessenger} from "./interfaces/IRemoteOmnichainMessenger.sol";
import {IVault} from "./interfaces/IVault.sol";
import {IEscrowDeployer} from "./escrow/interfaces/IEscrowDeployer.sol";

import {RebalancingLib} from "./libraries/RebalancingLib.sol";
import {OrderLib} from "./libraries/OrderLib.sol";

import {OmnichainMessenger} from "./OmnichainMessenger.sol";

/// @title RemoteOmnichainMessenger
/// @notice A messenger contract for the Remote chain
/// @dev Methods of this contract are not intended for direct usage
contract RemoteOmnichainMessenger is IRemoteOmnichainMessenger, OmnichainMessenger {
    /// @dev The address of the Vault contract
    IVault internal immutable vault;

    /// @notice Thrown when there are pending orders to be pushed
    error PushOrders();

    /// @dev Thrown when the provided msg.value is insufficient for the operation
    error InsufficientValue();

    constructor(
        address owner,
        address _stargateComposer,
        address payable _endpoint,
        address _vault,
        uint16 _homeEid,
        address _sgETH,
        NativeInfo memory _nativeInfo
    ) OmnichainMessenger(owner, _stargateComposer, _endpoint, _homeEid, _sgETH, _nativeInfo) {
        vault = IVault(_vault);
    }

    /// @notice Sends the currencies hash to the Homechain.
    ///
    /// @dev Reverts if the homechain endpoint ID is not set.
    ///
    /// @param info The result of registering currencies in the Vault contract.
    /// @param refundAddress The address to refund the native fee to.
    /// @param lzParams LayerZero params.
    function sendCurrenciesHash(
        IVault.RegisterCurrenciesResult calldata info,
        address payable refundAddress,
        LzParams calldata lzParams
    ) external payable onlyOwner {
        // sload home endpoint id
        uint16 eid = homeEid;

        // store the balance before the lzSend (not couting the value passed to the method)
        uint256 balanceBefore = address(this).balance - msg.value;

        // send REGISTER_CURRENCY message to homechain using LayerZero
        _lzSend(
            eid,
            _getPathOrRevert(eid),
            abi.encode(REGISTER_CURRENCY, _fillCurrenciesMetadata(info)),
            refundAddress,
            lzParams.zroPaymentAddress,
            lzParams.options[0]
        );

        // only amount passed to the method should be used for the lzSend
        if (address(this).balance < balanceBefore) revert InsufficientValue();
    }

    /// @notice Finishes the rebalancing process and sends the result hash to the specified Omnichain instance
    ///
    /// @dev Reverts if homechain and/or remote chain endpoint IDs are not set
    ///
    /// @param orderBookParams The parameters for finishing the order execution in the OrderBook contract
    /// @param params The parameters for ending the rebalancing phase in the Vault contract
    /// @param refundAddress The address to refund the payment to
    /// @param sgParams Stargate params
    /// @param lzParams LayerZero params. `REMOVE_DUST_ORDERS`'s options go first, `FINISH_REBALANCING` - the last on
    function finishVaultRebalancing(
        IOrderBook.FinishOrderExecutionParams calldata orderBookParams,
        IVault.EndRebalancingParams calldata params,
        SgParams[] calldata sgParams,
        LzParams calldata lzParams,
        address payable refundAddress
    ) external payable onlyOwner {
        // check if there are no hash of orders for the current chain
        if (ordersHashOf[block.chainid] != bytes32(0)) revert PushOrders();

        // gather pending orders from order book and distribute them across the chains using Stargate
        _distributeOrders(orderBook.finishOrderExecution(orderBookParams), sgParams, lzParams);

        // sload home endpoint id
        uint16 eid = homeEid;

        // finish rebalancing phase on Vault contract and get the result hash
        bytes32 resultHash = vault.finishRebalancingPhase(params);

        // send FINISH_REBALANCING message to homechain using LayerZero
        _lzSend(
            eid,
            _getPathOrRevert(eid),
            abi.encode(FINISH_REBALANCING, HashedResult(block.chainid, resultHash)),
            refundAddress,
            lzParams.zroPaymentAddress,
            lzParams.options[lzParams.options.length - 1]
        );
    }

    /// @notice Pushes the orders for the current chain
    ///
    /// @param chainOrders The orders to be pushed for the current chain
    function pushOrders(RebalancingLib.ChainOrders memory chainOrders) external {
        // validate orders hash
        if (keccak256(abi.encode(chainOrders)) != ordersHashOf[block.chainid]) revert OrderHashMismatch();

        // delete orders hash – it should be used only once
        delete ordersHashOf[block.chainid];
        emit OrdersHashClear(block.chainid);

        // inject local buy currency into orders
        OrderLib.Order[] memory orders = chainOrders.orders;
        _injectLocalBuyCurrency(orders);

        // set orders in the order book
        orderBook.setOrders(chainOrders.incomingOrders, orders);
    }

    /// @dev Handle messages received from the Homechain via LayerZero
    /// @param message The received message – abi encoded packet type and payload
    function _lzReceive(bytes calldata message) internal override {
        // decode packet type
        uint8 packetType = uint8(uint256(bytes32(message[:32])));

        if (packetType == TRANSFER_SNAPSHOT) {
            // TRANSFER_SNAPSHOT packet payload: original msg.sender from Homechain, kAmount redeemed
            (, address sender, uint256 kAmount) = abi.decode(message, (uint8, address, uint256));

            // get address of escrow account for sender, notice that escrow is not being deployed here
            (address escrow,) = escrowDeployer.escrowOf(sender);

            // transfer kAmount of latest snapshot to escrow of sender
            vault.transferLatestSnapshot(escrow, kAmount);
        } else if (packetType == TRADE_SNAPSHOT) {
            // TRADE_SNAPSHOT packet payload: original msg.sender from Homechain, callback for RemoteEscrow
            (, address sender, bytes memory callback) = abi.decode(message, (uint8, address, bytes));

            // sload an escrow deployer
            IEscrowDeployer deployer = escrowDeployer;

            // get address of escrow account for sender and whether it is deployed
            (address escrow, bool deployed) = deployer.escrowOf(sender);

            if (!deployed) {
                // if escrow is not deployed, deploy it
                try deployer.deploy(sender) {}
                catch {
                    return;
                }
            }

            // call phutureOnMessageCallbackV1 on deployed escrow
            try IPhutureOnMessageCallback(escrow).phutureOnMessageCallbackV1(0, 0, callback) {} catch {}
        } else if (packetType == TRANSFER_AND_TRADE_SNAPSHOT) {
            // TRANSFER_AND_TRADE_SNAPSHOT packet payload: original msg.sender from Homechain, kAmount redeemed, callback for RemoteEscrow
            (, address sender, uint256 kAmount, bytes memory callback) =
                abi.decode(message, (uint8, address, uint256, bytes));

            // sload an escrow deployer
            IEscrowDeployer deployer = escrowDeployer;

            // get address of escrow account for sender and whether it is deployed
            (address escrow, bool deployed) = deployer.escrowOf(sender);

            // transfer kAmount of latest snapshot to escrow of sender
            uint256 snapshot = vault.transferLatestSnapshot(escrow, kAmount);

            if (!deployed) {
                // if escrow is not deployed, deploy it
                try deployer.deploy(sender) {}
                catch {
                    return;
                }
            }

            // notice, transferred snapshot is passed to the callback for instant withdrawal
            try IPhutureOnMessageCallback(escrow).phutureOnMessageCallbackV1(snapshot, kAmount, callback) {} catch {}
        } else if (packetType == START_REBALANCING) {
            // PLACE_ORDERS packet payload: StartRebalancingResult {withdrawal; ordersHash;}
            (, bytes32 ordersHash, IVault.CurrencyWithdrawal memory withdrawal) =
                abi.decode(message, (uint8, bytes32, IVault.CurrencyWithdrawal));

            // save orders hash for validation on the next push
            ordersHashOf[block.chainid] = ordersHash;

            // start rebalancing phase on Vault contract
            vault.startRebalancingPhase(withdrawal);
        } else if (packetType == START_RESERVE_REBALANCING) {
            // START_RESERVE_REBALANCING packet payload: incomingOrders
            (, uint256 incomingOrders) = abi.decode(message, (uint8, uint256));

            // start rebalancing phase on Vault contract
            IVault.CurrencyWithdrawal memory withdrawal;
            vault.startRebalancingPhase(withdrawal);

            orderBook.setOrders(incomingOrders, new OrderLib.Order[](0));
        } else if (packetType == REMOVE_DUST_ORDERS) {
            // REMOVE_DUST_ORDERS packet payload: incomingOrders
            (, uint256 incomingOrders) = abi.decode(message, (uint8, uint256));

            // remove dust orders from the order book
            orderBook.removeDustOrders(incomingOrders);
        }
    }
}

File 2 of 39 : IOrderBook.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {Currency} from "../libraries/CurrencyLib.sol";
import {OrderLib} from "../libraries/OrderLib.sol";

/// @title IOrderBook interface
interface IOrderBook {
    struct TradeParams {
        address target;
        bytes data;
    }

    struct BoughtOrder {
        // Bought amount of local buy currency, sell amount on the remote
        uint256 amount;
        // Buy currency on the remote
        Currency buyCurrency;
    }

    struct PendingOrder {
        uint256 chainId;
        Currency currency;
        uint256 totalBought;
        BoughtOrder[] orders;
    }

    struct FinishOrderExecutionParams {
        OrderLib.OrderId[] orderIds;
        uint256[] idIndices;
        uint256[] pendingOrderCounts;
    }

    struct ExecuteOrderParams {
        OrderLib.OrderId orderId;
        uint96 sell;
        TradeParams tradeParams;
        bytes payload;
    }

    event OrderFilled(bytes32 indexed id, uint256 sold, uint256 bought);

    function receiveIncomingOrders(OrderLib.Order[] calldata orders, Currency currency, uint256 amount) external;
    function removeDustOrders(uint256 _incomingOrders) external;

    function setOrders(uint256 _incomingOrders, OrderLib.Order[] calldata orders) external;

    /// @notice Execute the given local order
    /// @param params Execute order data
    function executeOrder(ExecuteOrderParams calldata params) external;

    function finishOrderExecution(FinishOrderExecutionParams calldata params)
        external
        returns (PendingOrder[] memory pendingOrders);

    function updateFundManager(address fundManager, bool isAllowed) external;

    function setMessenger(address messenger) external;

    function setPriceOracle(address priceOracle) external;

    function setMaxSlippageInBP(uint16 maxSlippageInBP) external;

    function orderOf(OrderLib.OrderId calldata orderIdParams) external view returns (uint96 amount);
}

File 3 of 39 : IPhutureOnMessageCallback.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface IPhutureOnMessageCallback {
    function phutureOnMessageCallbackV1(uint256 snapshot, uint256 kAmount, bytes calldata data) external;
}

File 4 of 39 : IRemoteOmnichainMessenger.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {IOmnichainMessenger} from "./IOmnichainMessenger.sol";
import {IVault} from "./IVault.sol";

import {RebalancingLib} from "../libraries/RebalancingLib.sol";

interface IRemoteOmnichainMessenger is IOmnichainMessenger {
    function sendCurrenciesHash(
        IVault.RegisterCurrenciesResult calldata result,
        address payable refundAddress,
        LzParams calldata lzParams
    ) external payable;

    function pushOrders(RebalancingLib.ChainOrders calldata chainOrders) external;
}

File 5 of 39 : IVault.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {Currency} from "../libraries/CurrencyLib.sol";
import {a160u96} from "../utils/a160u96.sol";

interface IVault {
    struct CurrencyWithdrawal {
        uint256[] currencyIndexSet;
        uint96[] amounts;
    }

    struct SnapshotAnatomy {
        a160u96[] currencies;
        uint256[] currencyIndexSet;
    }

    struct EndRebalancingParams {
        a160u96[] anatomyCurrencies;
        SnapshotAnatomy newAnatomy;
        CurrencyWithdrawal withdrawals;
        uint256 lastKBalance;
        Currency[] currencies;
    }

    struct RebalancingResult {
        uint256 chainId;
        uint256 snapshot;
        uint256[] currencyIdSet;
        a160u96[] currencies;
    }

    struct RegisterCurrenciesResult {
        Currency[] currencies;
        bytes32 currenciesHash;
    }

    function setOrderBook(address _orderBook) external;
    function setMessenger(address _messenger) external;

    function startRebalancingPhase(CurrencyWithdrawal calldata withdrawals) external;

    function finishRebalancingPhase(EndRebalancingParams calldata params) external returns (bytes32);
    function transferLatestSnapshot(address recipient, uint256 kAmountWads) external returns (uint256);
    function withdraw(uint256 snapshot, uint256 kAmount, address recipient) external;
    function registerCurrencies(Currency[] calldata currencies) external returns (RegisterCurrenciesResult memory);

    function donate(Currency currency, bytes memory data) external;
    function consume(Currency currency, uint96 amount, address target, bytes calldata data) external;
}

File 6 of 39 : IEscrowDeployer.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

/// @title IEscrowDeployer
/// @dev Interface for the EscrowDeployer contract, which manages the deployment and tracking of Escrow contracts
interface IEscrowDeployer {
    /// @notice Deploys a new Escrow contract for the specified user
    ///
    /// @param user The address of the user for whom the Escrow contract is deployed
    ///
    /// @return escrow The address of the newly deployed Escrow contract
    function deploy(address user) external returns (address escrow);

    /// @notice Retrieves the address and deployment status of the Escrow contract associated with the given owner
    ///
    /// @param owner The address of the owner for whom to retrieve the Escrow contract information
    ///
    /// @return escrow The address of the Escrow contract associated with the owner
    /// @return deployed A boolean indicating whether the Escrow contract has been deployed for the owner
    function escrowOf(address owner) external view returns (address escrow, bool deployed);

    /// @notice Retrieves the address of the Messenger contract associated with the EscrowDeployer
    ///
    /// @return The address of the Messenger contract
    function messenger() external view returns (address);
}

File 7 of 39 : RebalancingLib.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

import {Currency} from "./CurrencyLib.sol";
import {BitSet} from "./BitSet.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {OrderLib} from "./OrderLib.sol";
import {PriceLib} from "../price-oracles/libraries/PriceLib.sol";
import {StackLib} from "./StackLib.sol";

import {IVault} from "../interfaces/IVault.sol";
import {IConfigBuilder} from "../interfaces/IConfigBuilder.sol";

/// @title RebalancingLib
/// @notice Library for managing order creation during rebalancing
library RebalancingLib {
    using SafeCastLib for *;
    using BitSet for *;
    using FixedPointMathLib for *;
    using PriceLib for *;
    using StackLib for StackLib.Node;

    /// @dev Represents the orders for a specific chain
    struct ChainOrders {
        OrderLib.Order[] orders;
        uint128 incomingOrders;
    }

    /// @dev Represents the valuation information for the assets
    struct ValuationInfo {
        uint96[] balances;
        uint256[] prices;
        uint256 totalValuation;
    }

    /// @dev Represents the result of the rebalancing process
    struct RebalancingResult {
        ChainOrders[] chainOrders;
        IVault.CurrencyWithdrawal[] withdrawals;
        uint256[] chainIdSet;
        uint256[] counters;
    }

    struct RebalancingVars {
        StackLib.Node sellDeltas;
        StackLib.Node buyDeltas;
        uint256 targetInBase;
        uint256 currentInBase;
        uint256 i;
        uint256 j;
        uint256 priorChainIndex;
        uint256 activeChainIndex;
        uint256 currencyIndex;
        uint256 orderIndex;
        uint256 weightIndex;
        bytes32 chainsHash;
        bytes32 currenciesHash;
        uint256[] counters;
        bool priorChain;
        bool activeChain;
        bool priorAsset;
    }

    struct ReserveRebalancingVars {
        uint256 orderCount;
        uint96 utilized;
        uint256 i;
        uint256 j;
        uint256 lastIndex;
        uint256 orderIndex;
        uint256 weightIndex;
        bytes32 chainsHash;
    }

    uint256 internal constant MAX_WEIGHT = type(uint16).max;

    /// @notice Thrown when the currencies hash does not match the expected value
    /// @param chainId The chainId that the hash is associated with
    error CurrenciesHashMismatch(uint256 chainId);

    /// @notice Thrown when the total weight of the rebalancing weights is not equal to MAX_WEIGHT
    error TotalWeight();

    /// @notice Thrown when there are unutilized weights in the rebalancing weights
    error UnutilizedWeights();

    /// @notice Thrown when the chains hash does not match the expected value
    error ChainsHashMismatch();

    /// @notice Previews the rebalancing orders based on the given parameters
    ///
    /// @param currenciesHashOf The mapping of chain IDs to their currencies hash
    /// @param valuationInfo The valuation information for the assets
    /// @param params The start rebalancing parameters
    /// @param chainsHash The expected hash of the chain IDs
    ///
    /// @return result The rebalancing result containing the chain orders, withdrawals, and counters
    function previewRebalancingOrders(
        mapping(uint256 => bytes32) storage currenciesHashOf,
        ValuationInfo memory valuationInfo,
        IConfigBuilder.StartRebalancingParams calldata params,
        bytes32 chainsHash
    ) internal view returns (RebalancingResult memory result) {
        result.chainIdSet = params.anatomy.chainIdSet.addAll(params.newAnatomy.chainIdSet);
        result.chainOrders = new ChainOrders[](result.chainIdSet.size());
        result.withdrawals = new IVault.CurrencyWithdrawal[](result.chainOrders.length);

        result.counters = new uint256[](result.chainOrders.length);

        RebalancingVars memory vars;
        for (; vars.i < params.chainIds.length;) {
            vars.chainsHash = keccak256(abi.encode(vars.chainsHash, params.chainIds[vars.i]));

            vars.priorChain = params.anatomy.chainIdSet.contains(vars.i);
            vars.activeChain = params.newAnatomy.chainIdSet.contains(vars.i);
            if (vars.activeChain || vars.priorChain) {
                if (vars.priorChain) {
                    result.chainOrders[vars.orderIndex].orders =
                        new OrderLib.Order[](params.orderCounts[vars.orderIndex]);
                    result.withdrawals[vars.orderIndex] = IVault.CurrencyWithdrawal(
                        BitSet.create(params.currencies[vars.orderIndex].length),
                        new uint96[](params.anatomy.currencyIdSets[vars.priorChainIndex].size())
                    );
                }

                IVault.CurrencyWithdrawal memory withdrawal = result.withdrawals[vars.orderIndex];

                vars.currenciesHash = bytes32(0);
                Currency[] calldata currencies = params.currencies[vars.orderIndex];
                for (vars.j = 0; vars.j < currencies.length;) {
                    vars.currenciesHash = keccak256(abi.encode(vars.currenciesHash, currencies[vars.j]));
                    vars.priorAsset =
                        vars.priorChain && params.anatomy.currencyIdSets[vars.priorChainIndex].contains(vars.j);

                    vars.targetInBase = vars.activeChain
                        && params.newAnatomy.currencyIdSets[vars.activeChainIndex].contains(vars.j)
                        ? valuationInfo.totalValuation.mulDivUp(params.newWeights[vars.weightIndex++], MAX_WEIGHT)
                        : 0;

                    vars.currentInBase = vars.priorAsset
                        ? valuationInfo.balances[vars.currencyIndex].convertToBaseUp(
                            valuationInfo.prices[vars.currencyIndex]
                        )
                        : 0;

                    if (vars.currentInBase < vars.targetInBase) {
                        uint256 delta = vars.targetInBase - vars.currentInBase;
                        vars.buyDeltas =
                            vars.buyDeltas.push(delta, vars.orderIndex, currencies[vars.j], params.chainIds[vars.i]);
                    } else if (vars.currentInBase > vars.targetInBase) {
                        // result will never exceed type(uint96).max.
                        uint96 assets = uint96(
                            valuationInfo.balances[vars.currencyIndex].mulDivDown(
                                vars.currentInBase - vars.targetInBase, vars.currentInBase
                            )
                        );

                        if (assets != 0) {
                            vars.sellDeltas = vars.sellDeltas.push(
                                vars.currentInBase - vars.targetInBase,
                                assets,
                                vars.orderIndex,
                                currencies[vars.j],
                                valuationInfo.prices[vars.currencyIndex]
                            );

                            withdrawal.amounts[withdrawal.currencyIndexSet.size()] = assets;
                            withdrawal.currencyIndexSet.add(vars.j);
                        }
                    }

                    unchecked {
                        if (vars.priorAsset) ++vars.currencyIndex;
                        ++vars.j;
                    }
                }

                if (vars.currenciesHash != currenciesHashOf[vars.i]) {
                    revert CurrenciesHashMismatch(params.chainIds[vars.i]);
                }

                (vars.sellDeltas, vars.buyDeltas) =
                    _createOrders(result.chainOrders, vars.sellDeltas, vars.buyDeltas, result.counters);

                unchecked {
                    if (vars.priorChain) ++vars.priorChainIndex;
                    if (vars.activeChain) ++vars.activeChainIndex;
                    ++vars.orderIndex;
                }
            }

            unchecked {
                ++vars.i;
            }
        }

        if (params.newWeights.length != vars.weightIndex) revert UnutilizedWeights();
        if (vars.chainsHash != chainsHash) revert ChainsHashMismatch();
    }

    /// @notice Previews the reserve rebalancing orders based on the given parameters
    ///
    /// @param currenciesHashOf The mapping of chain IDs to their currencies hash
    /// @param weights The array of weights for the reserve assets
    /// @param params The start reserve rebalancing parameters
    /// @param reserveAmount The total amount of reserve assets
    /// @param reserve The reserve currency
    /// @param chainsHash The expected hash of the chain IDs
    ///
    /// @return orders The array of chain orders for the reserve rebalancing
    function previewReserveRebalancingOrders(
        mapping(uint256 => bytes32) storage currenciesHashOf,
        uint256[] memory weights,
        IConfigBuilder.StartReserveRebalancingParams calldata params,
        uint96 reserveAmount,
        Currency reserve,
        bytes32 chainsHash
    ) internal view returns (ChainOrders[] memory orders) {
        orders = new ChainOrders[](params.anatomy.chainIdSet.size());

        ReserveRebalancingVars memory vars;
        vars.orderCount = weights.length;
        vars.lastIndex = vars.orderCount - 1;

        orders[0].orders = new OrderLib.Order[](vars.orderCount);

        for (; vars.i < params.chainIds.length; ++vars.i) {
            vars.chainsHash = keccak256(abi.encode(vars.chainsHash, params.chainIds[vars.i]));

            if (!params.anatomy.chainIdSet.contains(vars.i)) continue;

            bytes32 currenciesHash;
            Currency[] calldata currencies = params.currencies[vars.orderIndex];
            for (vars.j = 0; vars.j < currencies.length; ++vars.j) {
                currenciesHash = keccak256(abi.encode(currenciesHash, currencies[vars.j]));

                if (params.anatomy.currencyIdSets[vars.orderIndex].contains(vars.j)) {
                    uint96 orderSellAmount = vars.weightIndex == vars.lastIndex
                        ? reserveAmount - vars.utilized
                        : reserveAmount.mulDivDown(weights[vars.weightIndex], MAX_WEIGHT).safeCastTo96();
                    orders[0].orders[vars.weightIndex] = OrderLib.Order(
                        orderSellAmount,
                        OrderLib.OrderId(reserve, currencies[vars.j], currencies[vars.j], params.chainIds[vars.i])
                    );

                    unchecked {
                        if (vars.orderIndex != 0 && orderSellAmount != 0) {
                            ++orders[vars.orderIndex].incomingOrders;
                        }
                        vars.utilized += orderSellAmount;
                        ++vars.weightIndex;
                    }
                }
            }

            if (currenciesHash != currenciesHashOf[vars.i]) revert CurrenciesHashMismatch(params.chainIds[vars.i]);

            unchecked {
                ++vars.orderIndex;
            }
        }

        if (vars.chainsHash != chainsHash) revert ChainsHashMismatch();
    }

    /// @notice Checks if the total weight is equal to the maximum weight
    ///
    /// @dev This function reverts if the sum of the weights is not equal to MAX_WEIGHT
    ///
    /// @param weights The array of weights to check
    function checkTotalWeight(uint256[] calldata weights) internal pure {
        uint256 total;
        for (uint256 i; i < weights.length; ++i) {
            total += weights[i];
        }
        if (total != MAX_WEIGHT) revert TotalWeight();
    }

    /// @dev Creates the rebalancing orders by matching sell and buy deltas
    ///
    /// @param orders The array of chain orders to populate
    /// @param sellDeltas The stack of sell deltas
    /// @param buyDeltas The stack of buy deltas
    /// @param counters The array of order counters for each chain
    ///
    /// @return The updated sell and buy delta stacks after creating the orders
    function _createOrders(
        ChainOrders[] memory orders,
        StackLib.Node memory sellDeltas,
        StackLib.Node memory buyDeltas,
        uint256[] memory counters
    ) internal pure returns (StackLib.Node memory, StackLib.Node memory) {
        // while one of lists is not empty
        while (sellDeltas.notEmpty() && buyDeltas.notEmpty()) {
            // get first nodes from both lists
            StackLib.Data memory sell = sellDeltas.peek();
            StackLib.Data memory buy = buyDeltas.peek();

            uint256 fill = Math.min(sell.delta, buy.delta);
            sell.delta -= fill;
            buy.delta -= fill;

            uint256 sellAmount = Math.min(fill.convertToAssetsUp(sell.data), sell.availableAssets);
            sell.availableAssets -= sellAmount;

            orders[sell.orderIndex].orders[counters[sell.orderIndex]++] = OrderLib.Order(
                sellAmount.safeCastTo96(), OrderLib.OrderId(sell.currency, buy.currency, buy.currency, buy.data)
            );

            // increment "fence" counter
            if (buy.orderIndex != sell.orderIndex && sellAmount != 0) {
                ++orders[buy.orderIndex].incomingOrders;
            }

            // remove nodes with zero delta. Notice, both deltas can be set to zero.
            if (sell.delta == 0) {
                sellDeltas = sellDeltas.pop();
            }
            if (buy.delta == 0) {
                buyDeltas = buyDeltas.pop();
            }
        }

        return (sellDeltas, buyDeltas);
    }
}

File 8 of 39 : OrderLib.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import {Currency} from "./CurrencyLib.sol";

/// @title OrderLib
/// @notice Library for managing orders
library OrderLib {
    struct OrderId {
        // Sell currency of order
        Currency sellCurrency;
        // Local buy currency of order
        Currency localBuyCurrency;
        // Final destination buy currency of order
        Currency finalDestinationBuyCurrency;
        // Final destination chainId of order
        uint256 finalDestinationChainId;
    }

    struct Order {
        // Sell amount of order
        uint96 sellAmount;
        // Id params of order
        OrderId idParams;
    }

    struct OrderRegistry {
        // Sell amount of given order
        mapping(bytes32 => uint96) orderOf;
        // Hash of registry state
        bytes32 ordersHash;
    }

    /// @notice Emitted when a new order is created
    event NewOrder(
        uint256 sellAmount,
        Currency indexed sellCurrency,
        Currency localBuyCurrency,
        Currency indexed finalDestinationBuyCurrency,
        uint256 finalDestinationChainId
    );

    /// @notice Thrown when there's a mismatch in order hashes
    error OrderHashMismatch();

    /// @notice Thrown when an order is not filled
    /// @param id The id of the order that was not filled
    error OrderNotFilled(bytes32 id);

    /// @notice Sets multiple orders in the registry
    ///
    /// @param self The order registry where orders are stored
    /// @param orders An array of orders to set in the registry
    function set(OrderRegistry storage self, Order[] calldata orders) internal {
        bytes32 newHash = self.ordersHash;
        for (uint256 i; i < orders.length; ++i) {
            if (orders[i].sellAmount == 0) continue;

            OrderId calldata params = orders[i].idParams;
            // don't need to create order for the same currency within a single chain, as it's already in the final destination
            if (params.sellCurrency != params.localBuyCurrency || params.finalDestinationChainId != block.chainid) {
                bytes32 idKey = id(params);
                newHash = keccak256(abi.encode(newHash, idKey));
                self.orderOf[idKey] += orders[i].sellAmount;

                emit NewOrder(
                    orders[i].sellAmount,
                    params.sellCurrency,
                    params.localBuyCurrency,
                    params.finalDestinationBuyCurrency,
                    params.finalDestinationChainId
                );
            }
        }
        self.ordersHash = newHash;
    }

    /// @notice Fills a specific order from the registry
    ///
    /// @param self The order registry
    /// @param orderId The id params of the order to fill
    /// @param sell The sell amount of the order
    function fill(OrderRegistry storage self, OrderId calldata orderId, uint96 sell) internal {
        self.orderOf[id(orderId)] -= sell;
    }

    /// @notice Resets the orders in the registry
    ///
    /// @param self The order registry to reset
    ///
    /// @param orderIds An array of order id parameters to reset
    function reset(OrderRegistry storage self, OrderId[] calldata orderIds) internal {
        bytes32 ordersHash;
        for (uint256 i; i < orderIds.length; ++i) {
            bytes32 idKey = id(orderIds[i]);
            ordersHash = keccak256(abi.encode(ordersHash, idKey));

            if (self.orderOf[idKey] != 0) revert OrderNotFilled(idKey);
        }

        if (ordersHash != self.ordersHash) revert OrderHashMismatch();

        self.ordersHash = bytes32(0);
    }

    /// @notice Retrieves the sell amount of a specific order
    /// @param self The order registry
    ///
    /// @param orderId The id parameters of the order to retrieve
    ///
    /// @return The sell amount of the specified order
    function get(OrderRegistry storage self, OrderId calldata orderId) internal view returns (uint96) {
        return self.orderOf[id(orderId)];
    }

    /// @dev Generates a unique id for an order based on its parameters
    ///
    /// @param self The order id parameters
    ///
    /// @return A unique bytes32 id for the order
    function id(OrderId calldata self) internal pure returns (bytes32) {
        return keccak256(abi.encode(self));
    }
}

File 9 of 39 : OmnichainMessenger.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

import {ICurrencyMetadata} from "./interfaces/ICurrencyMetadata.sol";
import {IOmnichainMessenger} from "./interfaces/IOmnichainMessenger.sol";
import {IOrderBook} from "./interfaces/IOrderBook.sol";
import {IPhutureOnConsumeCallback} from "./interfaces/IPhutureOnConsumeCallback.sol";
import {IStargateReceiver} from "./interfaces/stargate/IStargateReceiver.sol";
import {IStargateRouter} from "./interfaces/stargate/IStargateRouter.sol";
import {IStargateFactory} from "./interfaces/stargate/IStargateFactory.sol";
import {IStargatePool} from "./interfaces/stargate/IStargatePool.sol";
import {IEscrowDeployer} from "./escrow/interfaces/IEscrowDeployer.sol";

import {IVault} from "./interfaces/IVault.sol";

import {Currency, CurrencyLib} from "./libraries/CurrencyLib.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {OrderLib} from "./libraries/OrderLib.sol";
import {SSTORE2} from "sstore2/SSTORE2.sol";
import {SafeCastLib} from "solmate/utils/SafeCastLib.sol";

import {BlockingApp} from "./BlockingApp.sol";

/// @title OmnichainMessenger
/// @notice Base contract for cross-chain messaging and order distribution
abstract contract OmnichainMessenger is
    BlockingApp,
    IStargateReceiver,
    IOmnichainMessenger,
    IPhutureOnConsumeCallback
{
    using CurrencyLib for Currency;
    using FixedPointMathLib for *;
    using SafeCastLib for *;

    /// @dev Struct representing the native currency information
    struct NativeInfo {
        string name;
        string symbol;
        uint8 decimals;
    }

    /// @dev Struct for holding variables used in the `_distributeOrders` function
    struct DistrubuteOrdersVars {
        IStargateFactory factory;
        uint256 lzOptionsIndex;
        uint256 length;
        bytes path;
    }

    /// @dev update currencies hash on home chain
    uint8 internal constant REGISTER_CURRENCY = 0;
    /// @dev if reserve changed we only send redeemedK, recipient and owner to each remote chain
    uint8 internal constant TRANSFER_SNAPSHOT = 1;
    /// @dev once snapshot is transferred to user trading module,
    /// trade batches are sent to each remote chain to swap tokens and send them to home
    uint8 internal constant TRADE_SNAPSHOT = 2;
    /// @dev in the best-case scenario, we send both bodies in one message
    uint8 internal constant TRANSFER_AND_TRADE_SNAPSHOT = 3;
    /// @dev do vault withdrawals, place local orders & increment incoming orders counter by N
    uint8 internal constant START_REBALANCING = 4;
    /// @dev increment incoming orders counter by N
    uint8 internal constant START_RESERVE_REBALANCING = 5;
    /// @dev append builder with remote chain state
    uint8 internal constant FINISH_REBALANCING = 6;
    /// @dev remove dust orders which can't be sent via Stargate
    uint8 internal constant REMOVE_DUST_ORDERS = 7;

    /// @dev Native currency information
    NativeInfo internal nativeInfo;

    /// @dev Address of the Stargate composer contract
    address internal immutable stargateComposer;

    /// @dev Address of the sgETH contract
    address internal immutable sgETH;

    /// @dev Pointer to the bridging info data stored using SSTORE2
    address internal bridgingInfoDataPointer;

    /// @dev Home chain endpoint ID
    uint16 internal immutable homeEid;

    /// @dev Address of the OrderBook contract
    IOrderBook internal orderBook;

    /// @dev Address of the EscrowDeployer contract
    IEscrowDeployer internal escrowDeployer;

    /// @dev Mapping of chain IDs to order hashes
    mapping(uint256 chainid => bytes32 orderHash) internal ordersHashOf;

    /// @notice Event emitted when outgoing orders are distributed
    /// @param orders The bought orders
    /// @param totalBought The total amount bought
    event OutgoingOrders(IOrderBook.BoughtOrder[] orders, uint256 totalBought);

    /// @notice Event emitted when the orders hash for a chain is cleared
    /// @param chainId The ID of the chain
    event OrdersHashClear(uint256 chainId);

    /// @notice Thrown when bridging currency is not found for a destination chain
    /// @param dstChainId The destination chain ID
    error BridgingCurrencyNotFound(uint256 dstChainId);

    /// @notice Thrown when the caller is not allowed to perform the action
    error Forbidden();

    /// @notice Thrown when a query fails
    error QueryFailed();

    /// @notice Thrown when the order hash doesn't match the expected value
    error OrderHashMismatch();

    /// @notice Thrown when trying to set EscrowDeployer with invalid messenger
    error Invalid();

    /// @notice Thrown when trying to set EscrowDeployer after it has been set
    error Set();

    constructor(
        address owner,
        address _stargateComposer,
        address payable _endpoint,
        uint16 _homeEid,
        address _sgETH,
        NativeInfo memory _nativeInfo
    ) BlockingApp(owner, _endpoint) {
        stargateComposer = _stargateComposer;
        homeEid = _homeEid;
        sgETH = _sgETH;

        nativeInfo = _nativeInfo;
    }

    /// @notice Callback function for handling consume currency from Vault
    /// @param data The data passed from the Vault
    function phutureOnConsumeCallbackV1(bytes calldata data) external {}

    /// @notice Sets the address of the EscrowDeployer contract
    /// @param _escrowDeployer The address of the EscrowDeployer contract
    function setEscrowDeployer(address _escrowDeployer) external onlyOwner {
        // prevents setting new EscrowDeployer to protect users' access to escrow
        if (address(escrowDeployer) != address(0)) revert Set();
        if (IEscrowDeployer(_escrowDeployer).messenger() != address(this)) revert Invalid();

        escrowDeployer = IEscrowDeployer(_escrowDeployer);
    }

    /// @notice Sets the address of the OrderBook contract
    /// @param _orderBook The address of the OrderBook contract
    function setOrderBook(address _orderBook) external onlyOwner {
        orderBook = IOrderBook(_orderBook);
    }

    /// @notice Sets the bridging info data
    /// @param _infos The array of BridgingInfo structs
    function setBridgingInfo(BridgingInfo[] calldata _infos) external onlyOwner {
        bridgingInfoDataPointer = SSTORE2.write(abi.encode(_infos));
    }

    /// @notice Withdraws the specified amount of currency to the given address
    ///
    /// @param currency The currency to withdraw
    /// @param to The recipient address
    /// @param amount The amount to withdraw
    function withdrawCurrency(Currency currency, address to, uint256 amount) external onlyOwner {
        currency.transfer(to, amount);
    }

    /// @notice Receives tokens from Stargate
    ///
    /// @param srcEid The source endpoint ID
    /// @param srcAddress The source address
    /// @param token The address of the token received
    /// @param amountLD The amount received in local decimals
    /// @param payload Additional data passed with the transfer
    function sgReceive(
        uint16 srcEid,
        bytes calldata srcAddress,
        uint256,
        address token,
        uint256 amountLD,
        bytes calldata payload
    ) external {
        if (!(msg.sender == stargateComposer || msg.sender == allowedCaller)) revert Forbidden();
        if (keccak256(abi.encodePacked(srcAddress, address(this))) != keccak256(trustedRemotes[srcEid])) return;

        Currency currency = token == sgETH ? CurrencyLib.NATIVE : Currency.wrap(token);

        (bytes32 ordersHash, uint256 chainId) = abi.decode(payload, (bytes32, uint256));
        ordersHashOf[chainId] = keccak256(abi.encode(ordersHash, currency, amountLD));

        currency.transfer(address(orderBook), amountLD);
    }

    /// @notice Pushes the incoming orders to the OrderBook contract
    ///
    /// @param srcChainId The source chain ID
    /// @param boughtOrders The array of bought orders
    /// @param boughtOrdersTotalAmount The total amount of bought orders
    /// @param currency The currency of the bought orders
    /// @param receivedAmount The amount received from Stargate
    function pushIncomingOrders(
        uint256 srcChainId,
        IOrderBook.BoughtOrder[] calldata boughtOrders,
        uint256 boughtOrdersTotalAmount,
        Currency currency,
        uint256 receivedAmount
    ) external {
        if (
            keccak256(
                abi.encode(keccak256(abi.encode(boughtOrders, boughtOrdersTotalAmount)), currency, receivedAmount)
            ) != ordersHashOf[srcChainId]
        ) revert OrderHashMismatch();

        delete ordersHashOf[srcChainId];
        emit OrdersHashClear(srcChainId);

        OrderLib.Order[] memory orders = new OrderLib.Order[](boughtOrders.length);
        uint256 lastIndex = boughtOrders.length - 1;
        uint256 utilized;
        for (uint256 i; i <= lastIndex; i++) {
            uint96 sellAmount = i == lastIndex
                ? (receivedAmount - utilized).safeCastTo96()
                : boughtOrders[i].amount.mulDivDown(receivedAmount, boughtOrdersTotalAmount).safeCastTo96();

            orders[i] = OrderLib.Order({
                sellAmount: sellAmount,
                idParams: OrderLib.OrderId({
                    sellCurrency: currency,
                    localBuyCurrency: boughtOrders[i].buyCurrency,
                    finalDestinationBuyCurrency: boughtOrders[i].buyCurrency,
                    finalDestinationChainId: block.chainid
                })
            });

            unchecked {
                utilized += sellAmount;
            }
        }

        orderBook.receiveIncomingOrders(orders, currency, receivedAmount);
    }

    function getBridgingInfo() external view returns (BridgingInfo[] memory) {
        return abi.decode(SSTORE2.read(bridgingInfoDataPointer), (BridgingInfo[]));
    }

    /// @dev Distributes the pending orders to remote chains using Stargate
    /// @param pendingOrders The array of pending orders
    /// @param sgParams The array of Stargate parameters
    /// @param lzParams The LayerZero parameters
    function _distributeOrders(
        IOrderBook.PendingOrder[] memory pendingOrders,
        SgParams[] calldata sgParams,
        LzParams calldata lzParams
    ) internal {
        DistrubuteOrdersVars memory vars;
        vars.factory = IStargateFactory(IStargateRouter(stargateComposer).factory());

        vars.length = pendingOrders.length;
        for (uint256 i; i < vars.length; ++i) {
            IOrderBook.PendingOrder memory pendingOrder = pendingOrders[i];

            uint16 dstEid = eIds[pendingOrder.chainId];

            vars.path = _getPathOrRevert(dstEid);

            PoolIds memory sgPoolIds = poolIds[pendingOrder.chainId];
            if (pendingOrder.totalBought >= IStargatePool(vars.factory.getPool(sgPoolIds.src)).convertRate()) {
                SgParams calldata sgParam = sgParams[i - vars.lzOptionsIndex];

                emit OutgoingOrders(pendingOrder.orders, pendingOrder.totalBought);
                bytes memory payload =
                    abi.encode(keccak256(abi.encode(pendingOrder.orders, pendingOrder.totalBought)), block.chainid);

                bytes memory to = bytes.concat(bytes20(vars.path));
                (uint256 sgMessageFee,) =
                    IStargateRouter(stargateComposer).quoteLayerZeroFee(dstEid, 1, to, payload, sgParam.lzTxObj);

                if (pendingOrder.currency.isNative()) sgMessageFee += pendingOrder.totalBought;

                pendingOrder.currency.approve(stargateComposer, pendingOrder.totalBought);

                IStargateRouter(stargateComposer).swap{value: sgMessageFee}(
                    dstEid,
                    sgPoolIds.src,
                    sgPoolIds.dst,
                    payable(address(this)),
                    pendingOrder.totalBought,
                    sgParam.minAmountLD,
                    sgParam.lzTxObj,
                    to,
                    payload
                );

                pendingOrder.currency.approve(stargateComposer, 0);
            } else {
                _lzSend(
                    dstEid,
                    vars.path,
                    abi.encode(REMOVE_DUST_ORDERS, pendingOrder.orders.length),
                    payable(address(this)),
                    lzParams.zroPaymentAddress,
                    lzParams.options[vars.lzOptionsIndex++]
                );
            }
        }
    }

    /// @dev Injects the local buy currency into the orders based on the bridging info
    ///
    /// @param orders The array of orders
    function _injectLocalBuyCurrency(OrderLib.Order[] memory orders) internal view {
        BridgingInfo[] memory bridgingInfo = abi.decode(SSTORE2.read(bridgingInfoDataPointer), (BridgingInfo[]));
        for (uint256 i; i < orders.length; ++i) {
            uint256 finalDestinationChainId = orders[i].idParams.finalDestinationChainId;
            if (finalDestinationChainId != block.chainid) {
                bool bridgingCurrencyFound;
                for (uint256 j; j < bridgingInfo.length; ++j) {
                    if (finalDestinationChainId == bridgingInfo[j].finalDstChainId) {
                        bridgingCurrencyFound = true;
                        orders[i].idParams.localBuyCurrency = bridgingInfo[j].localCurrency;
                        break;
                    }
                }

                if (!bridgingCurrencyFound) revert BridgingCurrencyNotFound(finalDestinationChainId);
            }
        }
    }

    /// @dev Fills the metadata for registered currencies
    ///
    /// @param info The RegisterCurrenciesResult from the Vault contract
    ///
    /// @return result The filled RegisteredMetadata struct
    function _fillCurrenciesMetadata(IVault.RegisterCurrenciesResult calldata info)
        internal
        view
        returns (ICurrencyMetadata.RegisteredMetadata memory result)
    {
        result.currenciesHash = info.currenciesHash;
        result.chainId = block.chainid;
        result.metadata = new ICurrencyMetadata.CurrencyMetadata[](info.currencies.length);
        for (uint256 i; i < info.currencies.length; ++i) {
            Currency currency = info.currencies[i];
            if (currency.isNative()) {
                NativeInfo memory _info = nativeInfo;
                result.metadata[i] =
                    ICurrencyMetadata.CurrencyMetadata(_info.name, _info.symbol, _info.decimals, currency);
            } else {
                result.metadata[i] = ICurrencyMetadata.CurrencyMetadata(
                    _queryStringOrBytes32(Currency.unwrap(currency), IERC20Metadata.name.selector),
                    _queryStringOrBytes32(Currency.unwrap(currency), IERC20Metadata.symbol.selector),
                    IERC20Metadata(Currency.unwrap(currency)).decimals(),
                    currency
                );
            }
        }
    }

    /// @dev Queries a string or bytes32 value from a target contract
    ///
    /// @param target The address of the target contract
    /// @param selector The function selector to call
    ///
    /// @return s The queried string value
    function _queryStringOrBytes32(address target, bytes4 selector) internal view returns (string memory s) {
        (bool success, bytes memory returndata) = target.staticcall(abi.encodeWithSelector(selector));
        if (!success) revert QueryFailed();

        if (returndata.length != 32) return abi.decode(returndata, (string));

        s = string(returndata);

        // Find last non-zero byte
        uint256 length = 32;
        for (; length != 0; length--) {
            if (returndata[length - 1] != 0) break;
        }

        // Shorten length of string
        assembly {
            mstore(s, length)
        }
    }
}

File 10 of 39 : CurrencyLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

type Currency is address;

using {eq as ==, neq as !=} for Currency global;

function eq(Currency currency, Currency other) pure returns (bool) {
    return Currency.unwrap(currency) == Currency.unwrap(other);
}

function neq(Currency currency, Currency other) pure returns (bool) {
    return !eq(currency, other);
}

/// @title CurrencyLibrary
/// @dev This library allows for transferring and holding native tokens and ERC20 tokens
/// @author Modified from Uniswap (https://github.com/Uniswap/v4-core/blob/main/src/types/Currency.sol)
library CurrencyLib {
    using SafeERC20 for IERC20;
    using CurrencyLib for Currency;

    /// @dev Currency wrapper for native currency
    Currency public constant NATIVE = Currency.wrap(address(0));

    /// @notice Thrown when a native transfer fails
    error NativeTransferFailed();

    /// @notice Thrown when an ERC20 transfer fails
    error ERC20TransferFailed();

    /// @notice Thrown when deposit amount exceeds current balance
    error AmountExceedsBalance();

    /// @notice Transfers currency
    ///
    /// @param currency Currency to transfer
    /// @param to Address of recipient
    /// @param amount Currency amount ot transfer
    function transfer(Currency currency, address to, uint256 amount) internal {
        if (amount == 0) return;
        // implementation from
        // https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol

        bool success;
        if (currency.isNative()) {
            assembly {
                // Transfer the ETH and store if it succeeded or not.
                success := call(gas(), to, amount, 0, 0, 0, 0)
            }

            if (!success) revert NativeTransferFailed();
        } else {
            assembly {
                // We'll write our calldata to this slot below, but restore it later.
                let freeMemoryPointer := mload(0x40)

                // Write the abi-encoded calldata into memory, beginning with the function selector.
                mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
                mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
                mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

                success :=
                    and(
                        // Set success to whether the call reverted, if not we check it either
                        // returned exactly 1 (can't just be non-zero data), or had no return data.
                        or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                        // We use 68 because that's the total length of our calldata (4 + 32 * 2)
                        // Counterintuitively, this call() must be positioned after the or() in the
                        // surrounding and() because and() evaluates its arguments from right to left.
                        call(gas(), currency, 0, freeMemoryPointer, 68, 0, 32)
                    )
            }

            if (!success) revert ERC20TransferFailed();
        }
    }

    /// @notice Approves currency
    ///
    /// @param currency Currency to approve
    /// @param spender Address of spender
    /// @param amount Currency amount to approve
    function approve(Currency currency, address spender, uint256 amount) internal {
        if (isNative(currency)) return;
        IERC20(Currency.unwrap(currency)).forceApprove(spender, amount);
    }

    /// @notice Returns the balance of a given currency for a specific account
    ///
    /// @param currency The currency to check
    /// @param account The address of the account
    ///
    /// @return The balance of the specified currency for the given account
    function balanceOf(Currency currency, address account) internal view returns (uint256) {
        return currency.isNative() ? account.balance : IERC20(Currency.unwrap(currency)).balanceOf(account);
    }

    /// @notice Returns the balance of a given currency for this contract
    ///
    /// @param currency The currency to check
    ///
    /// @return The balance of the specified currency for this contract
    function balanceOfSelf(Currency currency) internal view returns (uint256) {
        return currency.isNative() ? address(this).balance : IERC20(Currency.unwrap(currency)).balanceOf(address(this));
    }

    /// @notice Checks if the specified currency is the native currency
    ///
    /// @param currency The currency to check
    ///
    /// @return `true` if the specified currency is the native currency, `false` otherwise
    function isNative(Currency currency) internal pure returns (bool) {
        return currency == NATIVE;
    }
}

File 11 of 39 : IOmnichainMessenger.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {IOrderBook} from "./IOrderBook.sol";
import {IVault} from "./IVault.sol";
import {IStargateRouter} from "./stargate/IStargateRouter.sol";

import {Currency} from "../libraries/CurrencyLib.sol";

interface IOmnichainMessenger {
    struct BridgingInfo {
        uint256 finalDstChainId;
        Currency localCurrency;
    }

    struct HashedResult {
        uint256 chainId;
        bytes32 hash;
    }

    struct LzParams {
        bytes[] options;
        address zroPaymentAddress;
    }

    struct SgParams {
        IStargateRouter.lzTxObj lzTxObj;
        uint256 minAmountLD;
    }

    function withdrawCurrency(Currency currency, address to, uint256 amount) external;

    function setOrderBook(address orderBook) external;
    function setEscrowDeployer(address escrowDeployer) external;

    function setBridgingInfo(BridgingInfo[] calldata _infos) external;

    function pushIncomingOrders(
        uint256 srcChainId,
        IOrderBook.BoughtOrder[] memory boughtOrders,
        uint256 boughtOrdersTotalAmount,
        Currency currency,
        uint256 receivedAmount
    ) external;

    function finishVaultRebalancing(
        IOrderBook.FinishOrderExecutionParams calldata orderBookParams,
        IVault.EndRebalancingParams calldata params,
        SgParams[] calldata sgParams,
        LzParams calldata lzParams,
        address payable refundAddress
    ) external payable;
}

File 12 of 39 : a160u96.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.23;

import {Currency} from "../libraries/CurrencyLib.sol";

type a160u96 is uint256;

using {addr, unpack, unpackRaw, currency, value, eq as ==, neq as !=} for a160u96 global;

error AddressMismatch(address, address);

function neq(a160u96 a, a160u96 b) pure returns (bool) {
    return !eq(a, b);
}

function eq(a160u96 a, a160u96 b) pure returns (bool) {
    return a160u96.unwrap(a) == a160u96.unwrap(b);
}

function currency(a160u96 packed) pure returns (Currency) {
    return Currency.wrap(addr(packed));
}

function addr(a160u96 packed) pure returns (address) {
    return address(uint160(a160u96.unwrap(packed)));
}

function value(a160u96 packed) pure returns (uint96) {
    return uint96(a160u96.unwrap(packed) >> 160);
}

function unpack(a160u96 packed) pure returns (Currency _curr, uint96 _value) {
    uint256 raw = a160u96.unwrap(packed);
    _curr = Currency.wrap(address(uint160(raw)));
    _value = uint96(raw >> 160);
}

function unpackRaw(a160u96 packed) pure returns (address _addr, uint96 _value) {
    uint256 raw = a160u96.unwrap(packed);
    _addr = address(uint160(raw));
    _value = uint96(raw >> 160);
}

library A160U96Factory {
    function create(address _addr, uint96 _value) internal pure returns (a160u96) {
        return a160u96.wrap((uint256(_value) << 160) | uint256(uint160(_addr)));
    }

    function create(Currency _currency, uint96 _value) internal pure returns (a160u96) {
        return create(Currency.unwrap(_currency), _value);
    }
}

File 13 of 39 : SafeCastLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Safe unsigned integer casting library that reverts on overflow.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
    function safeCastTo248(uint256 x) internal pure returns (uint248 y) {
        require(x < 1 << 248);

        y = uint248(x);
    }

    function safeCastTo240(uint256 x) internal pure returns (uint240 y) {
        require(x < 1 << 240);

        y = uint240(x);
    }

    function safeCastTo232(uint256 x) internal pure returns (uint232 y) {
        require(x < 1 << 232);

        y = uint232(x);
    }

    function safeCastTo224(uint256 x) internal pure returns (uint224 y) {
        require(x < 1 << 224);

        y = uint224(x);
    }

    function safeCastTo216(uint256 x) internal pure returns (uint216 y) {
        require(x < 1 << 216);

        y = uint216(x);
    }

    function safeCastTo208(uint256 x) internal pure returns (uint208 y) {
        require(x < 1 << 208);

        y = uint208(x);
    }

    function safeCastTo200(uint256 x) internal pure returns (uint200 y) {
        require(x < 1 << 200);

        y = uint200(x);
    }

    function safeCastTo192(uint256 x) internal pure returns (uint192 y) {
        require(x < 1 << 192);

        y = uint192(x);
    }

    function safeCastTo184(uint256 x) internal pure returns (uint184 y) {
        require(x < 1 << 184);

        y = uint184(x);
    }

    function safeCastTo176(uint256 x) internal pure returns (uint176 y) {
        require(x < 1 << 176);

        y = uint176(x);
    }

    function safeCastTo168(uint256 x) internal pure returns (uint168 y) {
        require(x < 1 << 168);

        y = uint168(x);
    }

    function safeCastTo160(uint256 x) internal pure returns (uint160 y) {
        require(x < 1 << 160);

        y = uint160(x);
    }

    function safeCastTo152(uint256 x) internal pure returns (uint152 y) {
        require(x < 1 << 152);

        y = uint152(x);
    }

    function safeCastTo144(uint256 x) internal pure returns (uint144 y) {
        require(x < 1 << 144);

        y = uint144(x);
    }

    function safeCastTo136(uint256 x) internal pure returns (uint136 y) {
        require(x < 1 << 136);

        y = uint136(x);
    }

    function safeCastTo128(uint256 x) internal pure returns (uint128 y) {
        require(x < 1 << 128);

        y = uint128(x);
    }

    function safeCastTo120(uint256 x) internal pure returns (uint120 y) {
        require(x < 1 << 120);

        y = uint120(x);
    }

    function safeCastTo112(uint256 x) internal pure returns (uint112 y) {
        require(x < 1 << 112);

        y = uint112(x);
    }

    function safeCastTo104(uint256 x) internal pure returns (uint104 y) {
        require(x < 1 << 104);

        y = uint104(x);
    }

    function safeCastTo96(uint256 x) internal pure returns (uint96 y) {
        require(x < 1 << 96);

        y = uint96(x);
    }

    function safeCastTo88(uint256 x) internal pure returns (uint88 y) {
        require(x < 1 << 88);

        y = uint88(x);
    }

    function safeCastTo80(uint256 x) internal pure returns (uint80 y) {
        require(x < 1 << 80);

        y = uint80(x);
    }

    function safeCastTo72(uint256 x) internal pure returns (uint72 y) {
        require(x < 1 << 72);

        y = uint72(x);
    }

    function safeCastTo64(uint256 x) internal pure returns (uint64 y) {
        require(x < 1 << 64);

        y = uint64(x);
    }

    function safeCastTo56(uint256 x) internal pure returns (uint56 y) {
        require(x < 1 << 56);

        y = uint56(x);
    }

    function safeCastTo48(uint256 x) internal pure returns (uint48 y) {
        require(x < 1 << 48);

        y = uint48(x);
    }

    function safeCastTo40(uint256 x) internal pure returns (uint40 y) {
        require(x < 1 << 40);

        y = uint40(x);
    }

    function safeCastTo32(uint256 x) internal pure returns (uint32 y) {
        require(x < 1 << 32);

        y = uint32(x);
    }

    function safeCastTo24(uint256 x) internal pure returns (uint24 y) {
        require(x < 1 << 24);

        y = uint24(x);
    }

    function safeCastTo16(uint256 x) internal pure returns (uint16 y) {
        require(x < 1 << 16);

        y = uint16(x);
    }

    function safeCastTo8(uint256 x) internal pure returns (uint8 y) {
        require(x < 1 << 8);

        y = uint8(x);
    }
}

File 14 of 39 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 15 of 39 : BitSet.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

/// @title BitSet
/// @notice A library for managing bitsets
library BitSet {
    uint256 private constant WORD_SHIFT = 8;

    /// @notice Checks if the next bit is set in the given word starting from the given bit position
    ///
    /// @param word The word to check
    /// @param bit The bit position
    ///
    /// @return r True if the next bit is set, false otherwise
    function hasNext(uint256 word, uint256 bit) internal pure returns (bool r) {
        assembly ("memory-safe") {
            r := and(shr(bit, word), 1)
        }
    }

    /// @notice Finds the position of the next set bit in the given word starting from the given bit position
    ///
    /// @dev This function uses a lookup table approach to find the position of the next set bit.
    ///      It first shifts the word right by the given bit position and then checks the lower 3 bits
    ///      of the resulting word to determine the position of the next set bit.
    ///      If no set bit is found, it returns 256 to indicate that there are no more set bits.
    ///
    /// @param word The word to search
    /// @param b The starting bit position
    ///
    /// @return nb The position of the next set bit
    function find(uint256 word, uint256 b) internal pure returns (uint256 nb) {
        assembly ("memory-safe") {
            let w := shr(b, word)
            switch w
            case 0 {
                // no more bits
                nb := 256
            }
            default {
                // 0b000 = 0
                // 0b001 = 1
                // 0b010 = 2
                // 0b011 = 3
                // 0b100 = 4
                // 0b101 = 5
                // 0b110 = 6
                // 0b111 = 7
                switch and(w, 7)
                case 0 { nb := add(lsb(w), b) }
                case 2 { nb := add(b, 1) }
                case 4 { nb := add(b, 2) }
                case 6 { nb := add(b, 1) }
                default { nb := b }
            }

            function lsb(x) -> r {
                if iszero(x) { revert(0, 0) }
                r := 255
                switch gt(and(x, 0xffffffffffffffffffffffffffffffff), 0)
                case 1 { r := sub(r, 128) }
                case 0 { x := shr(128, x) }

                switch gt(and(x, 0xffffffffffffffff), 0)
                case 1 { r := sub(r, 64) }
                case 0 { x := shr(64, x) }

                switch gt(and(x, 0xffffffff), 0)
                case 1 { r := sub(r, 32) }
                case 0 { x := shr(32, x) }

                switch gt(and(x, 0xffff), 0)
                case 1 { r := sub(r, 16) }
                case 0 { x := shr(16, x) }

                switch gt(and(x, 0xff), 0)
                case 1 { r := sub(r, 8) }
                case 0 { x := shr(8, x) }

                switch gt(and(x, 0xf), 0)
                case 1 { r := sub(r, 4) }
                case 0 { x := shr(4, x) }

                switch gt(and(x, 0x3), 0)
                case 1 { r := sub(r, 2) }
                case 0 { x := shr(2, x) }

                switch gt(and(x, 0x1), 0)
                case 1 { r := sub(r, 1) }
            }
        }
    }

    /// @notice Computes the value at the given word index and bit position
    ///
    /// @param wordIndex The index of the word
    /// @param bit The bit position within the word
    ///
    /// @return r The computed value
    function valueAt(uint256 wordIndex, uint256 bit) internal pure returns (uint256 r) {
        assembly ("memory-safe") {
            r := or(shl(8, wordIndex), bit)
        }
    }

    /// @notice Creates a new bitset with the given maximum size
    ///
    /// @param maxSize The maximum size of the bitset
    ///
    /// @return bitset The created bitset
    function create(uint256 maxSize) internal pure returns (uint256[] memory bitset) {
        bitset = new uint256[](_capacity(maxSize));
    }

    /// @notice Checks if the given value is contained in the bitset
    ///
    /// @param bitset The bitset to check
    /// @param value The value to search for
    ///
    /// @return _contains True if the value is contained in the bitset, false otherwise
    function contains(uint256[] memory bitset, uint256 value) internal pure returns (bool _contains) {
        (uint256 wordIndex, uint8 bit) = _bitOffset(value);
        if (wordIndex < bitset.length) {
            _contains = (bitset[wordIndex] & (1 << bit)) != 0;
        }
    }

    /// @notice Adds the given value to the bitset
    ///
    /// @param bitset The bitset to modify
    /// @param value The value to add
    ///
    /// @return The modified bitset
    function add(uint256[] memory bitset, uint256 value) internal pure returns (uint256[] memory) {
        (uint256 wordIndex, uint8 bit) = _bitOffset(value);
        bitset[wordIndex] |= (1 << bit);
        return bitset;
    }

    /// @notice Adds all elements from bitset b to bitset a
    ///
    /// @param a The destination bitset
    /// @param b The source bitset
    ///
    /// @return c The resulting bitset
    function addAll(uint256[] memory a, uint256[] memory b) internal pure returns (uint256[] memory c) {
        (uint256 min, uint256 max) = a.length < b.length ? (a.length, b.length) : (b.length, a.length);
        c = new uint256[](max);
        uint256 i;
        for (; i < min; ++i) {
            c[i] = a[i] | b[i];
        }
        // copy leftover elements from a
        for (; i < a.length; ++i) {
            c[i] = a[i];
        }
        // copy leftover elements from b
        for (; i < b.length; ++i) {
            c[i] = b[i];
        }
    }

    /// @notice Removes the given value from the bitset
    ///
    /// @param bitset The bitset to modify
    /// @param value The value to remove
    ///
    /// @return The modified bitset
    function remove(uint256[] memory bitset, uint256 value) internal pure returns (uint256[] memory) {
        (uint256 wordIndex, uint8 bit) = _bitOffset(value);
        bitset[wordIndex] &= ~(1 << bit);
        return bitset;
    }

    /// @notice Computes the size (number of set bits) of the bitset
    ///
    /// @param bitset The bitset to compute the size of
    ///
    /// @return count The number of set bits in the bitset
    function size(uint256[] memory bitset) internal pure returns (uint256 count) {
        for (uint256 i; i < bitset.length; ++i) {
            count += _countSetBits(bitset[i]);
        }
    }

    /// @dev Computes the word index and bit position for the given value
    ///
    /// @param value The value to compute the offsets for
    ///
    /// @return wordIndex The index of the word containing the value
    /// @return bit The bit position within the word
    function _bitOffset(uint256 value) private pure returns (uint256 wordIndex, uint8 bit) {
        assembly ("memory-safe") {
            wordIndex := shr(8, value)
            // mask bits that don't fit the first wordIndex's bits
            // n % 2^i = n & (2^i - 1)
            bit := and(value, 255)
        }
    }

    /// @dev Computes the number of words required to store the given maximum size
    ///
    /// @param maxSize The maximum size of the bitset
    ///
    /// @return words The number of words required
    function _capacity(uint256 maxSize) private pure returns (uint256 words) {
        // round up
        words = (maxSize + type(uint8).max) >> WORD_SHIFT;
    }

    /// @dev Counts the number of set bits in the given word using Brian Kernighan's algorithm
    ///
    /// @param x The word to count the set bits of
    ///
    /// @return count The number of set bits in the word
    function _countSetBits(uint256 x) private pure returns (uint256 count) {
        // Brian Kernighan's Algorithm
        // This algorithm counts the number of set bits in a word by repeatedly
        // clearing the least significant set bit until the word becomes zero.
        while (x != 0) {
            unchecked {
                // cannot overflow, x > 0
                x = x & (x - 1);
                ++count;
            }
        }
    }
}

File 16 of 39 : FixedPointMathLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

File 17 of 39 : PriceLib.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.23;

import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";

/// @title PriceLib
/// @notice A library for handling fixed-point arithmetic for prices
library PriceLib {
    using FixedPointMathLib for uint256;

    /// @dev 2**128
    uint256 internal constant Q128 = 0x100000000000000000000000000000000;
    uint16 internal constant PRICE_ORACLE_DECIMALS = 18;
    uint256 internal constant DECIMALS_MULTIPLIER = 10 ** PRICE_ORACLE_DECIMALS;

    /// @notice Converts (down) an amount in base units to an amount in asset units based on a fixed-price value
    /// @param base The amount to convert in base units
    /// @param price The fixed-price value represented as a uint256
    /// @return The equivalent amount in asset units
    function convertToAssetsDown(uint256 base, uint256 price) internal pure returns (uint256) {
        return base.mulDivDown(price, Q128);
    }

    /// @notice Converts (up) an amount in base units to an amount in asset units based on a fixed-price value
    /// @param base The amount to convert in base units
    /// @param price The fixed-price value represented as a uint256
    /// @return The equivalent amount in asset units
    function convertToAssetsUp(uint256 base, uint256 price) internal pure returns (uint256) {
        return base.mulDivUp(price, Q128);
    }

    /// @notice Converts (down) an amount in asset units to an amount in base units based on a fixed-price value
    /// @param assets The amount to convert in asset units
    /// @param price The fixed-price value represented as a uint256
    /// @return The equivalent amount in base units
    function convertToBaseDown(uint256 assets, uint256 price) internal pure returns (uint256) {
        return assets.mulDivDown(Q128, price);
    }

    /// @notice Converts (up) an amount in asset units to an amount in base units based on a fixed-price value
    /// @param assets The amount to convert in asset units
    /// @param price The fixed-price value represented as a uint256
    /// @return The equivalent amount in base units
    function convertToBaseUp(uint256 assets, uint256 price) internal pure returns (uint256) {
        return assets.mulDivUp(Q128, price);
    }
}

File 18 of 39 : StackLib.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.23;

import {Currency} from "./CurrencyLib.sol";

/// @title StackLib
/// @notice A library for managing a stack data
library StackLib {
    /// @dev Represents the data held in each stack node
    struct Data {
        // Index of order
        uint256 orderIndex;
        // Currency of order
        Currency currency;
        // Amount of order
        uint256 delta;
        // `price` for sell, `chainId` for buy
        uint256 data;
        // Available asset for sell data, 0 for buy data
        uint256 availableAssets;
    }

    /// @dev Represents a node in the stack
    struct Node {
        // Pointer to the next node
        uint256 next;
        // Value of the node
        Data value;
    }

    /// @notice Pushes a new sell order onto the stack
    ///
    /// @param head The current head of the stack
    /// @param delta The delta value of the order
    /// @param availableAssets The number of assets available for selling
    /// @param orderIndex The index of the order
    /// @param currency The currency used in the order
    /// @param price The price of the assets in the order
    ///
    /// @return newNode The new node created with the given data
    function push(
        Node memory head,
        uint256 delta,
        uint256 availableAssets,
        uint256 orderIndex,
        Currency currency,
        uint256 price
    ) internal pure returns (Node memory newNode) {
        newNode.value = Data(orderIndex, currency, delta, price, availableAssets);

        assembly {
            // Store the address of the current head in the new node's 'next'
            mstore(newNode, head)
        }
    }

    /// @notice Pushes a new buy order onto the stack
    ///
    /// @param head The current head of the stack
    /// @param delta The delta value of the order
    /// @param orderIndex The index of the order
    /// @param currency The currency used in the order
    /// @param chainId The chain ID associated with the buy order
    ///
    /// @return newNode The new node created with the given data
    function push(Node memory head, uint256 delta, uint256 orderIndex, Currency currency, uint256 chainId)
        internal
        pure
        returns (Node memory newNode)
    {
        newNode.value = Data(orderIndex, currency, delta, chainId, 0);

        assembly {
            // Store the address of the current head in the new node's 'next'
            mstore(newNode, head)
        }
    }

    /// @notice Pops the top value from the stack
    ///
    /// @param head The current head of the stack
    ///
    /// @return nextNode The next node in the stack after popping
    function pop(Node memory head) internal pure returns (Node memory nextNode) {
        assembly {
            // Load the address of the next node (which head points to)
            nextNode := mload(head)
        }
    }

    /// @notice Checks if the stack is not empty
    ///
    /// @param head The head of the stack to check
    ///
    /// @return `true` if the stack is not empty, `false` otherwise
    function notEmpty(Node memory head) internal pure returns (bool) {
        return head.next != 0 || head.value.delta != 0;
    }

    /// @notice Retrieves the value of the top node of the stack
    ///
    /// @param head The head of the stack
    ///
    /// @return The data value of the top node of the stack
    function peek(Node memory head) internal pure returns (Data memory) {
        return head.value;
    }
}

File 19 of 39 : IConfigBuilder.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {IIndex} from "./IIndex.sol";
import {IVault} from "./IVault.sol";
import {ICurrencyMetadata} from "./ICurrencyMetadata.sol";

import {Currency} from "../libraries/CurrencyLib.sol";

interface IConfigBuilder {
    struct Anatomy {
        uint256[] chainIdSet;
        uint256[][] currencyIdSets;
    }

    struct SharedConfig {
        uint256 AUMDilutionPerSecond;
        bool useCustomAUMFee;
        address metadata;
    }

    struct FeeConfig {
        uint16 BPs;
        bool useCustomCallback;
    }

    struct Config {
        SharedConfig shared;
        FeeConfig depositFee;
        FeeConfig redemptionFee;
    }

    struct StartReserveRebalancingParams {
        Anatomy anatomy;
        uint256[] chainIds;
        Currency[][] currencies;
    }

    struct StartRebalancingParams {
        Anatomy anatomy;
        Anatomy newAnatomy;
        uint256[] chainIds;
        Currency[][] currencies;
        uint256[] newWeights;
        uint256[] orderCounts; // count of orders for current anatomy chains
        bytes payload;
    }

    function startRebalancing(StartRebalancingParams calldata params, bytes calldata data) external payable;

    function startReserveRebalancing(StartReserveRebalancingParams calldata params, bytes calldata data)
        external
        payable;

    function finishRebalancing(IVault.RebalancingResult[] calldata results, IConfigBuilder.Config calldata config)
        external
        returns (IIndex.DepositConfig memory deposit, IIndex.RedemptionConfig memory redemption);

    function chainRebalancingFinished(uint256 chainId, bytes32 resultHash) external;

    function currenciesUpdated(ICurrencyMetadata.RegisteredMetadata calldata result) external;

    function registerChain(uint256 chainId) external;

    function setMessenger(address _messenger) external;

    function setConfig(IConfigBuilder.Config memory _config)
        external
        returns (IIndex.DepositConfig memory deposit, IIndex.RedemptionConfig memory redemption);

    function configs(Config calldata _config)
        external
        view
        returns (IIndex.DepositConfig memory deposit, IIndex.RedemptionConfig memory redemption);

    function configHash() external view returns (bytes32);
}

File 20 of 39 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 21 of 39 : ICurrencyMetadata.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {Currency} from "../libraries/CurrencyLib.sol";

interface ICurrencyMetadata {
    struct RegisteredMetadata {
        uint256 chainId;
        CurrencyMetadata[] metadata;
        bytes32 currenciesHash;
    }

    struct CurrencyMetadata {
        string name;
        string symbol;
        uint8 decimals;
        Currency currency;
    }
}

File 22 of 39 : IPhutureOnConsumeCallback.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface IPhutureOnConsumeCallback {
    function phutureOnConsumeCallbackV1(bytes calldata data) external;
}

File 23 of 39 : IStargateReceiver.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface IStargateReceiver {
    function sgReceive(
        uint16 _eid,
        bytes memory _srcAddress,
        uint256 _nonce,
        address _token,
        uint256 amountLD,
        bytes memory payload
    ) external;
}

File 24 of 39 : IStargateRouter.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface IStargateRouter {
    struct lzTxObj {
        uint256 dstGasForCall; // extra gas, if calling smart contract,
        uint256 dstNativeAmount; // amount of dust dropped in destination wallet
        bytes dstNativeAddr; // destination wallet for dust
    }

    function swap(
        uint16 _dstEid,
        uint256 _srcPoolId,
        uint256 _dstPoolId,
        address payable _refundAddress,
        uint256 _amountLD,
        uint256 _minAmountLD,
        lzTxObj memory _lzTxParams,
        bytes calldata _to,
        bytes calldata _payload
    ) external payable;

    function quoteLayerZeroFee(
        uint16 _dstEid,
        uint8 _functionType,
        bytes calldata _toAddress,
        bytes calldata _transferAndCallPayload,
        lzTxObj memory _lzTxParams
    ) external view returns (uint256, uint256);

    function factory() external view returns (address);
}

File 25 of 39 : IStargateFactory.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface IStargateFactory {
    function getPool(uint256 poolId) external view returns (address);
}

File 26 of 39 : IStargatePool.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

interface IStargatePool {
    function convertRate() external view returns (uint256);
}

File 27 of 39 : SSTORE2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./utils/Bytecode.sol";

/**
  @title A key-value storage with auto-generated keys for storing chunks of data with a lower write & read cost.
  @author Agustin Aguilar <[email protected]>

  Readme: https://github.com/0xsequence/sstore2#readme
*/
library SSTORE2 {
  error WriteError();

  /**
    @notice Stores `_data` and returns `pointer` as key for later retrieval
    @dev The pointer is a contract address with `_data` as code
    @param _data to be written
    @return pointer Pointer to the written `_data`
  */
  function write(bytes memory _data) internal returns (address pointer) {
    // Append 00 to _data so contract can't be called
    // Build init code
    bytes memory code = Bytecode.creationCodeFor(
      abi.encodePacked(
        hex'00',
        _data
      )
    );

    // Deploy contract using create
    assembly { pointer := create(0, add(code, 32), mload(code)) }

    // Address MUST be non-zero
    if (pointer == address(0)) revert WriteError();
  }

  /**
    @notice Reads the contents of the `_pointer` code as data, skips the first byte 
    @dev The function is intended for reading pointers generated by `write`
    @param _pointer to be read
    @return data read from `_pointer` contract
  */
  function read(address _pointer) internal view returns (bytes memory) {
    return Bytecode.codeAt(_pointer, 1, type(uint256).max);
  }

  /**
    @notice Reads the contents of the `_pointer` code as data, skips the first byte 
    @dev The function is intended for reading pointers generated by `write`
    @param _pointer to be read
    @param _start number of bytes to skip
    @return data read from `_pointer` contract
  */
  function read(address _pointer, uint256 _start) internal view returns (bytes memory) {
    return Bytecode.codeAt(_pointer, _start + 1, type(uint256).max);
  }

  /**
    @notice Reads the contents of the `_pointer` code as data, skips the first byte 
    @dev The function is intended for reading pointers generated by `write`
    @param _pointer to be read
    @param _start number of bytes to skip
    @param _end index before which to end extraction
    @return data read from `_pointer` contract
  */
  function read(address _pointer, uint256 _start, uint256 _end) internal view returns (bytes memory) {
    return Bytecode.codeAt(_pointer, _start + 1, _end + 1);
  }
}

File 28 of 39 : BlockingApp.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import {IBlockingApp} from "./interfaces/IBlockingApp.sol";
import {ILayerZeroEndpoint} from "layerzero/interfaces/ILayerZeroEndpoint.sol";

import {Owned} from "solmate/auth/Owned.sol";

/// @title BlockingApp
/// @notice Abstract contract for a LayerZero blocking queue UA
abstract contract BlockingApp is IBlockingApp, Owned {
    /// @notice The LayerZero Endpoint contract
    ILayerZeroEndpoint public immutable lzEndpoint;

    /// @notice Address whos allowed to call `lzReceive` method
    /// @dev this slot is used for stateOverrides during gas estimation
    address internal allowedCaller;

    /// @notice Mapping of remote chainIDs to their respective LayerZero Endpoint IDs
    mapping(uint256 => uint16) public eIds;

    /// @notice Mapping of LayerZero Endpoint IDs to their trusted remote paths
    mapping(uint16 => bytes) public trustedRemotes;

    /// @notice Mapping of remote chainIDs to their respective Stargate Pool IDs
    mapping(uint256 => PoolIds) public poolIds;

    /// @notice Mapping of LayerZero Endpoint IDs to the minimum gas amount required for the chain
    mapping(uint16 => uint256) public minGasAmountForChain;

    /// @notice Event emitted when a trusted remote is set
    ///
    /// @param remoteEid LayerZero Endpoint ID on the remote chain
    /// @param path Trusted path to the remote chain (abi-encoded remote address and local address)
    /// @param poolIds The Stargate Oool IDs associated with the trusted remote
    event TrustedRemoteSet(uint16 remoteEid, bytes path, PoolIds poolIds);

    /// @notice Thrown when the caller is not the LayerZero endpoint
    error OnlyEndpoint();

    /// @notice Thrown if ZRO payments are not supported
    error ZRONotSupported();

    /// @notice Thrown when a trusted remote path is not found for the given LayerZero Endpoint ID
    /// @param eid LayerZero Endpoint ID for which the path was not found
    error PathNotFound(uint16 eid);

    constructor(address owner, address _endpoint) Owned(owner) {
        lzEndpoint = ILayerZeroEndpoint(_endpoint);
    }

    receive() external payable {}

    /// @notice Sets the configuration for specified LayerZero Endpoint ID
    ///
    /// @param version Configuration version
    /// @param eid LayerZero Endpoint ID
    /// @param configType Configuration type
    /// @param config Configuration data
    function setConfig(uint16 version, uint16 eid, uint256 configType, bytes calldata config)
        external
        override
        onlyOwner
    {
        lzEndpoint.setConfig(version, eid, configType, config);
    }

    /// @notice Sets the send version for the LayerZero endpoint
    ///
    /// @param version The send version to set
    function setSendVersion(uint16 version) external override onlyOwner {
        lzEndpoint.setSendVersion(version);
    }

    /// @notice Sets the receive version for the LayerZero endpoint
    ///
    /// @param version The receive version to set
    function setReceiveVersion(uint16 version) external override onlyOwner {
        lzEndpoint.setReceiveVersion(version);
    }

    /// @notice Forces the resumption of message receiving for the specified source LayerZero Endpoint and address
    ///
    /// @param srcEid The source LayerZero Endpoint ID
    /// @param srcAddress The source address
    function forceResumeReceive(uint16 srcEid, bytes calldata srcAddress) external override onlyOwner {
        lzEndpoint.forceResumeReceive(srcEid, srcAddress);
    }

    /// @notice Sets the trusted remote for the specified remote chain ID
    ///
    /// @param remoteChainId The remote chain ID
    /// @param remoteEid The remote LayerZero Endpoint ID
    /// @param minGasAmount The minimum gas amount required for the remote chain
    /// @param path The trusted remote path (abi.encodePacked(remoteAddress, localAddress))
    /// @param _poolIds The pool IDs associated with the trusted remote
    function setTrustedRemote(
        uint256 remoteChainId,
        uint16 remoteEid,
        uint256 minGasAmount,
        bytes calldata path,
        PoolIds calldata _poolIds
    ) external onlyOwner {
        eIds[remoteChainId] = remoteEid;
        poolIds[remoteChainId] = _poolIds;
        trustedRemotes[remoteEid] = path;
        minGasAmountForChain[remoteEid] = minGasAmount;
        emit TrustedRemoteSet(remoteEid, path, _poolIds);
    }

    /// @notice Receives messages from the LayerZero
    ///
    /// @param srcEid The source LayerZero Endpoint ID
    /// @param srcAddress The source address
    /// @param message The received message
    function lzReceive(uint16 srcEid, bytes calldata srcAddress, uint64, bytes calldata message) external override {
        if (!(msg.sender == address(lzEndpoint) || msg.sender == allowedCaller)) revert OnlyEndpoint();
        if (keccak256(srcAddress) != keccak256(trustedRemotes[srcEid])) return;

        _lzReceive(message);
    }

    /// @notice Retrieves the configuration for the specified LayerZero Endpoint ID and configuration type
    ///
    /// @param version The configuration version
    /// @param eid The LayerZero Endpoint ID
    /// @param configType The configuration type
    ///
    /// @return The configuration data
    function getConfig(uint16 version, uint16 eid, address, uint256 configType) external view returns (bytes memory) {
        return lzEndpoint.getConfig(version, eid, address(this), configType);
    }

    /// @dev Sends a message through the LayerZero endpoint
    ///
    /// @param dstEid The destination LayerZero Endpoint ID
    /// @param path The trusted remote path
    /// @param message The message to send
    /// @param refundAddress The address to receive refunds
    /// @param zroPaymentAddress The address for ZRO payments
    /// @param options Additional options for the message
    function _lzSend(
        uint16 dstEid,
        bytes memory path,
        bytes memory message,
        address payable refundAddress,
        address zroPaymentAddress,
        bytes memory options
    ) internal {
        if (zroPaymentAddress != address(0)) revert ZRONotSupported();

        // solhint-disable-next-line check-send-result
        lzEndpoint.send{value: address(this).balance}(dstEid, path, message, refundAddress, address(0), options);
    }

    /// @dev Processes messages from the LayerZero endpoint
    ///
    /// @param message The received message
    function _lzReceive(bytes calldata message) internal virtual;

    /// @dev Retrieves the trusted remote path for the specified LayerZero Endpoint ID,
    ///      or reverts if not found
    ///
    /// @param eid The LayerZero Endpoint ID
    ///
    /// @return path The trusted remote path
    function _getPathOrRevert(uint16 eid) internal view returns (bytes memory path) {
        path = trustedRemotes[eid];
        if (path.length == 0) revert PathNotFound(eid);
    }
}

File 29 of 39 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 30 of 39 : IIndex.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {IVault} from "./IVault.sol";

import {Currency} from "../libraries/CurrencyLib.sol";
import {a160u96} from "../utils/a160u96.sol";

interface IIndex is IVault {
    struct IndexState {
        uint128 totalSupply;
        uint96 fees;
        uint32 lastAUMAccrualTimestamp;
        uint96 reserve;
    }

    struct Config {
        uint256 latestSnapshot; // needed to get the latest k value
        uint256 AUMDilutionPerSecond;
        bool useCustomAUMFee;
        address staticPriceOracle;
        address metadata;
    }

    struct FeeConfig {
        uint16 BPs;
        bool useCustomCallback;
    }

    struct DepositConfig {
        Config shared;
        FeeConfig fee;
    }

    struct RedemptionConfig {
        Config shared;
        FeeConfig fee;
        address forwarder;
        a160u96[] homeCurrencies; // Reserve currency + Vault's currencies
    }

    struct DepositParams {
        DepositConfig config;
        address recipient;
        bytes payload;
    }

    struct RedemptionParams {
        RedemptionConfig config;
        address owner;
        uint128 shares;
        bytes payload;
    }

    struct RedemptionInfo {
        uint256 reserveValuation;
        uint256 totalValuation;
        uint256 totalReserveShares;
        uint128 totalSupplyAfterAUMAccrual;
        uint256 totalKBeforeRedeem;
        uint256 accountBalanceSharesBeforeRedeem;
        uint96 accountReserveRedeemed;
        uint256 accountReserveSharesRedeemed;
        uint256 accountKRedeemed;
        uint256 reservePriceInQ128;
    }

    error IndexConfigHash();
    error IndexConfigMismatch();
    error IndexInitialConfig();
    error PermitDeadlineExpired();
    error InvalidSigner();
    error ZeroAddressTransfer();
    error InvalidSender();
    error ZeroDeposit();

    function deposit(DepositParams calldata params, address cbTarget, bytes calldata cbData)
        external
        payable
        returns (uint256 shares);

    function redeem(RedemptionParams calldata params, address forwardedSender, address recipient)
        external
        returns (RedemptionInfo memory redeemed);

    function startIndexRebalancing() external;

    function setConfig(
        Config calldata _prevConfig,
        DepositConfig calldata _depositConfig,
        RedemptionConfig calldata _redemptionConfig
    ) external;

    function setFeePool(address feePool) external;

    function accrueFee(address recipient) external;

    function reserve() external view returns (Currency);
    function reserveBalance() external view returns (uint96);
    function kSelf() external view returns (uint256);
    function fees() external view returns (uint256);
}

File 31 of 39 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 32 of 39 : Bytecode.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;


library Bytecode {
  error InvalidCodeAtRange(uint256 _size, uint256 _start, uint256 _end);

  /**
    @notice Generate a creation code that results on a contract with `_code` as bytecode
    @param _code The returning value of the resulting `creationCode`
    @return creationCode (constructor) for new contract
  */
  function creationCodeFor(bytes memory _code) internal pure returns (bytes memory) {
    /*
      0x00    0x63         0x63XXXXXX  PUSH4 _code.length  size
      0x01    0x80         0x80        DUP1                size size
      0x02    0x60         0x600e      PUSH1 14            14 size size
      0x03    0x60         0x6000      PUSH1 00            0 14 size size
      0x04    0x39         0x39        CODECOPY            size
      0x05    0x60         0x6000      PUSH1 00            0 size
      0x06    0xf3         0xf3        RETURN
      <CODE>
    */

    return abi.encodePacked(
      hex"63",
      uint32(_code.length),
      hex"80_60_0E_60_00_39_60_00_F3",
      _code
    );
  }

  /**
    @notice Returns the size of the code on a given address
    @param _addr Address that may or may not contain code
    @return size of the code on the given `_addr`
  */
  function codeSize(address _addr) internal view returns (uint256 size) {
    assembly { size := extcodesize(_addr) }
  }

  /**
    @notice Returns the code of a given address
    @dev It will fail if `_end < _start`
    @param _addr Address that may or may not contain code
    @param _start number of bytes of code to skip on read
    @param _end index before which to end extraction
    @return oCode read from `_addr` deployed bytecode

    Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd
  */
  function codeAt(address _addr, uint256 _start, uint256 _end) internal view returns (bytes memory oCode) {
    uint256 csize = codeSize(_addr);
    if (csize == 0) return bytes("");

    if (_start > csize) return bytes("");
    if (_end < _start) revert InvalidCodeAtRange(csize, _start, _end); 

    unchecked {
      uint256 reqSize = _end - _start;
      uint256 maxSize = csize - _start;

      uint256 size = maxSize < reqSize ? maxSize : reqSize;

      assembly {
        // allocate output byte array - this could also be done without assembly
        // by using o_code = new bytes(size)
        oCode := mload(0x40)
        // new "memory end" including padding
        mstore(0x40, add(oCode, and(add(add(size, 0x20), 0x1f), not(0x1f))))
        // store length in memory
        mstore(oCode, size)
        // actually retrieve the code, this needs assembly
        extcodecopy(_addr, add(oCode, 0x20), _start, size)
      }
    }
  }
}

File 33 of 39 : IBlockingApp.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.23;

import {ILayerZeroReceiver} from "layerzero/interfaces/ILayerZeroReceiver.sol";
import {ILayerZeroUserApplicationConfig} from "layerzero/interfaces/ILayerZeroUserApplicationConfig.sol";

interface IBlockingApp is ILayerZeroReceiver, ILayerZeroUserApplicationConfig {
    struct PoolIds {
        uint128 src;
        uint128 dst;
    }

    function setConfig(uint16 version, uint16 eid, uint256 configType, bytes calldata config) external;

    function setSendVersion(uint16 version) external;

    function setReceiveVersion(uint16 version) external;

    function setTrustedRemote(
        uint256 remoteChainId,
        uint16 remoteEid,
        uint256 minGasAmount,
        bytes calldata path,
        PoolIds calldata poolIds
    ) external;
}

File 34 of 39 : ILayerZeroEndpoint.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

import "./ILayerZeroUserApplicationConfig.sol";

interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {
    // @notice send a LayerZero message to the specified address at a LayerZero endpoint.
    // @param _dstChainId - the destination chain identifier
    // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains
    // @param _payload - a custom bytes payload to send to the destination contract
    // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address
    // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction
    // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination
    function send(uint16 _dstChainId, bytes calldata _destination, bytes calldata _payload, address payable _refundAddress, address _zroPaymentAddress, bytes calldata _adapterParams) external payable;

    // @notice used by the messaging library to publish verified payload
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source contract (as bytes) at the source chain
    // @param _dstAddress - the address on destination chain
    // @param _nonce - the unbound message ordering nonce
    // @param _gasLimit - the gas limit for external contract execution
    // @param _payload - verified payload to send to the destination contract
    function receivePayload(uint16 _srcChainId, bytes calldata _srcAddress, address _dstAddress, uint64 _nonce, uint _gasLimit, bytes calldata _payload) external;

    // @notice get the inboundNonce of a receiver from a source chain which could be EVM or non-EVM chain
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);

    // @notice get the outboundNonce from this source chain which, consequently, is always an EVM
    // @param _srcAddress - the source chain contract address
    function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);

    // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery
    // @param _dstChainId - the destination chain identifier
    // @param _userApplication - the user app address on this EVM chain
    // @param _payload - the custom message to send over LayerZero
    // @param _payInZRO - if false, user app pays the protocol fee in native token
    // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain
    function estimateFees(uint16 _dstChainId, address _userApplication, bytes calldata _payload, bool _payInZRO, bytes calldata _adapterParam) external view returns (uint nativeFee, uint zroFee);

    // @notice get this Endpoint's immutable source identifier
    function getChainId() external view returns (uint16);

    // @notice the interface to retry failed message on this Endpoint destination
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    // @param _payload - the payload to be retried
    function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external;

    // @notice query if any STORED payload (message blocking) at the endpoint.
    // @param _srcChainId - the source chain identifier
    // @param _srcAddress - the source chain contract address
    function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);

    // @notice query if the _libraryAddress is valid for sending msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getSendLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the _libraryAddress is valid for receiving msgs.
    // @param _userApplication - the user app address on this EVM chain
    function getReceiveLibraryAddress(address _userApplication) external view returns (address);

    // @notice query if the non-reentrancy guard for send() is on
    // @return true if the guard is on. false otherwise
    function isSendingPayload() external view returns (bool);

    // @notice query if the non-reentrancy guard for receive() is on
    // @return true if the guard is on. false otherwise
    function isReceivingPayload() external view returns (bool);

    // @notice get the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _userApplication - the contract address of the user application
    // @param _configType - type of configuration. every messaging library has its own convention.
    function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint _configType) external view returns (bytes memory);

    // @notice get the send() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getSendVersion(address _userApplication) external view returns (uint16);

    // @notice get the lzReceive() LayerZero messaging library version
    // @param _userApplication - the contract address of the user application
    function getReceiveVersion(address _userApplication) external view returns (uint16);
}

File 35 of 39 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnershipTransferred(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

File 36 of 39 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 37 of 39 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 38 of 39 : ILayerZeroReceiver.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroReceiver {
    // @notice LayerZero endpoint will invoke this function to deliver the message on the destination
    // @param _srcChainId - the source endpoint identifier
    // @param _srcAddress - the source sending contract address from the source chain
    // @param _nonce - the ordered message nonce
    // @param _payload - the signed payload is the UA bytes has encoded to be sent
    function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) external;
}

File 39 of 39 : ILayerZeroUserApplicationConfig.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.5.0;

interface ILayerZeroUserApplicationConfig {
    // @notice set the configuration of the LayerZero messaging library of the specified version
    // @param _version - messaging library version
    // @param _chainId - the chainId for the pending config change
    // @param _configType - type of configuration. every messaging library has its own convention.
    // @param _config - configuration in the bytes. can encode arbitrary content.
    function setConfig(uint16 _version, uint16 _chainId, uint _configType, bytes calldata _config) external;

    // @notice set the send() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setSendVersion(uint16 _version) external;

    // @notice set the lzReceive() LayerZero messaging library version to _version
    // @param _version - new messaging library version
    function setReceiveVersion(uint16 _version) external;

    // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload
    // @param _srcChainId - the chainId of the source chain
    // @param _srcAddress - the contract address of the source contract at the source chain
    function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/phuture-v2-contracts/lib/@openzeppelin/contracts/",
    "chainlink/=lib/phuture-v2-contracts/lib/chainlink-brownie-contracts/contracts/",
    "forge-std/=lib/forge-std/src/",
    "layerzero/=lib/phuture-v2-contracts/lib/LayerZero/contracts/",
    "redstone/=lib/phuture-v2-contracts/lib/redstone-oracles-monorepo/packages/evm-connector/contracts/",
    "solmate/=lib/phuture-v2-contracts/lib/solmate/src/",
    "src/=lib/phuture-v2-contracts/src/",
    "sstore2/=lib/phuture-v2-contracts/lib/sstore2/contracts/",
    "@chainlink/=node_modules/@chainlink/",
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@openzeppelin/contracts-upgradeable/=lib/phuture-v2-contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@redstone-finance/=node_modules/@redstone-finance/",
    "LayerZero/=lib/phuture-v2-contracts/lib/LayerZero/contracts/",
    "chainlink-brownie-contracts/=lib/phuture-v2-contracts/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/phuture-v2-contracts/lib/@openzeppelin/lib/erc4626-tests/",
    "openzeppelin-contracts-upgradeable/=lib/phuture-v2-contracts/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin/=lib/phuture-v2-contracts/lib/@openzeppelin/contracts/",
    "phuture-v2-contracts/=lib/phuture-v2-contracts/",
    "redstone-oracles-monorepo/=lib/phuture-v2-contracts/lib/",
    "solady/=lib/phuture-v2-contracts/lib/solady/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200,
    "details": {
      "constantOptimizer": true,
      "yul": true,
      "yulDetails": {
        "stackAllocation": true
      }
    }
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": false
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"_stargateComposer","type":"address"},{"internalType":"address payable","name":"_endpoint","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"uint16","name":"_homeEid","type":"uint16"},{"internalType":"address","name":"_sgETH","type":"address"},{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"internalType":"struct OmnichainMessenger.NativeInfo","name":"_nativeInfo","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"dstChainId","type":"uint256"}],"name":"BridgingCurrencyNotFound","type":"error"},{"inputs":[],"name":"ERC20TransferFailed","type":"error"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[],"name":"InsufficientValue","type":"error"},{"inputs":[],"name":"Invalid","type":"error"},{"inputs":[{"internalType":"uint256","name":"_size","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"InvalidCodeAtRange","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"OnlyEndpoint","type":"error"},{"inputs":[],"name":"OrderHashMismatch","type":"error"},{"inputs":[{"internalType":"uint16","name":"eid","type":"uint16"}],"name":"PathNotFound","type":"error"},{"inputs":[],"name":"PushOrders","type":"error"},{"inputs":[],"name":"QueryFailed","type":"error"},{"inputs":[],"name":"Set","type":"error"},{"inputs":[],"name":"WriteError","type":"error"},{"inputs":[],"name":"ZRONotSupported","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"OrdersHashClear","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"Currency","name":"buyCurrency","type":"address"}],"indexed":false,"internalType":"struct IOrderBook.BoughtOrder[]","name":"orders","type":"tuple[]"},{"indexed":false,"internalType":"uint256","name":"totalBought","type":"uint256"}],"name":"OutgoingOrders","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"remoteEid","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"path","type":"bytes"},{"components":[{"internalType":"uint128","name":"src","type":"uint128"},{"internalType":"uint128","name":"dst","type":"uint128"}],"indexed":false,"internalType":"struct IBlockingApp.PoolIds","name":"poolIds","type":"tuple"}],"name":"TrustedRemoteSet","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"eIds","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId[]","name":"orderIds","type":"tuple[]"},{"internalType":"uint256[]","name":"idIndices","type":"uint256[]"},{"internalType":"uint256[]","name":"pendingOrderCounts","type":"uint256[]"}],"internalType":"struct IOrderBook.FinishOrderExecutionParams","name":"orderBookParams","type":"tuple"},{"components":[{"internalType":"a160u96[]","name":"anatomyCurrencies","type":"uint256[]"},{"components":[{"internalType":"a160u96[]","name":"currencies","type":"uint256[]"},{"internalType":"uint256[]","name":"currencyIndexSet","type":"uint256[]"}],"internalType":"struct IVault.SnapshotAnatomy","name":"newAnatomy","type":"tuple"},{"components":[{"internalType":"uint256[]","name":"currencyIndexSet","type":"uint256[]"},{"internalType":"uint96[]","name":"amounts","type":"uint96[]"}],"internalType":"struct IVault.CurrencyWithdrawal","name":"withdrawals","type":"tuple"},{"internalType":"uint256","name":"lastKBalance","type":"uint256"},{"internalType":"Currency[]","name":"currencies","type":"address[]"}],"internalType":"struct IVault.EndRebalancingParams","name":"params","type":"tuple"},{"components":[{"components":[{"internalType":"uint256","name":"dstGasForCall","type":"uint256"},{"internalType":"uint256","name":"dstNativeAmount","type":"uint256"},{"internalType":"bytes","name":"dstNativeAddr","type":"bytes"}],"internalType":"struct IStargateRouter.lzTxObj","name":"lzTxObj","type":"tuple"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"}],"internalType":"struct IOmnichainMessenger.SgParams[]","name":"sgParams","type":"tuple[]"},{"components":[{"internalType":"bytes[]","name":"options","type":"bytes[]"},{"internalType":"address","name":"zroPaymentAddress","type":"address"}],"internalType":"struct IOmnichainMessenger.LzParams","name":"lzParams","type":"tuple"},{"internalType":"address payable","name":"refundAddress","type":"address"}],"name":"finishVaultRebalancing","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcEid","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"}],"name":"forceResumeReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getBridgingInfo","outputs":[{"components":[{"internalType":"uint256","name":"finalDstChainId","type":"uint256"},{"internalType":"Currency","name":"localCurrency","type":"address"}],"internalType":"struct IOmnichainMessenger.BridgingInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"uint16","name":"eid","type":"uint16"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"configType","type":"uint256"}],"name":"getConfig","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lzEndpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcEid","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"minGasAmountForChain","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"phutureOnConsumeCallbackV1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolIds","outputs":[{"internalType":"uint128","name":"src","type":"uint128"},{"internalType":"uint128","name":"dst","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"srcChainId","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"Currency","name":"buyCurrency","type":"address"}],"internalType":"struct IOrderBook.BoughtOrder[]","name":"boughtOrders","type":"tuple[]"},{"internalType":"uint256","name":"boughtOrdersTotalAmount","type":"uint256"},{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint256","name":"receivedAmount","type":"uint256"}],"name":"pushIncomingOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint96","name":"sellAmount","type":"uint96"},{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId","name":"idParams","type":"tuple"}],"internalType":"struct OrderLib.Order[]","name":"orders","type":"tuple[]"},{"internalType":"uint128","name":"incomingOrders","type":"uint128"}],"internalType":"struct RebalancingLib.ChainOrders","name":"chainOrders","type":"tuple"}],"name":"pushOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"Currency[]","name":"currencies","type":"address[]"},{"internalType":"bytes32","name":"currenciesHash","type":"bytes32"}],"internalType":"struct IVault.RegisterCurrenciesResult","name":"info","type":"tuple"},{"internalType":"address payable","name":"refundAddress","type":"address"},{"components":[{"internalType":"bytes[]","name":"options","type":"bytes[]"},{"internalType":"address","name":"zroPaymentAddress","type":"address"}],"internalType":"struct IOmnichainMessenger.LzParams","name":"lzParams","type":"tuple"}],"name":"sendCurrenciesHash","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"finalDstChainId","type":"uint256"},{"internalType":"Currency","name":"localCurrency","type":"address"}],"internalType":"struct IOmnichainMessenger.BridgingInfo[]","name":"_infos","type":"tuple[]"}],"name":"setBridgingInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"uint16","name":"eid","type":"uint16"},{"internalType":"uint256","name":"configType","type":"uint256"},{"internalType":"bytes","name":"config","type":"bytes"}],"name":"setConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_escrowDeployer","type":"address"}],"name":"setEscrowDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_orderBook","type":"address"}],"name":"setOrderBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"setReceiveVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"version","type":"uint16"}],"name":"setSendVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"remoteChainId","type":"uint256"},{"internalType":"uint16","name":"remoteEid","type":"uint16"},{"internalType":"uint256","name":"minGasAmount","type":"uint256"},{"internalType":"bytes","name":"path","type":"bytes"},{"components":[{"internalType":"uint128","name":"src","type":"uint128"},{"internalType":"uint128","name":"dst","type":"uint128"}],"internalType":"struct IBlockingApp.PoolIds","name":"_poolIds","type":"tuple"}],"name":"setTrustedRemote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"srcEid","type":"uint16"},{"internalType":"bytes","name":"srcAddress","type":"bytes"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"sgReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"trustedRemotes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawCurrency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6040610120815234620004e0576200499090813803806200002081620004fb565b93843982019060e083830312620004e0576200003c8362000521565b6020906200004c82860162000521565b838601516001600160a01b03808216979094909291889003620004e057620000776060840162000521565b96608084015161ffff81168103620004e0576200009760a0860162000521565b60c08601516001600160401b0396919291878211620004e0570194606086850312620004e0578951936060850185811089821117620004e5578b528651888111620004e05781620000ea91890162000536565b855285870151888111620004e0578b916200010791890162000536565b9686860197885201519760ff89168903620004e057848b01988952600080546001600160a01b031916918b1691821781559c908d7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a360805260a05260e05260c0525197885192848411620003de576006549360019a8b86811c96168015620004d5575b85871014620004c1578190601f968781116200046d575b508590878311600114620003fe578592620003f2575b5050600019600383901b1c1916908b1b176006555b51918251948511620003de576007548a81811c91168015620003d3575b82821014620003bf5784811162000376575b5080938511600114620003085750978392839260ff9798999a94620002fc575b50501b916000199060031b1c1916176007555b511660ff19600854161760085561010092168252516143e79182620005a98339608051828181610446015281816105ec01528181610fb90152818161119e015281816113580152818161157b0152818161164801526138e3015260a0518281816124dd0152818161335b015281816135b4015281816136170152818161367d015281816136db015261371c015260c05182612572015260e051828181610eb201526117e201525181818161182601528181612ba501528181612df101528181612f2f0152612fa60152f35b0151925038806200021e565b9893929091601f198416996007845280842093905b8b82106200035e5750508360ff9798999a1062000344575b505050811b0160075562000231565b015160001960f88460031b161c1916905538808062000335565b8087859682949686015181550195019301906200031d565b600783528183208580880160051c820192848910620003b5575b0160051c01908b905b828110620003a9575050620001fe565b848155018b9062000399565b9250819262000390565b634e487b7160e01b83526022600452602483fd5b90607f1690620001ec565b634e487b7160e01b82526041600452602482fd5b015190503880620001ba565b600686528686208e94509190601f198416875b898282106200044d575050841162000433575b505050811b01600655620001cf565b015160001960f88460031b161c1916905538808062000424565b91929395968291958786015181550195019301908f959493929162000411565b909150600685528585208780850160051c820192888610620004b7575b918f91869594930160051c01915b828110620004a8575050620001a4565b8781558594508f910162000498565b925081926200048a565b634e487b7160e01b84526022600452602484fd5b95607f16956200018d565b600080fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f191682016001600160401b03811183821017620004e557604052565b51906001600160a01b0382168203620004e057565b919080601f84011215620004e05782516001600160401b038111620004e5576020906200056c601f8201601f19168301620004fb565b92818452828287010111620004e05760005b8181106200059457508260009394955001015290565b85810183015184820184015282016200057e56fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80621d3567146101aa578063055f192c146101a557806307e0db17146101a05780630e73c0d31461019b57806310ddb1371461019657806318b8dac9146101915780632583c29c1461018c57806327a0371f146101875780632b5d23d214610182578063314012d11461017d5780633a26f9421461017857806342d65a8d1461017357806369883b4e1461016e5780637a7c7348146101695780638da5cb5b146101645780639a1598c81461015f578063ab8236f31461015a578063b353aaa714610155578063bee01be814610150578063c4f7941d1461014b578063cbed8b9c14610146578063ccfc9ba514610141578063d699e0af1461013c578063f2fde38b146101375763f5ecbdbc0361000e57611519565b6114a6565b61145c565b6113c3565b6112f8565b6112c8565b6111cd565b611188565b61111a565b6110ca565b6110a1565b611066565b61102a565b610f65565b610e4a565b610d2a565b610cdd565b610a65565b610914565b610643565b6105b9565b61052f565b610413565b61029e565b610203565b6004359061ffff821682036101c057565b600080fd5b6024359061ffff821682036101c057565b9181601f840112156101c0578235916001600160401b0383116101c057602083818601950101116101c057565b346101c05760803660031901126101c05761021c6101af565b6001600160401b03906024358281116101c05761023d9036906004016101d6565b604492919235848116036101c0576064359384116101c0576102666100199436906004016101d6565b939092611639565b9181601f840112156101c0578235916001600160401b0383116101c0576020808501948460061b0101116101c057565b346101c05760203660031901126101c0576004356001600160401b0381116101c0576102ce90369060040161026e565b60018060a01b03906000926102e78385541633146116e4565b604091825180926020820192808684016020865252606083019190885b878282106103f257505050506103a09261032c6103b093602e9303601f1981018752866109e3565b61035c60218751809361034c60208301998d8b5251809285850190610c81565b81010360018101845201826109e3565b80519486519485926020840197606360f81b895263ffffffff60e01b9060e01b1660218501526880600e6000396000f360b81b602585015251809285850190610c81565b810103600e8101845201826109e3565b519084f0918216156103e25750600980546001600160a01b0319166001600160a01b0390921691909117905580f35b80f35b5163046a55db60e11b8152600490fd5b839550846104056001949683949661171f565b019401910191859392610304565b346101c057600060203660031901126104af5761042e6101af565b8160018060a01b036104448183541633146116e4565b7f00000000000000000000000000000000000000000000000000000000000000001691823b156104ab57602461ffff918360405195869485936307e0db1760e01b85521660048401525af180156104a65761049d575080f35b6103df9061095f565b611740565b5080fd5b80fd5b908160a09103126101c05790565b9181601f840112156101c0578235916001600160401b0383116101c0576020808501948460051b0101116101c057565b60409060831901126101c057608490565b908160409103126101c05790565b6001600160a01b038116036101c057565b6084359061052d8261050f565b565b60031960a0368201126101c0576004356001600160401b03918282116101c05760609082360301126101c0576024358281116101c0576105739036906004016104b2565b6044358381116101c05761058b9036906004016104c0565b906064359485116101c0576105a7610019953690600401610501565b926105b0610520565b9460040161174c565b346101c057600060203660031901126104af576105d46101af565b8160018060a01b036105ea8183541633146116e4565b7f00000000000000000000000000000000000000000000000000000000000000001691823b156104ab57602461ffff918360405195869485936310ddb13760e01b85521660048401525af180156104a65761049d575080f35b346101c05760a03660031901126101c0576004356024356001600160401b0381116101c05761067690369060040161026e565b9091906064356044356106888261050f565b60843591604091825194602095868101816106a585858d85611f1c565b03916106b9601f19938481018352826109e3565b51902085518881019182526001600160a01b03861660208301526040820188905290916106f29082606085015b039081018352826109e3565b51902061070988600052600c602052604060002090565b5403610903577fc945d9e1f8095c0dea44c1e121710035a0e1825064e18e6e9d304e2cbf233c2061075b6000988961074b82600052600c602052604060002090565b5586519081529081906020820190565b0390a161076781611f7a565b9561077182611e6a565b988893845b8b8611156107f6578a8a818b8b8b6107a4610798600a5460018060a01b031690565b6001600160a01b031690565b91823b156107f2576107cd958591519687958694859363ad175a8b60e01b8552600485016120a6565b03925af180156104a6576107df575080f35b806107ec6103df9261095f565b80611096565b8480fd5b806001600160601b03866108d48f8f8f908f8f8f92908f958d8f93848f6108dd9f8b906108a5998f938361085c956108949a610868995082146000146108e35750505061084b9161084691611e79565b61399f565b9d5b6108628461085c84848a61200a565b01611e15565b9561200a565b93610883610874610a04565b6001600160a01b039098168852565b6001600160a01b0390911690860152565b6001600160a01b0390911690830152565b4660608201526108b3610a11565b6001600160601b0386168152908b8201526108ce838361201a565b5261201a565b50160195611ffb565b94610776565b6108fd945061084693916108f7918b61200a565b35613989565b9d61084d565b835163be364e3b60e01b8152600490fd5b346101c05760203660031901126101c05761ffff6109306101af565b1660005260056020526020604060002054604051908152f35b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161097257604052565b610949565b604081019081106001600160401b0382111761097257604052565b608081019081106001600160401b0382111761097257604052565b606081019081106001600160401b0382111761097257604052565b602081019081106001600160401b0382111761097257604052565b90601f801991011681019081106001600160401b0382111761097257604052565b6040519061052d82610992565b6040519061052d82610977565b6001600160401b0381116109725760051b60200190565b35906001600160601b03821682036101c057565b6001600160801b038116036101c057565b359061052d82610a49565b346101c057602060031981813601126101c057600435916001600160401b03918284116101c0576040809185360301126101c057805192610aa584610977565b84600401359081116101c0578401366023820112156101c057600481013590610acd82610a1e565b92610ada815194856109e3565b82845284840190602460a0809502840101923684116101c057602401915b838310610b1c576100198888610b1360248d8b855201610a5a565b90820152612120565b8236038581126101c057825191610b3283610977565b610b3b85610a35565b835260808092601f1901126101c05786928992855190610b5a82610992565b84880135610b678161050f565b825286880135610b768161050f565b8583015260609081890135610b8a8161050f565b888401528801359082015283820152815201920191610af8565b90600182811c92168015610bd4575b6020831014610bbe57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610bb3565b90604051918260008254610bf181610ba4565b90818452602094600191600181169081600014610c5f5750600114610c20575b50505061052d925003836109e3565b600090815285812095935091905b818310610c4757505061052d9350820101388080610c11565b85548884018501529485019487945091830191610c2e565b9250505061052d94925060ff191682840152151560051b820101388080610c11565b60005b838110610c945750506000910152565b8181015183820152602001610c84565b90602091610cbd81518092818552858086019101610c81565b601f01601f1916010190565b906020610cda928181520190610ca4565b90565b346101c05760203660031901126101c05761ffff610cf96101af565b166000526003602052610d26610d126040600020610bde565b604051918291602083526020830190610ca4565b0390f35b346101c05760c03660031901126101c057610d436101c5565b6064356001600160401b0381116101c057610d837fa6c31f11fb022ad87f4d24c4d7341d7ff9914f0263c04421f24b33dc014efccd9136906004016101d6565b92610e44610d90366104f0565b600095610da760018060a01b0388541633146116e4565b600435875260026020526040872061ffff851661ffff198254161790556004602052604087208235610dd881610a49565b6001600160801b036020850135610dee81610a49565b81199060801b169116179055610e1c8186610e178761ffff166000526003602052604060002090565b61228c565b604435610e378561ffff166000526005602052604060002090565b556040519485948561237b565b0390a180f35b60603660031901126101c0576001600160401b036004358181116101c057610e76903690600401610501565b60243591610e838361050f565b6044359081116101c057610e9b903690600401610501565b610eb060018060a01b036000541633146116e4565b7f0000000000000000000000000000000000000000000000000000000000000000904793348503948511610f6057610f09610f4694610f17610efa610ef48761388c565b92613d18565b604051938491602083016123ce565b03601f1981018452836109e3565b610f40610f39610f33610f2c60208801611e15565b9680611e1f565b90611e9c565b3691611602565b946138ca565b4710610f4e57005b60405163044044a560e21b8152600490fd5b611e54565b346101c057600060403660031901126104af57610f806101af565b816024356001600160401b0381116104ab57610fa09036906004016101d6565b909260018060a01b03610fb78185541633146116e4565b7f00000000000000000000000000000000000000000000000000000000000000001690813b15611026578361ffff91611014604051978896879586946342d65a8d60e01b865216600485015260406024850152604484019161235a565b03925af180156104a65761049d575080f35b8380fd5b346101c05760203660031901126101c0576004356000526004602052604080600020548151906001600160801b038116825260801c6020820152f35b346101c05760203660031901126101c0576004356001600160401b0381116101c0576100199036906004016101d6565b60009103126101c057565b346101c05760003660031901126101c0576000546040516001600160a01b039091168152602090f35b346101c05760203660031901126101c0576004356110e78161050f565b6000546001600160a01b03919061110190831633146116e4565b166001600160601b0360a01b600a541617600a55600080f35b346101c05760c03660031901126101c0576111336101af565b6001600160401b03906024358281116101c0576111549036906004016101d6565b916064356111618161050f565b60a4359485116101c05761117c6100199536906004016101d6565b949093608435936124c8565b346101c05760003660031901126101c0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b346101c05760203660031901126101c0576004356111ea8161050f565b6000546001600160a01b03919061120490831633146116e4565b600b54829061121b906001600160a01b0316610798565b166112b657604051633cb747bf60e01b815290821691602082600481865afa9182156104a657600092611285575b503091160361127357600b80546001600160a01b0319166001600160a01b03909216919091179055005b604051636dac6a0960e01b8152600490fd5b6112a891925060203d6020116112af575b6112a081836109e3565b810190612645565b9038611249565b503d611296565b604051632081e91160e01b8152600490fd5b346101c05760203660031901126101c0576004356000526002602052602061ffff60406000205416604051908152f35b346101c05760803660031901126101c0576113116101af565b6113196101c5565b6064356001600160401b0381116101c0576113389036906004016101d6565b60018060a09493941b039160009483611356879586541633146116e4565b7f00000000000000000000000000000000000000000000000000000000000000001691823b156107f25784906107cd604051978896879586946332fb62e760e21b865261ffff8092166004870152166024850152604435604485015260806064850152608484019161235a565b346101c05760003660031901126101c0576009546113e9906001600160a01b03166141fe565b6113fe8151916020808094830101910161265a565b9060409160405192828493840190808552835180925280604086019401926000905b83821061142d5786860387f35b8451805187526020908101516001600160a01b0316908701528796509485019493820193600190910190611420565b346101c05760603660031901126101c05761001960043561147c8161050f565b6024356114888161050f565b61149d60018060a01b036000541633146116e4565b60443591613e96565b346101c05760203660031901126101c0576004356114c38161050f565b6000805490916001600160a01b03906114df33838516146116e4565b1680916001600160601b0360a01b16178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b346101c05760803660031901126101c0576115326101af565b61153a6101c5565b9061154660443561050f565b604051633d7b2f6f60e21b815261ffff91821660048201529116602482015230604482015260648035908201526000816084817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104a657610d26916000916115c4575b5060405191829182610cc9565b6115e191503d806000833e6115d981836109e3565b8101906126e6565b386115b7565b6001600160401b03811161097257601f01601f191660200190565b92919261160e826115e7565b9161161c60405193846109e3565b8294818452818301116101c0578281602093846000960137010152565b919093929360018060a01b03807f00000000000000000000000000000000000000000000000000000000000000001633149081156116d6575b50156116c45761168a6116a6916116ab933691611602565b602081519101209261ffff166000526003602052604060002090565b610bde565b60208151910120036116c05761052d91612ac8565b5050565b604051630fd72cd960e31b8152600490fd5b905060015416331438611672565b156116eb57565b60405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606490fd5b602080918035845201356117328161050f565b6001600160a01b0316910152565b6040513d6000823e3d90fd5b94919392909360018060a01b039560009261176b8885541633146116e4565b61177f46600052600c602052604060002090565b5461194457600a54849283916117bf91906117a2906001600160a01b0316610798565b9060405195868094819363474aba6b60e01b835260048301611bab565b03925af19283156104a6576117dd9387938691611922575b50613338565b6118227f000000000000000000000000000000000000000000000000000000000000000094604051809763099e120360e11b8252818581602096879660048301611d51565b03927f0000000000000000000000000000000000000000000000000000000000000000165af19081156104a65761052d966118ab93926118e7575b50610f396118c0610f40926118b96118748a61388c565b9561187d610a11565b9046825283820152604051978891848301919091604060206060830194600684528051828501520151910152565b03601f1981018852876109e3565b8701611e15565b956118da6118e16118d18380611e1f565b92909380611e1f565b9050611e6a565b91611edb565b8192506118c0611912610f3992610f40943d871161191b575b61190a81836109e3565b810190611c40565b9392505061185d565b503d611900565b61193e91503d8088833e61193681836109e3565b810190611987565b386117d7565b6040516370f1766760e01b8152600490fd5b91908260409103126101c05760405161196e81610977565b6020808294805184520151916119838361050f565b0152565b90602080838303126101c05782516001600160401b03938482116101c0570182601f820112156101c05780516119bc81610a1e565b946040946119cc865197886109e3565b828752848088019360051b850101938185116101c057858101935b8585106119f957505050505050505090565b84518481116101c0578201608080601f1983870301126101c057895191611a1f83610992565b8981015183528a810151611a328161050f565b8a840152606091828201518c850152810151908782116101c057019085603f830112156101c0578982015191611a6783610a1e565b92611a748d5194856109e3565b8084528c8c85019160061b830101918883116101c057908d808e97959896949301915b838310611ab2575050505083948201528152019401936119e7565b611ac48b849596989a97999394611956565b81520191018d8d969497959392611a97565b9190808252602080920192916000905b828210611af4575050505090565b909192936001908535611b068161050f565b828060a01b0380911682528084880135611b1f8161050f565b168483015260409081880135611b348161050f565b1690820152606086810135908201526080908101950193920190611ae6565b9035601e19823603018112156101c05701602081359101916001600160401b0382116101c0578160051b360383136101c057565b81835290916001600160fb1b0383116101c05760209260051b809284830137010190565b90602082528035601e19823603018112156101c057810191602083359301906001600160401b0384116101c0578360071b360382136101c057611bfe606092610cda958460208501526080840191611ad6565b90611c31611c26611c126020870187611b53565b601f19858703810160408701529591611b87565b946040810190611b53565b93909282860301910152611b87565b908160209103126101c0575190565b91908082526020809201929160005b828110611c6c575050505090565b833585529381019392810192600101611c5e565b9035603e19823603018112156101c0570190565b611caf611ca18280611b53565b604085526040850191611b87565b6020611cbf819382810190611b53565b9290948281830391015282815201929160005b828110611ce0575050505090565b9091929382806001926001600160601b03611cfa89610a35565b16815201950193929101611cd2565b91908082526020809201929160005b828110611d26575050505090565b9091929382806001928735611d3a8161050f565b848060a01b03168152019501910192919092611d18565b9060a0610cda9260208152611d79611d698480611b53565b84602085015260c0840191611c4f565b90611e06611df1611dd5611d906020880188611c80565b601f199586868203016040870152611dc7611dbc611dae8480611b53565b604085526040850191611c4f565b926020810190611b53565b916020818503910152611b87565b611de26040880188611c80565b85858303016060860152611c94565b94606081013560808401526080810190611b53565b93909282860301910152611d09565b35610cda8161050f565b903590601e19813603018212156101c057018035906001600160401b0382116101c057602001918160051b360383136101c057565b634e487b7160e01b600052601160045260246000fd5b600019810191908211610f6057565b91908203918211610f6057565b634e487b7160e01b600052603260045260246000fd5b9015611ed657803590601e19813603018212156101c05701908135916001600160401b0383116101c05760200182360381136101c0579190565b611e86565b9190811015611ed65760051b81013590601e19813603018212156101c05701908135916001600160401b0383116101c05760200182360381136101c0579190565b604080825280820184905290949392606086019160005b828110611f465750505060209150930152565b909192828082611f586001948961171f565b01950191019392919093611f33565b604051611f73816109c8565b6000815290565b90611f8482610a1e565b604090611f9460405191826109e3565b8381528093611fa5601f1991610a1e565b019160005b838110611fb75750505050565b6020908251611fc581610977565b60008152828451611fd581610992565b600081526000828201526000868201526000606082015281830152828601015201611faa565b6000198114610f605760010190565b9190811015611ed65760061b0190565b8051821015611ed65760209160051b010190565b90815180825260208080930193019160005b82811061204e575050505090565b835180516001600160601b0316865282015180516001600160a01b0390811687850152818401518116604080890191909152820151166060808801919091520151608086015260a09094019392810192600101612040565b6120be6040929594939560608352606083019061202e565b6001600160a01b0390951660208201520152565b6020815260406001600160801b0360206120f685518483870152606086019061202e565b9401511691015290565b6040906001600160801b03610cda9493168152816020820152019061202e565b60405160208101906121448161213685856120d2565b03601f1981018352826109e3565b51902061215b46600052600c602052604060002090565b540361222457600061217746600052600c602052604060002090565b556040514681527fc945d9e1f8095c0dea44c1e121710035a0e1825064e18e6e9d304e2cbf233c2090602090a180516121af816139b7565b600a546121da906020906121cb906001600160a01b0316610798565b9301516001600160801b031690565b90823b156101c057612206926000928360405180968195829463ad102f9b60e01b845260048401612100565b03925af180156104a6576122175750565b806107ec61052d9261095f565b60405163be364e3b60e01b8152600490fd5b90601f811161224457505050565b6000916000526020600020906020601f850160051c83019410612282575b601f0160051c01915b82811061227757505050565b81815560010161226b565b9092508290612262565b9092916001600160401b038111610972576122b1816122ab8454610ba4565b84612236565b6000601f82116001146122f25781906122e39394956000926122e7575b50508160011b916000199060031b1c19161790565b9055565b0135905038806122ce565b601f1982169461230784600052602060002090565b91805b878110612342575083600195969710612328575b505050811b019055565b0135600019600384901b60f8161c1916905538808061231e565b9092602060018192868601358155019401910161230a565b908060209392818452848401376000828201840152601f01601f1916010190565b929160609261ffff61239e9397969716855260806020860152608085019161235a565b9360208135916123ad83610a49565b6001600160801b03809316604086015201356123c881610a49565b16910152565b6040916000825260209260408484015260a0830182516040850152848301519460608080870152865180935260c086018260c08560051b8901019801946000925b85841061242a57505050505050506040608091015191015290565b90919293949598858060019260bf198c82030187528c5190856124696124596080855190808652850190610ca4565b8585015184820387860152610ca4565b9260ff89820151168984015281878060a01b03910151169101529b019401940192959493919061240f565b826014949392823701906001600160601b03199060601b1681520190565b91908260409103126101c0576020823592013590565b9495939490926001600160a01b0392909190337f00000000000000000000000000000000000000000000000000000000000000008516148015612628575b15612616576116a661255591612529966040519788916020830193309185612494565b039661253d601f19988981018352826109e3565b5190209261ffff166000526003602052604060002090565b602081519101200361260e5761052d956125ec926125a5928116907f000000000000000000000000000000000000000000000000000000000000000016810361260857506000945b8101906124b2565b60408051602081019384526001600160a01b038716918101919091526060810187905290936125d89082608081016106e6565b51902091600052600c602052604060002090565b55600a54612602906001600160a01b0316610798565b90613e96565b9461259d565b505050505050565b604051631dd2188d60e31b8152600490fd5b5060015461263e906001600160a01b0316610798565b3314612506565b908160209103126101c05751610cda8161050f565b906020916020818303126101c0578051906001600160401b0382116101c0570181601f820112156101c05780519261269184610a1e565b936040936126a260405196876109e3565b81865260208087019260061b850101938185116101c057602001915b8483106126ce5750505050505090565b8386916126db8486611956565b8152019201916126be565b6020818303126101c0578051906001600160401b0382116101c0570181601f820112156101c0578051612718816115e7565b9261272660405194856109e3565b818452602082840101116101c057610cda9160208085019101610c81565b906020116101c05790602090565b359060208110612760575090565b6000199060200360031b1b1690565b60ff8116036101c057565b91908260409103126101c057602082356127938161276f565b92013590565b604051906127a682610977565b60606020838281520152565b9060209081835260608301908051916040848601528251809152836080860193019060005b81811061282b57505050820151926040601f198284030191015281808451928381520193019160005b82811061280e575050505090565b83516001600160601b031685529381019392810192600101612800565b8251855293850193918501916001016127d7565b604090610cda93928152816020820152019061202e565b9080601f830112156101c057602090823561287081610a1e565b9361287e60405195866109e3565b81855260208086019260051b8201019283116101c057602001905b8282106128a7575050505090565b8380916128b384610a35565b815201910190612899565b916060838303126101c05782356128d48161276f565b926020808201359360408301356001600160401b03938482116101c05701906040828203126101c0576040519361290a85610977565b82358181116101c057830182601f820112156101c05780359061292c82610a1e565b9161293a60405193846109e3565b808352868084019160051b830101918583116101c05787809101915b83831061297f57505050508552838301359081116101c0576129789201612856565b9082015290565b8235815291810191889101612956565b9080601f830112156101c057816020610cda93359101611602565b906080828203126101c05781356129c08161276f565b9260208301356129cf8161050f565b9260408101359260608201356001600160401b0381116101c057610cda920161298f565b519081151582036101c057565b91908260409103126101c057610cda60208351612a1c8161050f565b93016129f3565b610cda9392606092825260208201528160408201520190610ca4565b916060838303126101c0578235612a558161276f565b926020810135612a648161050f565b9260408201356001600160401b0381116101c057610cda920161298f565b906060610cda9260008152600060208201528160408201520190610ca4565b908160609103126101c0578035612ab78161276f565b91604060208301356127938161050f565b60ff612ae6612ae0612ada8585612744565b90612752565b60ff1690565b1660018103612c1f575080612b4e92612b00920190612aa1565b600b546001600160a01b039493509091604091859190612b21908316610798565b835163701c61ed60e11b8152919092166001600160a01b0316600482015293849190829081906024820190565b03915afa9283156104a657612ba193602093600091612bef575b50604051632df8a21160e11b81526001600160a01b03909116600482015260248101929092529092839190829060009082906044820190565b03927f0000000000000000000000000000000000000000000000000000000000000000165af180156104a657612bd45750565b612bec9060203d60201161191b5761190a81836109e3565b50565b612c11915060403d604011612c18575b612c0981836109e3565b810190612a00565b5038612b68565b503d612bff565b60028103612d535750612c3491810190612a3f565b600b546001600160a01b039283169350909190612c52908216610798565b6040805163701c61ed60e11b81526001600160a01b0386166004820152909490918583602481845afa80156104a657600093600091612d30575b5015612ccc575b50501691823b156101c0576000928392612cc1925194858094819363216f3c6b60e01b835260048301612a82565b03925af16122175750565b8551634c96a38960e01b81526001600160a01b03929092166004830152602090829060249082906000905af19081612d11575b50612d0a5750505050565b3880612c93565b612d299060203d6020116112af576112a081836109e3565b5038612cff565b9050612d4a919350863d8811612c1857612c0981836109e3565b92909238612c8c565b60038103612f015750612d68918101906129aa565b600b546001600160a01b039384169450909190612d86908416610798565b6040805163701c61ed60e11b81526001600160a01b038716600482015290959194918682602481895afa80156104a657600092600091612ede575b508751632df8a21160e11b81526001600160a01b03841660048201526024810186905296602091828960448160007f00000000000000000000000000000000000000000000000000000000000000008b165af19889156104a657600099612ebf575b5015612e59575b5050501690813b156101c05760008094612cc196519687958694859363216f3c6b60e01b855260048501612a23565b8851634c96a38960e01b81526001600160a01b039390931660048401528190839060249082906000905af19182612ea1575b5050612e9957505050505050565b388080612e2a565b81612eb792903d106112af576112a081836109e3565b503880612e8b565b612ed7919950833d851161191b5761190a81836109e3565b9738612e23565b9050612ef8919250873d8911612c1857612c0981836109e3565b91909138612dc1565b60048103612f845750612f16918101906128be565b9150612f2c46600052600c602052604060002090565b557f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156101c057604051630e8f3bf560e31b815291600091839182908490829061220690600483016127b2565b600581036130695750612f999181019061277a565b919050612fa4612799565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b156101c057612ffb6040518093818094630e8f3bf560e31b825260009687958692600483016127b2565b03925af180156104a657613056575b50600a54613020906001600160a01b0316610798565b613028611f67565b90803b156130525761220693948360405180968195829463ad102f9b60e01b84526004840161283f565b8280fd5b806107ec6130639261095f565b3861300a565b600714613074575050565b6130809181019061277a565b600a54909150613098906001600160a01b0316610798565b803b156101c057604051630ca3008d60e01b815260048101929092526000908290602490829084905af180156104a6576122175750565b604051906130dc82610992565b606080836000815260006020820152600060408201520152565b9060405161310381610977565b91546001600160801b038116835260801c6020830152565b9190811015611ed65760051b81013590603e19813603018212156101c0570190565b9291906040906040850160408652815180915260608601916020809101936000905b838210613173575050505060209150930152565b8551805186526020908101516001600160a01b031690860152948201949384019360019091019061315f565b90602082519201516001600160601b03199081811693601481106131c257505050565b60140360031b82901b16169150565b90604051916001600160601b03191660208301526014825261052d82610977565b903590605e19813603018212156101c0570190565b91908260409103126101c0576020825192015190565b80358252602081013560208301526040810135601e19823603018112156101c05701602081359101906001600160401b0381116101c05780360382136101c057606083816040610cda960152019161235a565b9261329b610cda959361ffff6132a9941686526001602087015260a0604087015260a0860190610ca4565b908482036060860152610ca4565b91608081840391015261321d565b91908201809211610f6057565b979461331b94613329979293610cda9b999561ffff61012096168c526001600160801b0380921660208d01521660408b015260018060a01b031660608a0152608089015260a08801528060c088015286019061321d565b9084820360e0860152610ca4565b91610100818403910152610ca4565b9193926133436130cf565b60405163c45a015560e01b81529093906020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa80156104a6576133a59160009161386d575b506001600160a01b03168552565b8051946040850195865260005b8651811015613863576133c5818461201a565b51906134606133ea6133e284516000526002602052604060002090565b5461ffff1690565b926133f48461388c565b60608a015261341661341182516000526004602052604060002090565b6130f6565b60408201518a51602090613432906001600160a01b0316610798565b835160405163068bcd8d60e01b81526001600160801b03909116600482015295869190829081906024820190565b03915afa9384156104a657600494602091600091613846575b5060405163feb56b1560e01b815295869182906001600160a01b03165afa9081156104a657898b928f928e97600092613825575b50106137ad57509161358461357f60606134de613537958998976134d8602061356c9c01518d611e79565b9161311b565b966135788288017f37a28c62bfa8e4579bdc54985bb8380deeb34721706ffd1aac79b28b6a00d683815160408b01519061351d6040519283928361313d565b0390a151604089015160405198899160208301938461313d565b039761354b601f19998a81018352826109e3565b5190206040805160208101929092524690820152998a979088906060820190565b039081018852876109e3565b015161319f565b6131d1565b93604085896135b061359685806131f2565b8451630a51236960e01b81529a8b94859460048601613270565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9586156104a65760009661377b575b506020840180519096939084906001600160a01b031615613763575b5086516040860151613645917f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b0316614036565b604061366c602061365d86516001600160801b031690565b9501516001600160801b031690565b9501519061367a83806131f2565b967f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163b156101c0576000976020956136d7946040519d8e9a8b998a996327efc43f60e21b8b52013593309260048b016132c4565b03917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19081156104a65760019361374a92613750575b50517f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b0316613f2e565b016133b2565b806107ec61375d9261095f565b38613718565b6137749194506040860151906132b7565b9238613609565b61379e91965060403d6040116137a6575b61379681836109e3565b810190613207565b5094386135ed565b503d61378c565b925050506001946121366137e26060806138209701519501515160405192839160208301919060206040840193600781520152565b613818610f398d60206138006137f9828901611e15565b9780611e1f565b919092019182519261381184611ffb565b9052611edb565b9330926138ca565b61374a565b61383f91925060203d60201161191b5761190a81836109e3565b90386134ad565b61385d9150823d84116112af576112a081836109e3565b38613479565b5095505050505050565b613886915060203d6020116112af576112a081836109e3565b38613397565b61ffff16908160005260036020526138a76040600020610bde565b918251156138b25750565b60249060405190639cd86f1760e01b82526004820152fd5b929493909291906001600160a01b0390811661397757807f000000000000000000000000000000000000000000000000000000000000000016924791843b156101c0576139499760009761ffff956122069361395c6040519c8d9b8c9a8b9962c5803160e81b8b521660048a015260c060248a015260c4890190610ca4565b60031993848983030160448a0152610ca4565b931660648601528960848601528483030160a4850152610ca4565b60405163653626cf60e01b8152600490fd5b816000190481118202158302156101c057020490565b600160601b8110156101c0576001600160601b031690565b6009546139cc906001600160a01b03166141fe565b906139e28251926020808095830101910161265a565b60005b8251811015613ab2576060846139fb838661201a565b5101510151468103613a11575b506001016139e5565b92909493600094855b8451811015613aa757613a2d818661201a565b51518614613a3d57600101613a1a565b90969294919550613a85613a6687613a576001948861201a565b5101516001600160a01b031690565b8780613a72878a61201a565b5101516001600160a01b03909216910152565b613a085760405163132b474b60e31b81526004810191909152602490fd5b0390fd5b509591939094613a85565b50505050565b60405190613ac5826109ad565b6000604083828152606060208201520152565b90613ae282610a1e565b604090613af260405191826109e3565b8381528093613b03601f1991610a1e565b019160009160005b848110613b19575050505050565b6020908351613b2781610992565b606080825286849180838501528188850152830152828501015201613b0b565b9190811015611ed65760051b0190565b908160209103126101c05751610cda8161276f565b6040519060008260075491613b8083610ba4565b80835292602090600190818116908115613c0c5750600114613bab575b505061052d925003836109e3565b91509260076000527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688936000925b828410613bf4575061052d9450505081016020013880613b9d565b85548885018301529485019487945092810192613bd9565b9150506020925061052d94915060ff191682840152151560051b8201013880613b9d565b60405190613c3d826109ad565b6040516006548391600081613c5184610ba4565b9182825260209460019086600182169182600014613cf8575050600114613c9b575b50613c80925003826109e3565b8252613c8a613b6c565b90820152604060ff60085416910152565b85915060066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f906000915b858310613ce0575050613c80935082010138613c73565b80548388018501528694508793909201918101613cc9565b60ff191685820152613c8095151560051b8501019250389150613c739050565b90613d21613ab8565b91602092604093808301356040830152468252613d48613d418480611e1f565b9050613ad8565b9281830193845260009260005b613d5f8380611e1f565b9050811015613e8d57613d84613d7f82613d798680611e1f565b90613b47565b611e15565b9084896001600160a01b03841680613e015750613df991613dec600195613ddc8694613dae613c30565b90613dc28183519784015193015160ff1690565b91613dcb610a04565b9687528d87015285019060ff169052565b6001600160a01b03166060830152565b8951906108ce838361201a565b505b01613d55565b905060049150613e10816140cc565b87613e1a8361418a565b928d519485809263313ce56760e01b82525afa9182156104a657600195613ddc86948f613dec94613e58988f8f9094613e5e575b5050613dcb610a04565b50613dfb565b613e7e929450803d10613e86575b613e7681836109e3565b810190613b57565b91388e613e4e565b503d613e6c565b50955050505050565b8215613f29576001600160a01b03818116613ed557505060008080613ebd9481945af11590565b613ec357565b604051633d2cec6f60e21b8152600490fd5b60209260008093613f11966044946040519463a9059cbb60e01b865216600485015260248401525af1600051600114601f3d11163d1517161590565b613f1757565b604051633c9fd93960e21b8152600490fd5b505050565b6001600160a01b031680156116c05760405163095ea7b360e01b602082018181526001600160a01b0385166024840152600060448401819052919492939290918085606481015b0393613f89601f19958681018952886109e3565b86519082875af1613f9861407e565b81614007575b5080613ffd575b15613fb2575b5050505050565b60405160208101959095526001600160a01b0316602485015260006044850152613ff393613fee91613fe89082606481016106e6565b82614268565b614268565b3880808080613fab565b50823b1515613fa5565b805180159250821561401c575b505038613f9e565b61402f9250602080918301019101614254565b3880614014565b6001600160a01b03168015613f295760405163095ea7b360e01b602082018181526001600160a01b038516602484015260448301959095529390926000808560648101613f75565b3d156140a9573d9061408f826115e7565b9161409d60405193846109e3565b82523d6000602084013e565b606090565b8015610f60576000190190565b908151811015611ed6570160200190565b6000809160405160208101906306fdde0360e01b8252600481526140ef81610977565b51915afa906140fc61407e565b9115614178578151602081036141655750602082815b6141195752565b9061414d61414061413261412c84611e6a565b856140bb565b516001600160f81b03191690565b6001600160f81b03191690565b6141615761415a906140ae565b9081614112565b9052565b91602080610cda939483010191016126e6565b6040516360d806dd60e11b8152600490fd5b6000809160405160208101906395d89b4160e01b8252600481526141ad81610977565b51915afa906141ba61407e565b9115614178578151602081036141655750602082815b6141d75752565b906141ea61414061413261412c84611e6a565b614161576141f7906140ae565b90816141d0565b90813b8015614245578060011161424557600019016001198082101561423e57505b600160405193601f19603f840116850160405282855260208501903c565b9050614220565b509050604051611f73816109c8565b908160209103126101c057610cda906129f3565b6040516142c6916001600160a01b031661428182610977565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16142c061407e565b9161434e565b805190828215928315614336575b505050156142df5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6143469350820181019101614254565b3882816142d4565b919290156143b05750815115614362575090565b3b1561436b5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156143c35750805190602001fd5b60405162461bcd60e51b815260206004820152908190613aa3906024830190610ca456000000000000000000000000de4d377d8a8d455330edd7c4eb5b284ada1113d8000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a90000000000000000000000003c2269811836af69497e5f486a85d7316753cf62000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000007506f6c79676f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054d41544943000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80621d3567146101aa578063055f192c146101a557806307e0db17146101a05780630e73c0d31461019b57806310ddb1371461019657806318b8dac9146101915780632583c29c1461018c57806327a0371f146101875780632b5d23d214610182578063314012d11461017d5780633a26f9421461017857806342d65a8d1461017357806369883b4e1461016e5780637a7c7348146101695780638da5cb5b146101645780639a1598c81461015f578063ab8236f31461015a578063b353aaa714610155578063bee01be814610150578063c4f7941d1461014b578063cbed8b9c14610146578063ccfc9ba514610141578063d699e0af1461013c578063f2fde38b146101375763f5ecbdbc0361000e57611519565b6114a6565b61145c565b6113c3565b6112f8565b6112c8565b6111cd565b611188565b61111a565b6110ca565b6110a1565b611066565b61102a565b610f65565b610e4a565b610d2a565b610cdd565b610a65565b610914565b610643565b6105b9565b61052f565b610413565b61029e565b610203565b6004359061ffff821682036101c057565b600080fd5b6024359061ffff821682036101c057565b9181601f840112156101c0578235916001600160401b0383116101c057602083818601950101116101c057565b346101c05760803660031901126101c05761021c6101af565b6001600160401b03906024358281116101c05761023d9036906004016101d6565b604492919235848116036101c0576064359384116101c0576102666100199436906004016101d6565b939092611639565b9181601f840112156101c0578235916001600160401b0383116101c0576020808501948460061b0101116101c057565b346101c05760203660031901126101c0576004356001600160401b0381116101c0576102ce90369060040161026e565b60018060a01b03906000926102e78385541633146116e4565b604091825180926020820192808684016020865252606083019190885b878282106103f257505050506103a09261032c6103b093602e9303601f1981018752866109e3565b61035c60218751809361034c60208301998d8b5251809285850190610c81565b81010360018101845201826109e3565b80519486519485926020840197606360f81b895263ffffffff60e01b9060e01b1660218501526880600e6000396000f360b81b602585015251809285850190610c81565b810103600e8101845201826109e3565b519084f0918216156103e25750600980546001600160a01b0319166001600160a01b0390921691909117905580f35b80f35b5163046a55db60e11b8152600490fd5b839550846104056001949683949661171f565b019401910191859392610304565b346101c057600060203660031901126104af5761042e6101af565b8160018060a01b036104448183541633146116e4565b7f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf621691823b156104ab57602461ffff918360405195869485936307e0db1760e01b85521660048401525af180156104a65761049d575080f35b6103df9061095f565b611740565b5080fd5b80fd5b908160a09103126101c05790565b9181601f840112156101c0578235916001600160401b0383116101c0576020808501948460051b0101116101c057565b60409060831901126101c057608490565b908160409103126101c05790565b6001600160a01b038116036101c057565b6084359061052d8261050f565b565b60031960a0368201126101c0576004356001600160401b03918282116101c05760609082360301126101c0576024358281116101c0576105739036906004016104b2565b6044358381116101c05761058b9036906004016104c0565b906064359485116101c0576105a7610019953690600401610501565b926105b0610520565b9460040161174c565b346101c057600060203660031901126104af576105d46101af565b8160018060a01b036105ea8183541633146116e4565b7f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf621691823b156104ab57602461ffff918360405195869485936310ddb13760e01b85521660048401525af180156104a65761049d575080f35b346101c05760a03660031901126101c0576004356024356001600160401b0381116101c05761067690369060040161026e565b9091906064356044356106888261050f565b60843591604091825194602095868101816106a585858d85611f1c565b03916106b9601f19938481018352826109e3565b51902085518881019182526001600160a01b03861660208301526040820188905290916106f29082606085015b039081018352826109e3565b51902061070988600052600c602052604060002090565b5403610903577fc945d9e1f8095c0dea44c1e121710035a0e1825064e18e6e9d304e2cbf233c2061075b6000988961074b82600052600c602052604060002090565b5586519081529081906020820190565b0390a161076781611f7a565b9561077182611e6a565b988893845b8b8611156107f6578a8a818b8b8b6107a4610798600a5460018060a01b031690565b6001600160a01b031690565b91823b156107f2576107cd958591519687958694859363ad175a8b60e01b8552600485016120a6565b03925af180156104a6576107df575080f35b806107ec6103df9261095f565b80611096565b8480fd5b806001600160601b03866108d48f8f8f908f8f8f92908f958d8f93848f6108dd9f8b906108a5998f938361085c956108949a610868995082146000146108e35750505061084b9161084691611e79565b61399f565b9d5b6108628461085c84848a61200a565b01611e15565b9561200a565b93610883610874610a04565b6001600160a01b039098168852565b6001600160a01b0390911690860152565b6001600160a01b0390911690830152565b4660608201526108b3610a11565b6001600160601b0386168152908b8201526108ce838361201a565b5261201a565b50160195611ffb565b94610776565b6108fd945061084693916108f7918b61200a565b35613989565b9d61084d565b835163be364e3b60e01b8152600490fd5b346101c05760203660031901126101c05761ffff6109306101af565b1660005260056020526020604060002054604051908152f35b634e487b7160e01b600052604160045260246000fd5b6001600160401b03811161097257604052565b610949565b604081019081106001600160401b0382111761097257604052565b608081019081106001600160401b0382111761097257604052565b606081019081106001600160401b0382111761097257604052565b602081019081106001600160401b0382111761097257604052565b90601f801991011681019081106001600160401b0382111761097257604052565b6040519061052d82610992565b6040519061052d82610977565b6001600160401b0381116109725760051b60200190565b35906001600160601b03821682036101c057565b6001600160801b038116036101c057565b359061052d82610a49565b346101c057602060031981813601126101c057600435916001600160401b03918284116101c0576040809185360301126101c057805192610aa584610977565b84600401359081116101c0578401366023820112156101c057600481013590610acd82610a1e565b92610ada815194856109e3565b82845284840190602460a0809502840101923684116101c057602401915b838310610b1c576100198888610b1360248d8b855201610a5a565b90820152612120565b8236038581126101c057825191610b3283610977565b610b3b85610a35565b835260808092601f1901126101c05786928992855190610b5a82610992565b84880135610b678161050f565b825286880135610b768161050f565b8583015260609081890135610b8a8161050f565b888401528801359082015283820152815201920191610af8565b90600182811c92168015610bd4575b6020831014610bbe57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610bb3565b90604051918260008254610bf181610ba4565b90818452602094600191600181169081600014610c5f5750600114610c20575b50505061052d925003836109e3565b600090815285812095935091905b818310610c4757505061052d9350820101388080610c11565b85548884018501529485019487945091830191610c2e565b9250505061052d94925060ff191682840152151560051b820101388080610c11565b60005b838110610c945750506000910152565b8181015183820152602001610c84565b90602091610cbd81518092818552858086019101610c81565b601f01601f1916010190565b906020610cda928181520190610ca4565b90565b346101c05760203660031901126101c05761ffff610cf96101af565b166000526003602052610d26610d126040600020610bde565b604051918291602083526020830190610ca4565b0390f35b346101c05760c03660031901126101c057610d436101c5565b6064356001600160401b0381116101c057610d837fa6c31f11fb022ad87f4d24c4d7341d7ff9914f0263c04421f24b33dc014efccd9136906004016101d6565b92610e44610d90366104f0565b600095610da760018060a01b0388541633146116e4565b600435875260026020526040872061ffff851661ffff198254161790556004602052604087208235610dd881610a49565b6001600160801b036020850135610dee81610a49565b81199060801b169116179055610e1c8186610e178761ffff166000526003602052604060002090565b61228c565b604435610e378561ffff166000526005602052604060002090565b556040519485948561237b565b0390a180f35b60603660031901126101c0576001600160401b036004358181116101c057610e76903690600401610501565b60243591610e838361050f565b6044359081116101c057610e9b903690600401610501565b610eb060018060a01b036000541633146116e4565b7f000000000000000000000000000000000000000000000000000000000000006e904793348503948511610f6057610f09610f4694610f17610efa610ef48761388c565b92613d18565b604051938491602083016123ce565b03601f1981018452836109e3565b610f40610f39610f33610f2c60208801611e15565b9680611e1f565b90611e9c565b3691611602565b946138ca565b4710610f4e57005b60405163044044a560e21b8152600490fd5b611e54565b346101c057600060403660031901126104af57610f806101af565b816024356001600160401b0381116104ab57610fa09036906004016101d6565b909260018060a01b03610fb78185541633146116e4565b7f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf621690813b15611026578361ffff91611014604051978896879586946342d65a8d60e01b865216600485015260406024850152604484019161235a565b03925af180156104a65761049d575080f35b8380fd5b346101c05760203660031901126101c0576004356000526004602052604080600020548151906001600160801b038116825260801c6020820152f35b346101c05760203660031901126101c0576004356001600160401b0381116101c0576100199036906004016101d6565b60009103126101c057565b346101c05760003660031901126101c0576000546040516001600160a01b039091168152602090f35b346101c05760203660031901126101c0576004356110e78161050f565b6000546001600160a01b03919061110190831633146116e4565b166001600160601b0360a01b600a541617600a55600080f35b346101c05760c03660031901126101c0576111336101af565b6001600160401b03906024358281116101c0576111549036906004016101d6565b916064356111618161050f565b60a4359485116101c05761117c6100199536906004016101d6565b949093608435936124c8565b346101c05760003660031901126101c0576040517f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf626001600160a01b03168152602090f35b346101c05760203660031901126101c0576004356111ea8161050f565b6000546001600160a01b03919061120490831633146116e4565b600b54829061121b906001600160a01b0316610798565b166112b657604051633cb747bf60e01b815290821691602082600481865afa9182156104a657600092611285575b503091160361127357600b80546001600160a01b0319166001600160a01b03909216919091179055005b604051636dac6a0960e01b8152600490fd5b6112a891925060203d6020116112af575b6112a081836109e3565b810190612645565b9038611249565b503d611296565b604051632081e91160e01b8152600490fd5b346101c05760203660031901126101c0576004356000526002602052602061ffff60406000205416604051908152f35b346101c05760803660031901126101c0576113116101af565b6113196101c5565b6064356001600160401b0381116101c0576113389036906004016101d6565b60018060a09493941b039160009483611356879586541633146116e4565b7f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf621691823b156107f25784906107cd604051978896879586946332fb62e760e21b865261ffff8092166004870152166024850152604435604485015260806064850152608484019161235a565b346101c05760003660031901126101c0576009546113e9906001600160a01b03166141fe565b6113fe8151916020808094830101910161265a565b9060409160405192828493840190808552835180925280604086019401926000905b83821061142d5786860387f35b8451805187526020908101516001600160a01b0316908701528796509485019493820193600190910190611420565b346101c05760603660031901126101c05761001960043561147c8161050f565b6024356114888161050f565b61149d60018060a01b036000541633146116e4565b60443591613e96565b346101c05760203660031901126101c0576004356114c38161050f565b6000805490916001600160a01b03906114df33838516146116e4565b1680916001600160601b0360a01b16178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b346101c05760803660031901126101c0576115326101af565b61153a6101c5565b9061154660443561050f565b604051633d7b2f6f60e21b815261ffff91821660048201529116602482015230604482015260648035908201526000816084817f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf626001600160a01b03165afa80156104a657610d26916000916115c4575b5060405191829182610cc9565b6115e191503d806000833e6115d981836109e3565b8101906126e6565b386115b7565b6001600160401b03811161097257601f01601f191660200190565b92919261160e826115e7565b9161161c60405193846109e3565b8294818452818301116101c0578281602093846000960137010152565b919093929360018060a01b03807f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf621633149081156116d6575b50156116c45761168a6116a6916116ab933691611602565b602081519101209261ffff166000526003602052604060002090565b610bde565b60208151910120036116c05761052d91612ac8565b5050565b604051630fd72cd960e31b8152600490fd5b905060015416331438611672565b156116eb57565b60405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606490fd5b602080918035845201356117328161050f565b6001600160a01b0316910152565b6040513d6000823e3d90fd5b94919392909360018060a01b039560009261176b8885541633146116e4565b61177f46600052600c602052604060002090565b5461194457600a54849283916117bf91906117a2906001600160a01b0316610798565b9060405195868094819363474aba6b60e01b835260048301611bab565b03925af19283156104a6576117dd9387938691611922575b50613338565b6118227f000000000000000000000000000000000000000000000000000000000000006e94604051809763099e120360e11b8252818581602096879660048301611d51565b03927f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2165af19081156104a65761052d966118ab93926118e7575b50610f396118c0610f40926118b96118748a61388c565b9561187d610a11565b9046825283820152604051978891848301919091604060206060830194600684528051828501520151910152565b03601f1981018852876109e3565b8701611e15565b956118da6118e16118d18380611e1f565b92909380611e1f565b9050611e6a565b91611edb565b8192506118c0611912610f3992610f40943d871161191b575b61190a81836109e3565b810190611c40565b9392505061185d565b503d611900565b61193e91503d8088833e61193681836109e3565b810190611987565b386117d7565b6040516370f1766760e01b8152600490fd5b91908260409103126101c05760405161196e81610977565b6020808294805184520151916119838361050f565b0152565b90602080838303126101c05782516001600160401b03938482116101c0570182601f820112156101c05780516119bc81610a1e565b946040946119cc865197886109e3565b828752848088019360051b850101938185116101c057858101935b8585106119f957505050505050505090565b84518481116101c0578201608080601f1983870301126101c057895191611a1f83610992565b8981015183528a810151611a328161050f565b8a840152606091828201518c850152810151908782116101c057019085603f830112156101c0578982015191611a6783610a1e565b92611a748d5194856109e3565b8084528c8c85019160061b830101918883116101c057908d808e97959896949301915b838310611ab2575050505083948201528152019401936119e7565b611ac48b849596989a97999394611956565b81520191018d8d969497959392611a97565b9190808252602080920192916000905b828210611af4575050505090565b909192936001908535611b068161050f565b828060a01b0380911682528084880135611b1f8161050f565b168483015260409081880135611b348161050f565b1690820152606086810135908201526080908101950193920190611ae6565b9035601e19823603018112156101c05701602081359101916001600160401b0382116101c0578160051b360383136101c057565b81835290916001600160fb1b0383116101c05760209260051b809284830137010190565b90602082528035601e19823603018112156101c057810191602083359301906001600160401b0384116101c0578360071b360382136101c057611bfe606092610cda958460208501526080840191611ad6565b90611c31611c26611c126020870187611b53565b601f19858703810160408701529591611b87565b946040810190611b53565b93909282860301910152611b87565b908160209103126101c0575190565b91908082526020809201929160005b828110611c6c575050505090565b833585529381019392810192600101611c5e565b9035603e19823603018112156101c0570190565b611caf611ca18280611b53565b604085526040850191611b87565b6020611cbf819382810190611b53565b9290948281830391015282815201929160005b828110611ce0575050505090565b9091929382806001926001600160601b03611cfa89610a35565b16815201950193929101611cd2565b91908082526020809201929160005b828110611d26575050505090565b9091929382806001928735611d3a8161050f565b848060a01b03168152019501910192919092611d18565b9060a0610cda9260208152611d79611d698480611b53565b84602085015260c0840191611c4f565b90611e06611df1611dd5611d906020880188611c80565b601f199586868203016040870152611dc7611dbc611dae8480611b53565b604085526040850191611c4f565b926020810190611b53565b916020818503910152611b87565b611de26040880188611c80565b85858303016060860152611c94565b94606081013560808401526080810190611b53565b93909282860301910152611d09565b35610cda8161050f565b903590601e19813603018212156101c057018035906001600160401b0382116101c057602001918160051b360383136101c057565b634e487b7160e01b600052601160045260246000fd5b600019810191908211610f6057565b91908203918211610f6057565b634e487b7160e01b600052603260045260246000fd5b9015611ed657803590601e19813603018212156101c05701908135916001600160401b0383116101c05760200182360381136101c0579190565b611e86565b9190811015611ed65760051b81013590601e19813603018212156101c05701908135916001600160401b0383116101c05760200182360381136101c0579190565b604080825280820184905290949392606086019160005b828110611f465750505060209150930152565b909192828082611f586001948961171f565b01950191019392919093611f33565b604051611f73816109c8565b6000815290565b90611f8482610a1e565b604090611f9460405191826109e3565b8381528093611fa5601f1991610a1e565b019160005b838110611fb75750505050565b6020908251611fc581610977565b60008152828451611fd581610992565b600081526000828201526000868201526000606082015281830152828601015201611faa565b6000198114610f605760010190565b9190811015611ed65760061b0190565b8051821015611ed65760209160051b010190565b90815180825260208080930193019160005b82811061204e575050505090565b835180516001600160601b0316865282015180516001600160a01b0390811687850152818401518116604080890191909152820151166060808801919091520151608086015260a09094019392810192600101612040565b6120be6040929594939560608352606083019061202e565b6001600160a01b0390951660208201520152565b6020815260406001600160801b0360206120f685518483870152606086019061202e565b9401511691015290565b6040906001600160801b03610cda9493168152816020820152019061202e565b60405160208101906121448161213685856120d2565b03601f1981018352826109e3565b51902061215b46600052600c602052604060002090565b540361222457600061217746600052600c602052604060002090565b556040514681527fc945d9e1f8095c0dea44c1e121710035a0e1825064e18e6e9d304e2cbf233c2090602090a180516121af816139b7565b600a546121da906020906121cb906001600160a01b0316610798565b9301516001600160801b031690565b90823b156101c057612206926000928360405180968195829463ad102f9b60e01b845260048401612100565b03925af180156104a6576122175750565b806107ec61052d9261095f565b60405163be364e3b60e01b8152600490fd5b90601f811161224457505050565b6000916000526020600020906020601f850160051c83019410612282575b601f0160051c01915b82811061227757505050565b81815560010161226b565b9092508290612262565b9092916001600160401b038111610972576122b1816122ab8454610ba4565b84612236565b6000601f82116001146122f25781906122e39394956000926122e7575b50508160011b916000199060031b1c19161790565b9055565b0135905038806122ce565b601f1982169461230784600052602060002090565b91805b878110612342575083600195969710612328575b505050811b019055565b0135600019600384901b60f8161c1916905538808061231e565b9092602060018192868601358155019401910161230a565b908060209392818452848401376000828201840152601f01601f1916010190565b929160609261ffff61239e9397969716855260806020860152608085019161235a565b9360208135916123ad83610a49565b6001600160801b03809316604086015201356123c881610a49565b16910152565b6040916000825260209260408484015260a0830182516040850152848301519460608080870152865180935260c086018260c08560051b8901019801946000925b85841061242a57505050505050506040608091015191015290565b90919293949598858060019260bf198c82030187528c5190856124696124596080855190808652850190610ca4565b8585015184820387860152610ca4565b9260ff89820151168984015281878060a01b03910151169101529b019401940192959493919061240f565b826014949392823701906001600160601b03199060601b1681520190565b91908260409103126101c0576020823592013590565b9495939490926001600160a01b0392909190337f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a98516148015612628575b15612616576116a661255591612529966040519788916020830193309185612494565b039661253d601f19988981018352826109e3565b5190209261ffff166000526003602052604060002090565b602081519101200361260e5761052d956125ec926125a5928116907f000000000000000000000000000000000000000000000000000000000000000016810361260857506000945b8101906124b2565b60408051602081019384526001600160a01b038716918101919091526060810187905290936125d89082608081016106e6565b51902091600052600c602052604060002090565b55600a54612602906001600160a01b0316610798565b90613e96565b9461259d565b505050505050565b604051631dd2188d60e31b8152600490fd5b5060015461263e906001600160a01b0316610798565b3314612506565b908160209103126101c05751610cda8161050f565b906020916020818303126101c0578051906001600160401b0382116101c0570181601f820112156101c05780519261269184610a1e565b936040936126a260405196876109e3565b81865260208087019260061b850101938185116101c057602001915b8483106126ce5750505050505090565b8386916126db8486611956565b8152019201916126be565b6020818303126101c0578051906001600160401b0382116101c0570181601f820112156101c0578051612718816115e7565b9261272660405194856109e3565b818452602082840101116101c057610cda9160208085019101610c81565b906020116101c05790602090565b359060208110612760575090565b6000199060200360031b1b1690565b60ff8116036101c057565b91908260409103126101c057602082356127938161276f565b92013590565b604051906127a682610977565b60606020838281520152565b9060209081835260608301908051916040848601528251809152836080860193019060005b81811061282b57505050820151926040601f198284030191015281808451928381520193019160005b82811061280e575050505090565b83516001600160601b031685529381019392810192600101612800565b8251855293850193918501916001016127d7565b604090610cda93928152816020820152019061202e565b9080601f830112156101c057602090823561287081610a1e565b9361287e60405195866109e3565b81855260208086019260051b8201019283116101c057602001905b8282106128a7575050505090565b8380916128b384610a35565b815201910190612899565b916060838303126101c05782356128d48161276f565b926020808201359360408301356001600160401b03938482116101c05701906040828203126101c0576040519361290a85610977565b82358181116101c057830182601f820112156101c05780359061292c82610a1e565b9161293a60405193846109e3565b808352868084019160051b830101918583116101c05787809101915b83831061297f57505050508552838301359081116101c0576129789201612856565b9082015290565b8235815291810191889101612956565b9080601f830112156101c057816020610cda93359101611602565b906080828203126101c05781356129c08161276f565b9260208301356129cf8161050f565b9260408101359260608201356001600160401b0381116101c057610cda920161298f565b519081151582036101c057565b91908260409103126101c057610cda60208351612a1c8161050f565b93016129f3565b610cda9392606092825260208201528160408201520190610ca4565b916060838303126101c0578235612a558161276f565b926020810135612a648161050f565b9260408201356001600160401b0381116101c057610cda920161298f565b906060610cda9260008152600060208201528160408201520190610ca4565b908160609103126101c0578035612ab78161276f565b91604060208301356127938161050f565b60ff612ae6612ae0612ada8585612744565b90612752565b60ff1690565b1660018103612c1f575080612b4e92612b00920190612aa1565b600b546001600160a01b039493509091604091859190612b21908316610798565b835163701c61ed60e11b8152919092166001600160a01b0316600482015293849190829081906024820190565b03915afa9283156104a657612ba193602093600091612bef575b50604051632df8a21160e11b81526001600160a01b03909116600482015260248101929092529092839190829060009082906044820190565b03927f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2165af180156104a657612bd45750565b612bec9060203d60201161191b5761190a81836109e3565b50565b612c11915060403d604011612c18575b612c0981836109e3565b810190612a00565b5038612b68565b503d612bff565b60028103612d535750612c3491810190612a3f565b600b546001600160a01b039283169350909190612c52908216610798565b6040805163701c61ed60e11b81526001600160a01b0386166004820152909490918583602481845afa80156104a657600093600091612d30575b5015612ccc575b50501691823b156101c0576000928392612cc1925194858094819363216f3c6b60e01b835260048301612a82565b03925af16122175750565b8551634c96a38960e01b81526001600160a01b03929092166004830152602090829060249082906000905af19081612d11575b50612d0a5750505050565b3880612c93565b612d299060203d6020116112af576112a081836109e3565b5038612cff565b9050612d4a919350863d8811612c1857612c0981836109e3565b92909238612c8c565b60038103612f015750612d68918101906129aa565b600b546001600160a01b039384169450909190612d86908416610798565b6040805163701c61ed60e11b81526001600160a01b038716600482015290959194918682602481895afa80156104a657600092600091612ede575b508751632df8a21160e11b81526001600160a01b03841660048201526024810186905296602091828960448160007f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d28b165af19889156104a657600099612ebf575b5015612e59575b5050501690813b156101c05760008094612cc196519687958694859363216f3c6b60e01b855260048501612a23565b8851634c96a38960e01b81526001600160a01b039390931660048401528190839060249082906000905af19182612ea1575b5050612e9957505050505050565b388080612e2a565b81612eb792903d106112af576112a081836109e3565b503880612e8b565b612ed7919950833d851161191b5761190a81836109e3565b9738612e23565b9050612ef8919250873d8911612c1857612c0981836109e3565b91909138612dc1565b60048103612f845750612f16918101906128be565b9150612f2c46600052600c602052604060002090565b557f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d26001600160a01b0316803b156101c057604051630e8f3bf560e31b815291600091839182908490829061220690600483016127b2565b600581036130695750612f999181019061277a565b919050612fa4612799565b7f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d26001600160a01b031690813b156101c057612ffb6040518093818094630e8f3bf560e31b825260009687958692600483016127b2565b03925af180156104a657613056575b50600a54613020906001600160a01b0316610798565b613028611f67565b90803b156130525761220693948360405180968195829463ad102f9b60e01b84526004840161283f565b8280fd5b806107ec6130639261095f565b3861300a565b600714613074575050565b6130809181019061277a565b600a54909150613098906001600160a01b0316610798565b803b156101c057604051630ca3008d60e01b815260048101929092526000908290602490829084905af180156104a6576122175750565b604051906130dc82610992565b606080836000815260006020820152600060408201520152565b9060405161310381610977565b91546001600160801b038116835260801c6020830152565b9190811015611ed65760051b81013590603e19813603018212156101c0570190565b9291906040906040850160408652815180915260608601916020809101936000905b838210613173575050505060209150930152565b8551805186526020908101516001600160a01b031690860152948201949384019360019091019061315f565b90602082519201516001600160601b03199081811693601481106131c257505050565b60140360031b82901b16169150565b90604051916001600160601b03191660208301526014825261052d82610977565b903590605e19813603018212156101c0570190565b91908260409103126101c0576020825192015190565b80358252602081013560208301526040810135601e19823603018112156101c05701602081359101906001600160401b0381116101c05780360382136101c057606083816040610cda960152019161235a565b9261329b610cda959361ffff6132a9941686526001602087015260a0604087015260a0860190610ca4565b908482036060860152610ca4565b91608081840391015261321d565b91908201809211610f6057565b979461331b94613329979293610cda9b999561ffff61012096168c526001600160801b0380921660208d01521660408b015260018060a01b031660608a0152608089015260a08801528060c088015286019061321d565b9084820360e0860152610ca4565b91610100818403910152610ca4565b9193926133436130cf565b60405163c45a015560e01b81529093906020816004817f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a96001600160a01b03165afa80156104a6576133a59160009161386d575b506001600160a01b03168552565b8051946040850195865260005b8651811015613863576133c5818461201a565b51906134606133ea6133e284516000526002602052604060002090565b5461ffff1690565b926133f48461388c565b60608a015261341661341182516000526004602052604060002090565b6130f6565b60408201518a51602090613432906001600160a01b0316610798565b835160405163068bcd8d60e01b81526001600160801b03909116600482015295869190829081906024820190565b03915afa9384156104a657600494602091600091613846575b5060405163feb56b1560e01b815295869182906001600160a01b03165afa9081156104a657898b928f928e97600092613825575b50106137ad57509161358461357f60606134de613537958998976134d8602061356c9c01518d611e79565b9161311b565b966135788288017f37a28c62bfa8e4579bdc54985bb8380deeb34721706ffd1aac79b28b6a00d683815160408b01519061351d6040519283928361313d565b0390a151604089015160405198899160208301938461313d565b039761354b601f19998a81018352826109e3565b5190206040805160208101929092524690820152998a979088906060820190565b039081018852876109e3565b015161319f565b6131d1565b93604085896135b061359685806131f2565b8451630a51236960e01b81529a8b94859460048601613270565b03817f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a96001600160a01b03165afa9586156104a65760009661377b575b506020840180519096939084906001600160a01b031615613763575b5086516040860151613645917f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a9906001600160a01b0316614036565b604061366c602061365d86516001600160801b031690565b9501516001600160801b031690565b9501519061367a83806131f2565b967f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a96001600160a01b03163b156101c0576000976020956136d7946040519d8e9a8b998a996327efc43f60e21b8b52013593309260048b016132c4565b03917f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a96001600160a01b03165af19081156104a65760019361374a92613750575b50517f000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a9906001600160a01b0316613f2e565b016133b2565b806107ec61375d9261095f565b38613718565b6137749194506040860151906132b7565b9238613609565b61379e91965060403d6040116137a6575b61379681836109e3565b810190613207565b5094386135ed565b503d61378c565b925050506001946121366137e26060806138209701519501515160405192839160208301919060206040840193600781520152565b613818610f398d60206138006137f9828901611e15565b9780611e1f565b919092019182519261381184611ffb565b9052611edb565b9330926138ca565b61374a565b61383f91925060203d60201161191b5761190a81836109e3565b90386134ad565b61385d9150823d84116112af576112a081836109e3565b38613479565b5095505050505050565b613886915060203d6020116112af576112a081836109e3565b38613397565b61ffff16908160005260036020526138a76040600020610bde565b918251156138b25750565b60249060405190639cd86f1760e01b82526004820152fd5b929493909291906001600160a01b0390811661397757807f0000000000000000000000003c2269811836af69497e5f486a85d7316753cf6216924791843b156101c0576139499760009761ffff956122069361395c6040519c8d9b8c9a8b9962c5803160e81b8b521660048a015260c060248a015260c4890190610ca4565b60031993848983030160448a0152610ca4565b931660648601528960848601528483030160a4850152610ca4565b60405163653626cf60e01b8152600490fd5b816000190481118202158302156101c057020490565b600160601b8110156101c0576001600160601b031690565b6009546139cc906001600160a01b03166141fe565b906139e28251926020808095830101910161265a565b60005b8251811015613ab2576060846139fb838661201a565b5101510151468103613a11575b506001016139e5565b92909493600094855b8451811015613aa757613a2d818661201a565b51518614613a3d57600101613a1a565b90969294919550613a85613a6687613a576001948861201a565b5101516001600160a01b031690565b8780613a72878a61201a565b5101516001600160a01b03909216910152565b613a085760405163132b474b60e31b81526004810191909152602490fd5b0390fd5b509591939094613a85565b50505050565b60405190613ac5826109ad565b6000604083828152606060208201520152565b90613ae282610a1e565b604090613af260405191826109e3565b8381528093613b03601f1991610a1e565b019160009160005b848110613b19575050505050565b6020908351613b2781610992565b606080825286849180838501528188850152830152828501015201613b0b565b9190811015611ed65760051b0190565b908160209103126101c05751610cda8161276f565b6040519060008260075491613b8083610ba4565b80835292602090600190818116908115613c0c5750600114613bab575b505061052d925003836109e3565b91509260076000527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688936000925b828410613bf4575061052d9450505081016020013880613b9d565b85548885018301529485019487945092810192613bd9565b9150506020925061052d94915060ff191682840152151560051b8201013880613b9d565b60405190613c3d826109ad565b6040516006548391600081613c5184610ba4565b9182825260209460019086600182169182600014613cf8575050600114613c9b575b50613c80925003826109e3565b8252613c8a613b6c565b90820152604060ff60085416910152565b85915060066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f906000915b858310613ce0575050613c80935082010138613c73565b80548388018501528694508793909201918101613cc9565b60ff191685820152613c8095151560051b8501019250389150613c739050565b90613d21613ab8565b91602092604093808301356040830152468252613d48613d418480611e1f565b9050613ad8565b9281830193845260009260005b613d5f8380611e1f565b9050811015613e8d57613d84613d7f82613d798680611e1f565b90613b47565b611e15565b9084896001600160a01b03841680613e015750613df991613dec600195613ddc8694613dae613c30565b90613dc28183519784015193015160ff1690565b91613dcb610a04565b9687528d87015285019060ff169052565b6001600160a01b03166060830152565b8951906108ce838361201a565b505b01613d55565b905060049150613e10816140cc565b87613e1a8361418a565b928d519485809263313ce56760e01b82525afa9182156104a657600195613ddc86948f613dec94613e58988f8f9094613e5e575b5050613dcb610a04565b50613dfb565b613e7e929450803d10613e86575b613e7681836109e3565b810190613b57565b91388e613e4e565b503d613e6c565b50955050505050565b8215613f29576001600160a01b03818116613ed557505060008080613ebd9481945af11590565b613ec357565b604051633d2cec6f60e21b8152600490fd5b60209260008093613f11966044946040519463a9059cbb60e01b865216600485015260248401525af1600051600114601f3d11163d1517161590565b613f1757565b604051633c9fd93960e21b8152600490fd5b505050565b6001600160a01b031680156116c05760405163095ea7b360e01b602082018181526001600160a01b0385166024840152600060448401819052919492939290918085606481015b0393613f89601f19958681018952886109e3565b86519082875af1613f9861407e565b81614007575b5080613ffd575b15613fb2575b5050505050565b60405160208101959095526001600160a01b0316602485015260006044850152613ff393613fee91613fe89082606481016106e6565b82614268565b614268565b3880808080613fab565b50823b1515613fa5565b805180159250821561401c575b505038613f9e565b61402f9250602080918301019101614254565b3880614014565b6001600160a01b03168015613f295760405163095ea7b360e01b602082018181526001600160a01b038516602484015260448301959095529390926000808560648101613f75565b3d156140a9573d9061408f826115e7565b9161409d60405193846109e3565b82523d6000602084013e565b606090565b8015610f60576000190190565b908151811015611ed6570160200190565b6000809160405160208101906306fdde0360e01b8252600481526140ef81610977565b51915afa906140fc61407e565b9115614178578151602081036141655750602082815b6141195752565b9061414d61414061413261412c84611e6a565b856140bb565b516001600160f81b03191690565b6001600160f81b03191690565b6141615761415a906140ae565b9081614112565b9052565b91602080610cda939483010191016126e6565b6040516360d806dd60e11b8152600490fd5b6000809160405160208101906395d89b4160e01b8252600481526141ad81610977565b51915afa906141ba61407e565b9115614178578151602081036141655750602082815b6141d75752565b906141ea61414061413261412c84611e6a565b614161576141f7906140ae565b90816141d0565b90813b8015614245578060011161424557600019016001198082101561423e57505b600160405193601f19603f840116850160405282855260208501903c565b9050614220565b509050604051611f73816109c8565b908160209103126101c057610cda906129f3565b6040516142c6916001600160a01b031661428182610977565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16142c061407e565b9161434e565b805190828215928315614336575b505050156142df5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6143469350820181019101614254565b3882816142d4565b919290156143b05750815115614362575090565b3b1561436b5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156143c35750805190602001fd5b60405162461bcd60e51b815260206004820152908190613aa3906024830190610ca456

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000de4d377d8a8d455330edd7c4eb5b284ada1113d8000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a90000000000000000000000003c2269811836af69497e5f486a85d7316753cf62000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000007506f6c79676f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054d41544943000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : owner (address): 0xdE4D377D8A8d455330edD7C4EB5b284ADA1113d8
Arg [1] : _stargateComposer (address): 0xeCc19E177d24551aA7ed6Bc6FE566eCa726CC8a9
Arg [2] : _endpoint (address): 0x3c2269811836af69497E5F486A85D7316753cf62
Arg [3] : _vault (address): 0xE903F5a1D43d93407Bcd11c771c03628539414d2
Arg [4] : _homeEid (uint16): 110
Arg [5] : _sgETH (address): 0x0000000000000000000000000000000000000000
Arg [6] : _nativeInfo (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]

-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 000000000000000000000000de4d377d8a8d455330edd7c4eb5b284ada1113d8
Arg [1] : 000000000000000000000000ecc19e177d24551aa7ed6bc6fe566eca726cc8a9
Arg [2] : 0000000000000000000000003c2269811836af69497e5f486a85d7316753cf62
Arg [3] : 000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2
Arg [4] : 000000000000000000000000000000000000000000000000000000000000006e
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [8] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [11] : 506f6c79676f6e00000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [13] : 4d41544943000000000000000000000000000000000000000000000000000000


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.