Sepolia Testnet

Token

Layerless rETH (lrETH)
ERC-20

Overview

Max Total Supply

0.9999 lrETH

Holders

1

Total Transfers

-

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
LayerlessLRT

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 1 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 43 : LayerlessLRT.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import "../oft/OFT.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../utils/AddressUtils.sol";
import "../eigenlayer/IStrategy.sol";
import "../eigenlayer/IDelegationManager.sol";
import "../eigenlayer/IStrategyManager.sol";

contract LayerlessLRT is OFT, ReentrancyGuard {
    event Restaked(address indexed user, uint256 lstAmount, uint256 ortAmount);
    event Unstaked(address indexed user, uint256 ortAmount);
    event AssetReceived(address indexed asset, address indexed from, uint amount);

    /* General structures */
    uint256 public deployedAt;
    address public rewardsManager;

    /* EigenLayer structures */
    IERC20 public lst;
    IStrategy public strategy;
    IStrategyManager public strategyManager;
    IDelegationManager public delegationManager;
    uint256 public minAmount = 100;

    /* Snapshotting structures */
    mapping(uint256 => mapping(address => mapping(address => uint256))) public snapshotContractAccountBalance;
    mapping(address => mapping(address => uint256)) public contractAccountLastSnapshot;
    mapping(address => mapping(address => mapping(uint256 => uint256))) public contractAccountSnapshotToPreviousSnapshot;
    mapping(uint256 => uint256) public snapshotNativeRewards;
    mapping(uint256 => mapping(address => uint256)) public snapshotAccountBalance;
    mapping(address => uint256) public accountLastSnapshot;
    mapping(address => mapping(uint256 => uint256)) public accountSnapshotToPreviousSnapshot;
    mapping(uint256 => uint256) public totalSupplySnapshot;
    mapping(address => mapping(uint256 => uint256)) public assetSnapshotRewards;
    mapping(address => uint256) public restakedOf;

    constructor(
        string memory _name,
        string memory _symbol,
        address _lst,
        address _strategy,
        address _lzEndpoint
    ) OFT(_name, _symbol, _lzEndpoint, msg.sender) {
        lst = IERC20(_lst);
        strategy = IStrategy(_strategy);
        strategyManager = IStrategyManager(address(0x779d1b5315df083e3F9E94cB495983500bA8E907));
        delegationManager = IDelegationManager(address(0x1b7b8F6b258f95Cf9596EabB9aa18B62940Eb0a8));
        deployedAt = block.timestamp;

        // TODO (Must): remove this
        _mint(msg.sender, 10 ** 18);
    }

    function restake(uint256 _amount) external nonReentrant {
        require(_amount >= minAmount, "<minLrtAmount");

        require(lst.transferFrom(msg.sender, address(this), _amount), "!transferFrom");
        lst.approve(address(strategyManager), _amount);

        // Restake (deposit into EigenLayer Strategy) and get shares
        uint256 shares = strategyManager.depositIntoStrategy(strategy, lst, _amount);
        restakedOf[msg.sender] += shares;

        // Mint LRT amount equivalent to shares
        _mint(msg.sender, shares);

        emit Restaked(msg.sender, _amount, shares);
    }

    function unstake(uint256[] memory _shares) external nonReentrant {
        require(_shares.length == 1, "Only one withdrawal at a time");
        uint256 amount = _shares[0];
        require(amount >= minAmount, "<minLrtAmount");
        require(balanceOf(msg.sender) >= amount, "<balanceOf");

        IDelegationManager.QueuedWithdrawalParams[] memory queuedWithdrawalParams = new IDelegationManager.QueuedWithdrawalParams[](1);
        IStrategy[] memory strategies = new IStrategy[](1);
        strategies[0] = strategy;
        queuedWithdrawalParams[0] = IDelegationManager.QueuedWithdrawalParams({
            shares: _shares,
            strategies: strategies,
            withdrawer: msg.sender
        });

        delegationManager.queueWithdrawals(queuedWithdrawalParams);

        // Burn LRT amount equivalent to shares
        _burn(msg.sender, amount);
        restakedOf[msg.sender] -= amount;

        emit Unstaked(msg.sender, amount);
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
        super._beforeTokenTransfer(from, to, amount);
        uint256 currentSnapshot = getCurrentSnapshot();

        if (AddressUtils.isContract(from) && from != address(this)) {
            uint256 contractLastSnapshot = contractAccountLastSnapshot[from][to];
            contractAccountLastSnapshot[from][to] = currentSnapshot;
            contractAccountSnapshotToPreviousSnapshot[from][to][currentSnapshot] = contractLastSnapshot;
            snapshotContractAccountBalance[currentSnapshot][from][to] = amount <= snapshotContractAccountBalance[currentSnapshot][from][to] ? snapshotContractAccountBalance[currentSnapshot][from][to] - amount : 0;
        } else {
            snapshotAccountBalance[currentSnapshot][from] = amount <= snapshotAccountBalance[currentSnapshot][from] ? snapshotAccountBalance[currentSnapshot][from] - amount : 0;
            uint256 fromLastSnapshot = accountLastSnapshot[from];
            accountLastSnapshot[from] = currentSnapshot;
            accountSnapshotToPreviousSnapshot[from][currentSnapshot] = fromLastSnapshot;
        }

        if (AddressUtils.isContract(to) && to != address(this)) {
            uint256 contractLastSnapshot = contractAccountLastSnapshot[to][from];
            contractAccountLastSnapshot[to][from] = currentSnapshot;
            contractAccountSnapshotToPreviousSnapshot[to][from][currentSnapshot] = contractLastSnapshot;
            snapshotContractAccountBalance[currentSnapshot][to][from] += amount;
        } else {
            snapshotAccountBalance[currentSnapshot][to] += amount;
            uint256 toLastSnapshot = accountLastSnapshot[to];
            accountLastSnapshot[to] = currentSnapshot;
            accountSnapshotToPreviousSnapshot[to][currentSnapshot] = toLastSnapshot;
        }
    }

    function _afterTokenTransfer(address from, address to, uint256 amount) internal override {
        super._afterTokenTransfer(from, to, amount);
        uint256 currentSnapshot = getCurrentSnapshot();
        totalSupplySnapshot[currentSnapshot] = totalSupply();
    }

    // Internal function to get the current snapshot (day since contract deployment) starting from day 1
    function getCurrentSnapshot() public view returns (uint256) {
        return ((block.timestamp - deployedAt) / 1 days) + 1;
    }

    function transferAssetToRewardsManager(address _asset) external onlyOwner nonReentrant {
        require(rewardsManager != address(0), "!rewardsManager");

        if (_asset == address(0)) {
            (bool success, ) = payable(rewardsManager).call{value: address(this).balance}("");
            require(success, "!success");
        } else {
            IERC20 asset = IERC20(_asset);
            uint256 balance = asset.balanceOf(address(this));
            require(asset.transfer(rewardsManager, balance), "!transfer");
        }
    }

    function setRewardsManager(address _rewardsManager) external onlyOwner {
        rewardsManager = _rewardsManager;
    }

    /* View Functions */

    function lrtToLst(uint256 _amount) public view returns (uint256) {
        return strategy.sharesToUnderlyingView(_amount);
    }

    function lstToLrt(uint256 _amount) public view returns (uint256) {
        return strategy.underlyingToSharesView(_amount);
    }

    receive() external payable {
        emit AssetReceived(address(0), msg.sender, msg.value);
        uint256 currentSnapshot = getCurrentSnapshot();
        snapshotNativeRewards[currentSnapshot] += msg.value;
        // Necessary to update the totalSupply snapshot to be set during the rewards claiming (rewardsPerSnapshot[snapshot])
        totalSupplySnapshot[currentSnapshot] = totalSupply();
    }
}

File 2 of 43 : OFT.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

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

/**
 * @title OFT Contract
 * @dev OFT is an ERC-20 token that extends the functionality of the OFTCore contract.
 */
contract OFT is OFTCore, ERC20 {
    /**
     * @dev Constructor for the OFT contract.
     * @param _name The name of the OFT.
     * @param _symbol The symbol of the OFT.
     * @param _lzEndpoint The LayerZero endpoint address.
     * @param _owner The owner of the contract.
     */
    constructor(
        string memory _name,
        string memory _symbol,
        address _lzEndpoint,
        address _owner
    ) ERC20(_name, _symbol) OFTCore(decimals(), _lzEndpoint, _owner) {}

    /**
     * @dev Retrieves the OFT contract version.
     * @return major The major version.
     * @return minor The minor version.
     *
     * @dev major version: Indicates a cross-chain compatible msg encoding with other OFTs.
     * @dev minor version: Indicates a version within the local chains context. eg. OFTAdapter vs. OFT
     * @dev For example, if a new feature is added to the OFT contract, the minor version will be incremented.
     * @dev If a new feature is added to the OFT cross-chain msg encoding, the major version will be incremented.
     * ie. localOFT version(1,1) CAN send messages to remoteOFT version(1,2)
     */
    function oftVersion() external pure returns (uint64 major, uint64 minor) {
        return (1, 1);
    }

    /**
     * @dev Retrieves the address of the underlying ERC20 implementation.
     * @return The address of the OFT token.
     *
     * @dev In the case of OFT, address(this) and erc20 are the same contract.
     */
    function token() external view returns (address) {
        return address(this);
    }

    /**
     * @dev Burns tokens from the sender's specified balance.
     * @param _amountToSendLD The amount of tokens to send in local decimals.
     * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
     * @param _dstEid The destination chain ID.
     * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
     * @return amountToCreditLD The amount of tokens to credit in local decimals.
     */
    function _debitSender(
        uint256 _amountToSendLD,
        uint256 _minAmountToCreditLD,
        uint32 _dstEid
    ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
        (amountDebitedLD, amountToCreditLD) = _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid);

        // @dev In NON-default OFT, amountDebited could be 100, with a 10% fee, the credited amount is 90,
        // therefore amountDebited CAN differ from amountToCredit.

        // @dev Default OFT burns on src.
        _burn(msg.sender, amountDebitedLD);
    }

    /**
     * @dev Burns tokens that have been sent into this contract.
     * @param _minAmountToReceiveLD The minimum amount to receive in local decimals.
     * @param _dstEid The destination chain ID.
     * @return amountDebitedLD The amount of tokens ACTUALLY debited in local decimals.
     * @return amountToCreditLD The amount of tokens to credit in local decimals.
     */
    function _debitThis(
        uint256 _minAmountToReceiveLD,
        uint32 _dstEid
    ) internal virtual override returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
        // @dev This is the push method, where at any point in the transaction, the OFT receives tokens and they can be sent by the caller.
        // @dev This SHOULD be done atomically, otherwise any caller can spend tokens that are owned by the contract.
        // @dev In the NON-default case where fees are stored in the contract, there should be a value reserved via a global state.
        // eg. balanceOf(address(this)) - accruedFees;
        (amountDebitedLD, amountToCreditLD) = _debitView(balanceOf(address(this)), _minAmountToReceiveLD, _dstEid);

        // @dev Default OFT burns on src.
        _burn(address(this), amountDebitedLD);

        // @dev When sending tokens direct to the OFT contract,
        // there is NOT a default mechanism to capture the dust that MIGHT get left in the contract.
        // If you want to refund this dust, will need to add another function to return it.
    }

    /**
     * @dev Credits tokens to the specified address.
     * @param _to The address to credit the tokens to.
     * @param _amountToCreditLD The amount of tokens to credit in local decimals.
     * @dev _srcEid The source chain ID.
     * @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
     */
    function _credit(
        address _to,
        uint256 _amountToCreditLD,
        uint32 /*_srcEid*/
    ) internal virtual override returns (uint256 amountReceivedLD) {
        // @dev Default OFT mints on dst.
        _mint(_to, _amountToCreditLD);
        // @dev In the case of NON-default OFT, the amountToCreditLD MIGHT not == amountReceivedLD.
        return _amountToCreditLD;
    }
}

File 3 of 43 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @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);
}

File 4 of 43 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 5 of 43 : AddressUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

library AddressUtils {
    function isContract(address addr) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(addr)
        }
        return size > 0;
    }
}

File 6 of 43 : IStrategy.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title Minimal interface for an `Strategy` contract.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice Custom `Strategy` implementations may expand extensively on this interface.
 */
interface IStrategy {
    /**
     * @notice Used to deposit tokens into this Strategy
     * @param token is the ERC20 token being deposited
     * @param amount is the amount of token being deposited
     * @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
     * `depositIntoStrategy` function, and individual share balances are recorded in the strategyManager as well.
     * @return newShares is the number of new shares issued at the current exchange ratio.
     */
    function deposit(IERC20 token, uint256 amount) external returns (uint256);

    /**
     * @notice Used to withdraw tokens from this Strategy, to the `recipient`'s address
     * @param recipient is the address to receive the withdrawn funds
     * @param token is the ERC20 token being transferred out
     * @param amountShares is the amount of shares being withdrawn
     * @dev This function is only callable by the strategyManager contract. It is invoked inside of the strategyManager's
     * other functions, and individual share balances are recorded in the strategyManager as well.
     */
    function withdraw(address recipient, IERC20 token, uint256 amountShares) external;

    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @return The amount of underlying tokens corresponding to the input `amountShares`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function sharesToUnderlying(uint256 amountShares) external returns (uint256);

    /**
     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
     * @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications
     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
     * @return The amount of underlying tokens corresponding to the input `amountShares`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function underlyingToShares(uint256 amountUnderlying) external returns (uint256);

    /**
     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
     * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications
     */
    function userUnderlying(address user) external returns (uint256);

    /**
     * @notice convenience function for fetching the current total shares of `user` in this strategy, by
     * querying the `strategyManager` contract
     */
    function shares(address user) external view returns (uint256);

    /**
     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.
     * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications
     * @param amountShares is the amount of shares to calculate its conversion into the underlying token
     * @return The amount of shares corresponding to the input `amountUnderlying`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);

    /**
     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.
     * @notice In contrast to `underlyingToShares`, this function guarantees no state modifications
     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares
     * @return The amount of shares corresponding to the input `amountUnderlying`
     * @dev Implementation for these functions in particular may vary significantly for different strategies
     */
    function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);

    /**
     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in
     * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications
     */
    function userUnderlyingView(address user) external view returns (uint256);

    /// @notice The underlying token for shares in this Strategy
    function underlyingToken() external view returns (IERC20);

    /// @notice The total number of extant shares in this Strategy
    function totalShares() external view returns (uint256);

    /// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.
    function explanation() external view returns (string memory);
}

File 7 of 43 : IDelegationManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;

import "./IStrategy.sol";
import "./ISignatureUtils.sol";
import "./IStrategyManager.sol";

/**
 * @title DelegationManager
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice  This is the contract for delegation in EigenLayer. The main functionalities of this contract are
 * - enabling anyone to register as an operator in EigenLayer
 * - allowing operators to specify parameters related to stakers who delegate to them
 * - enabling any staker to delegate its stake to the operator of its choice (a given staker can only delegate to a single operator at a time)
 * - enabling a staker to undelegate its assets from the operator it is delegated to (performed as part of the withdrawal process, initiated through the StrategyManager)
 */
interface IDelegationManager is ISignatureUtils {
    // @notice Struct used for storing information about a single operator who has registered with EigenLayer
    struct OperatorDetails {
        // @notice address to receive the rewards that the operator earns via serving applications built on EigenLayer.
        address earningsReceiver;
        /**
         * @notice Address to verify signatures when a staker wishes to delegate to the operator, as well as controlling "forced undelegations".
         * @dev Signature verification follows these rules:
         * 1) If this address is left as address(0), then any staker will be free to delegate to the operator, i.e. no signature verification will be performed.
         * 2) If this address is an EOA (i.e. it has no code), then we follow standard ECDSA signature verification for delegations to the operator.
         * 3) If this address is a contract (i.e. it has code) then we forward a call to the contract and verify that it returns the correct EIP-1271 "magic value".
         */
        address delegationApprover;
        /**
         * @notice A minimum delay -- measured in blocks -- enforced between:
         * 1) the operator signalling their intent to register for a service, via calling `Slasher.optIntoSlashing`
         * and
         * 2) the operator completing registration for the service, via the service ultimately calling `Slasher.recordFirstStakeUpdate`
         * @dev note that for a specific operator, this value *cannot decrease*, i.e. if the operator wishes to modify their OperatorDetails,
         * then they are only allowed to either increase this value or keep it the same.
         */
        uint32 stakerOptOutWindowBlocks;
    }

    /**
     * @notice Abstract struct used in calculating an EIP712 signature for a staker to approve that they (the staker themselves) delegate to a specific operator.
     * @dev Used in computing the `STAKER_DELEGATION_TYPEHASH` and as a reference in the computation of the stakerDigestHash in the `delegateToBySignature` function.
     */
    struct StakerDelegation {
        // the staker who is delegating
        address staker;
        // the operator being delegated to
        address operator;
        // the staker's nonce
        uint256 nonce;
        // the expiration timestamp (UTC) of the signature
        uint256 expiry;
    }

    /**
     * @notice Abstract struct used in calculating an EIP712 signature for an operator's delegationApprover to approve that a specific staker delegate to the operator.
     * @dev Used in computing the `DELEGATION_APPROVAL_TYPEHASH` and as a reference in the computation of the approverDigestHash in the `_delegate` function.
     */
    struct DelegationApproval {
        // the staker who is delegating
        address staker;
        // the operator being delegated to
        address operator;
        // the operator's provided salt
        bytes32 salt;
        // the expiration timestamp (UTC) of the signature
        uint256 expiry;
    }

    /**
     * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored.
     * In functions that operate on existing queued withdrawals -- e.g. completeQueuedWithdrawal`, the data is resubmitted and the hash of the submitted
     * data is computed by `calculateWithdrawalRoot` and checked against the stored hash in order to confirm the integrity of the submitted data.
     */
    struct Withdrawal {
        // The address that originated the Withdrawal
        address staker;
        // The address that the staker was delegated to at the time that the Withdrawal was created
        address delegatedTo;
        // The address that can complete the Withdrawal + will receive funds when completing the withdrawal
        address withdrawer;
        // Nonce used to guarantee that otherwise identical withdrawals have unique hashes
        uint256 nonce;
        // Block number when the Withdrawal was created
        uint32 startBlock;
        // Array of strategies that the Withdrawal contains
        IStrategy[] strategies;
        // Array containing the amount of shares in each Strategy in the `strategies` array
        uint256[] shares;
    }

    struct QueuedWithdrawalParams {
        // Array of strategies that the QueuedWithdrawal contains
        IStrategy[] strategies;
        // Array containing the amount of shares in each Strategy in the `strategies` array
        uint256[] shares;
        // The address of the withdrawer
        address withdrawer;
    }

    /// @notice Enum representing the status of an operator's registration with an AVS
    enum OperatorAVSRegistrationStatus {
        UNREGISTERED,       // Operator not registered to AVS
        REGISTERED          // Operator registered to AVS
    }

    // @notice Emitted when a new operator registers in EigenLayer and provides their OperatorDetails.
    event OperatorRegistered(address indexed operator, OperatorDetails operatorDetails);

    /// @notice Emitted when an operator updates their OperatorDetails to @param newOperatorDetails
    event OperatorDetailsModified(address indexed operator, OperatorDetails newOperatorDetails);

    /**
     * @notice Emitted when @param operator indicates that they are updating their MetadataURI string
     * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing
     */
    event OperatorMetadataURIUpdated(address indexed operator, string metadataURI);

    /**
     * @notice Emitted when @param avs indicates that they are updating their MetadataURI string
     * @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing
     */
    event AVSMetadataURIUpdated(address indexed avs, string metadataURI);

    /// @notice Emitted when an operator's registration status for an AVS is updated
    event OperatorAVSRegistrationStatusUpdated(address indexed operator, address indexed avs, OperatorAVSRegistrationStatus status);

    /// @notice Emitted whenever an operator's shares are increased for a given strategy. Note that shares is the delta in the operator's shares.
    event OperatorSharesIncreased(address indexed operator, address staker, IStrategy strategy, uint256 shares);

    /// @notice Emitted whenever an operator's shares are decreased for a given strategy. Note that shares is the delta in the operator's shares.
    event OperatorSharesDecreased(address indexed operator, address staker, IStrategy strategy, uint256 shares);

    /// @notice Emitted when @param staker delegates to @param operator.
    event StakerDelegated(address indexed staker, address indexed operator);

    /// @notice Emitted when @param staker undelegates from @param operator.
    event StakerUndelegated(address indexed staker, address indexed operator);

    /// @notice Emitted when @param staker is undelegated via a call not originating from the staker themself
    event StakerForceUndelegated(address indexed staker, address indexed operator);

    /**
     * @notice Emitted when a new withdrawal is queued.
     * @param withdrawalRoot Is the hash of the `withdrawal`.
     * @param withdrawal Is the withdrawal itself.
     */
    event WithdrawalQueued(bytes32 withdrawalRoot, Withdrawal withdrawal);

    /// @notice Emitted when a queued withdrawal is completed
    event WithdrawalCompleted(bytes32 withdrawalRoot);

    /// @notice Emitted when a queued withdrawal is *migrated* from the StrategyManager to the DelegationManager
    event WithdrawalMigrated(bytes32 oldWithdrawalRoot, bytes32 newWithdrawalRoot);

    /// @notice Emitted when the `withdrawalDelayBlocks` variable is modified from `previousValue` to `newValue`.
    event WithdrawalDelayBlocksSet(uint256 previousValue, uint256 newValue);

    /**
     * @notice Registers the caller as an operator in EigenLayer.
     * @param registeringOperatorDetails is the `OperatorDetails` for the operator.
     * @param metadataURI is a URI for the operator's metadata, i.e. a link providing more details on the operator.
     *
     * @dev Once an operator is registered, they cannot 'deregister' as an operator, and they will forever be considered "delegated to themself".
     * @dev This function will revert if the caller attempts to set their `earningsReceiver` to address(0).
     * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
     */
    function registerAsOperator(
        OperatorDetails calldata registeringOperatorDetails,
        string calldata metadataURI
    ) external;

    /**
     * @notice Updates an operator's stored `OperatorDetails`.
     * @param newOperatorDetails is the updated `OperatorDetails` for the operator, to replace their current OperatorDetails`.
     *
     * @dev The caller must have previously registered as an operator in EigenLayer.
     * @dev This function will revert if the caller attempts to set their `earningsReceiver` to address(0).
     */
    function modifyOperatorDetails(OperatorDetails calldata newOperatorDetails) external;

    /**
     * @notice Called by an operator to emit an `OperatorMetadataURIUpdated` event indicating the information has updated.
     * @param metadataURI The URI for metadata associated with an operator
     * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `OperatorMetadataURIUpdated` event
     */
    function updateOperatorMetadataURI(string calldata metadataURI) external;

    /**
     * @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
     * @param metadataURI The URI for metadata associated with an AVS
     * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `AVSMetadataURIUpdated` event
     */
    function updateAVSMetadataURI(string calldata metadataURI) external;

    /**
     * @notice Caller delegates their stake to an operator.
     * @param operator The account (`msg.sender`) is delegating its assets to for use in serving applications built on EigenLayer.
     * @param approverSignatureAndExpiry Verifies the operator approves of this delegation
     * @param approverSalt A unique single use value tied to an individual signature.
     * @dev The approverSignatureAndExpiry is used in the event that:
     *          1) the operator's `delegationApprover` address is set to a non-zero value.
     *                  AND
     *          2) neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator
     *             or their delegationApprover is the `msg.sender`, then approval is assumed.
     * @dev In the event that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input
     * in this case to save on complexity + gas costs
     */
    function delegateTo(
        address operator,
        SignatureWithExpiry memory approverSignatureAndExpiry,
        bytes32 approverSalt
    ) external;

    /**
     * @notice Caller delegates a staker's stake to an operator with valid signatures from both parties.
     * @param staker The account delegating stake to an `operator` account
     * @param operator The account (`staker`) is delegating its assets to for use in serving applications built on EigenLayer.
     * @param stakerSignatureAndExpiry Signed data from the staker authorizing delegating stake to an operator
     * @param approverSignatureAndExpiry is a parameter that will be used for verifying that the operator approves of this delegation action in the event that:
     * @param approverSalt Is a salt used to help guarantee signature uniqueness. Each salt can only be used once by a given approver.
     *
     * @dev If `staker` is an EOA, then `stakerSignature` is verified to be a valid ECDSA stakerSignature from `staker`, indicating their intention for this action.
     * @dev If `staker` is a contract, then `stakerSignature` will be checked according to EIP-1271.
     * @dev the operator's `delegationApprover` address is set to a non-zero value.
     * @dev neither the operator nor their `delegationApprover` is the `msg.sender`, since in the event that the operator or their delegationApprover
     * is the `msg.sender`, then approval is assumed.
     * @dev This function will revert if the current `block.timestamp` is equal to or exceeds the expiry
     * @dev In the case that `approverSignatureAndExpiry` is not checked, its content is ignored entirely; it's recommended to use an empty input
     * in this case to save on complexity + gas costs
     */
    function delegateToBySignature(
        address staker,
        address operator,
        SignatureWithExpiry memory stakerSignatureAndExpiry,
        SignatureWithExpiry memory approverSignatureAndExpiry,
        bytes32 approverSalt
    ) external;

    /**
     * @notice Undelegates the staker from the operator who they are delegated to. Puts the staker into the "undelegation limbo" mode of the EigenPodManager
     * and queues a withdrawal of all of the staker's shares in the StrategyManager (to the staker), if necessary.
     * @param staker The account to be undelegated.
     * @return withdrawalRoot The root of the newly queued withdrawal, if a withdrawal was queued. Otherwise just bytes32(0).
     *
     * @dev Reverts if the `staker` is also an operator, since operators are not allowed to undelegate from themselves.
     * @dev Reverts if the caller is not the staker, nor the operator who the staker is delegated to, nor the operator's specified "delegationApprover"
     * @dev Reverts if the `staker` is already undelegated.
     */
    function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot);

    /**
     * Allows a staker to withdraw some shares. Withdrawn shares/strategies are immediately removed
     * from the staker. If the staker is delegated, withdrawn shares/strategies are also removed from
     * their operator.
     *
     * All withdrawn shares/strategies are placed in a queue and can be fully withdrawn after a delay.
     */
    function queueWithdrawals(
        QueuedWithdrawalParams[] calldata queuedWithdrawalParams
    ) external returns (bytes32[] memory);

    /**
     * @notice Used to complete the specified `withdrawal`. The caller must match `withdrawal.withdrawer`
     * @param withdrawal The Withdrawal to complete.
     * @param tokens Array in which the i-th entry specifies the `token` input to the 'withdraw' function of the i-th Strategy in the `withdrawal.strategies` array.
     * This input can be provided with zero length if `receiveAsTokens` is set to 'false' (since in that case, this input will be unused)
     * @param middlewareTimesIndex is the index in the operator that the staker who triggered the withdrawal was delegated to's middleware times array
     * @param receiveAsTokens If true, the shares specified in the withdrawal will be withdrawn from the specified strategies themselves
     * and sent to the caller, through calls to `withdrawal.strategies[i].withdraw`. If false, then the shares in the specified strategies
     * will simply be transferred to the caller directly.
     * @dev middlewareTimesIndex should be calculated off chain before calling this function by finding the first index that satisfies `slasher.canWithdraw`
     * @dev beaconChainETHStrategy shares are non-transferrable, so if `receiveAsTokens = false` and `withdrawal.withdrawer != withdrawal.staker`, note that
     * any beaconChainETHStrategy shares in the `withdrawal` will be _returned to the staker_, rather than transferred to the withdrawer, unlike shares in
     * any other strategies, which will be transferred to the withdrawer.
     */
    function completeQueuedWithdrawal(
        Withdrawal calldata withdrawal,
        IERC20[] calldata tokens,
        uint256 middlewareTimesIndex,
        bool receiveAsTokens
    ) external;

    /**
     * @notice Array-ified version of `completeQueuedWithdrawal`.
     * Used to complete the specified `withdrawals`. The function caller must match `withdrawals[...].withdrawer`
     * @param withdrawals The Withdrawals to complete.
     * @param tokens Array of tokens for each Withdrawal. See `completeQueuedWithdrawal` for the usage of a single array.
     * @param middlewareTimesIndexes One index to reference per Withdrawal. See `completeQueuedWithdrawal` for the usage of a single index.
     * @param receiveAsTokens Whether or not to complete each withdrawal as tokens. See `completeQueuedWithdrawal` for the usage of a single boolean.
     * @dev See `completeQueuedWithdrawal` for relevant dev tags
     */
    function completeQueuedWithdrawals(
        Withdrawal[] calldata withdrawals,
        IERC20[][] calldata tokens,
        uint256[] calldata middlewareTimesIndexes,
        bool[] calldata receiveAsTokens
    ) external;

    /**
     * @notice Increases a staker's delegated share balance in a strategy.
     * @param staker The address to increase the delegated shares for their operator.
     * @param strategy The strategy in which to increase the delegated shares.
     * @param shares The number of shares to increase.
     *
     * @dev *If the staker is actively delegated*, then increases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing.
     * @dev Callable only by the StrategyManager or EigenPodManager.
     */
    function increaseDelegatedShares(
        address staker,
        IStrategy strategy,
        uint256 shares
    ) external;

    /**
     * @notice Decreases a staker's delegated share balance in a strategy.
     * @param staker The address to increase the delegated shares for their operator.
     * @param strategy The strategy in which to decrease the delegated shares.
     * @param shares The number of shares to decrease.
     *
     * @dev *If the staker is actively delegated*, then decreases the `staker`'s delegated shares in `strategy` by `shares`. Otherwise does nothing.
     * @dev Callable only by the StrategyManager or EigenPodManager.
     */
    function decreaseDelegatedShares(
        address staker,
        IStrategy strategy,
        uint256 shares
    ) external;

    /**
     * @notice Called by an avs to register an operator with the avs.
     * @param operator The address of the operator to register.
     * @param operatorSignature The signature, salt, and expiry of the operator's signature.
     */
    function registerOperatorToAVS(
        address operator,
        ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature
    ) external;

    /**
     * @notice Called by an avs to deregister an operator with the avs.
     * @param operator The address of the operator to deregister.
     */
    function deregisterOperatorFromAVS(address operator) external;

    /**
     * @notice Returns whether or not the salt has already been used by the operator.
     * @dev Salts is used in the `registerOperatorToAVS` function.
     */
    function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool);

    /**
     * @notice Calculates the digest hash to be signed by an operator to register with an AVS
     * @param operator The account registering as an operator
     * @param avs The AVS the operator is registering to
     * @param salt A unique and single use value associated with the approver signature.
     * @param expiry Time after which the approver's signature becomes invalid
     */
    function calculateOperatorAVSRegistrationDigestHash(
        address operator,
        address avs,
        bytes32 salt,
        uint256 expiry
    ) external view returns (bytes32);

    /**
     * @notice returns the address of the operator that `staker` is delegated to.
     * @notice Mapping: staker => operator whom the staker is currently delegated to.
     * @dev Note that returning address(0) indicates that the staker is not actively delegated to any operator.
     */
    function delegatedTo(address staker) external view returns (address);

    /**
     * @notice Returns the OperatorDetails struct associated with an `operator`.
     */
    function operatorDetails(address operator) external view returns (OperatorDetails memory);

    /*
     * @notice Returns the earnings receiver address for an operator
     */
    function earningsReceiver(address operator) external view returns (address);

    /**
     * @notice Returns the delegationApprover account for an operator
     */
    function delegationApprover(address operator) external view returns (address);

    /**
     * @notice Returns the stakerOptOutWindowBlocks for an operator
     */
    function stakerOptOutWindowBlocks(address operator) external view returns (uint256);

    /**
     * @notice returns the total number of shares in `strategy` that are delegated to `operator`.
     * @notice Mapping: operator => strategy => total number of shares in the strategy delegated to the operator.
     * @dev By design, the following invariant should hold for each Strategy:
     * (operator's shares in delegation manager) = sum (shares above zero of all stakers delegated to operator)
     * = sum (delegateable shares of all stakers delegated to the operator)
     */
    function operatorShares(address operator, IStrategy strategy) external view returns (uint256);

    /**
     * @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.
     */
    function isDelegated(address staker) external view returns (bool);

    /**
     * @notice Returns true is an operator has previously registered for delegation.
     */
    function isOperator(address operator) external view returns (bool);

    /// @notice Mapping: staker => number of signed delegation nonces (used in `delegateToBySignature`) from the staker that the contract has already checked
    function stakerNonce(address staker) external view returns (uint256);

    /**
     * @notice Mapping: delegationApprover => 32-byte salt => whether or not the salt has already been used by the delegationApprover.
     * @dev Salts are used in the `delegateTo` and `delegateToBySignature` functions. Note that these functions only process the delegationApprover's
     * signature + the provided salt if the operator being delegated to has specified a nonzero address as their `delegationApprover`.
     */
    function delegationApproverSaltIsSpent(address _delegationApprover, bytes32 salt) external view returns (bool);

    /**
     * @notice Minimum delay enforced by this contract for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner,
     * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced).
     * @dev Note that the withdrawal delay is not enforced on withdrawals of 'beaconChainETH', as the EigenPods have their own separate delay mechanic
     * and we want to avoid stacking multiple enforced delays onto a single withdrawal.
     */
    function withdrawalDelayBlocks() external view returns (uint256);

    /**
     * @notice Calculates the digestHash for a `staker` to sign to delegate to an `operator`
     * @param staker The signing staker
     * @param operator The operator who is being delegated to
     * @param expiry The desired expiry time of the staker's signature
     */
    function calculateCurrentStakerDelegationDigestHash(
        address staker,
        address operator,
        uint256 expiry
    ) external view returns (bytes32);

    /**
     * @notice Calculates the digest hash to be signed and used in the `delegateToBySignature` function
     * @param staker The signing staker
     * @param _stakerNonce The nonce of the staker. In practice we use the staker's current nonce, stored at `stakerNonce[staker]`
     * @param operator The operator who is being delegated to
     * @param expiry The desired expiry time of the staker's signature
     */
    function calculateStakerDelegationDigestHash(
        address staker,
        uint256 _stakerNonce,
        address operator,
        uint256 expiry
    ) external view returns (bytes32);

    /**
     * @notice Calculates the digest hash to be signed by the operator's delegationApprove and used in the `delegateTo` and `delegateToBySignature` functions.
     * @param staker The account delegating their stake
     * @param operator The account receiving delegated stake
     * @param _delegationApprover the operator's `delegationApprover` who will be signing the delegationHash (in general)
     * @param approverSalt A unique and single use value associated with the approver signature.
     * @param expiry Time after which the approver's signature becomes invalid
     */
    function calculateDelegationApprovalDigestHash(
        address staker,
        address operator,
        address _delegationApprover,
        bytes32 approverSalt,
        uint256 expiry
    ) external view returns (bytes32);

    /// @notice The EIP-712 typehash for the contract's domain
    function DOMAIN_TYPEHASH() external view returns (bytes32);

    /// @notice The EIP-712 typehash for the StakerDelegation struct used by the contract
    function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32);

    /// @notice The EIP-712 typehash for the DelegationApproval struct used by the contract
    function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32);

    /// @notice The EIP-712 typehash for the Registration struct used by the contract
    function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32);

    /**
     * @notice Getter function for the current EIP-712 domain separator for this contract.
     *
     * @dev The domain separator will change in the event of a fork that changes the ChainID.
     * @dev By introducing a domain separator the DApp developers are guaranteed that there can be no signature collision.
     * for more detailed information please read EIP-712.
     */
    function domainSeparator() external view returns (bytes32);

    /// @notice Mapping: staker => cumulative number of queued withdrawals they have ever initiated.
    /// @dev This only increments (doesn't decrement), and is used to help ensure that otherwise identical withdrawals have unique hashes.
    function cumulativeWithdrawalsQueued(address staker) external view returns (uint256);

    /// @notice Returns the keccak256 hash of `withdrawal`.
    function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32);

    function migrateQueuedWithdrawals(IStrategyManager.DeprecatedStruct_QueuedWithdrawal[] memory withdrawalsToQueue) external;
}

File 8 of 43 : IStrategyManager.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;

import "./IStrategy.sol";
import "./IDelegationManager.sol";

/**
 * @title Interface for the primary entrypoint for funds into EigenLayer.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 * @notice See the `StrategyManager` contract itself for implementation details.
 */
interface IStrategyManager {
    /**
     * @notice Emitted when a new deposit occurs on behalf of `staker`.
     * @param staker Is the staker who is depositing funds into EigenLayer.
     * @param strategy Is the strategy that `staker` has deposited into.
     * @param token Is the token that `staker` deposited.
     * @param shares Is the number of new shares `staker` has been granted in `strategy`.
     */
    event Deposit(address staker, IERC20 token, IStrategy strategy, uint256 shares);

    /// @notice Emitted when the `strategyWhitelister` is changed
    event StrategyWhitelisterChanged(address previousAddress, address newAddress);

    /// @notice Emitted when a strategy is added to the approved list of strategies for deposit
    event StrategyAddedToDepositWhitelist(IStrategy strategy);

    /// @notice Emitted when a strategy is removed from the approved list of strategies for deposit
    event StrategyRemovedFromDepositWhitelist(IStrategy strategy);

    /**
     * @notice Deposits `amount` of `token` into the specified `strategy`, with the resultant shares credited to `msg.sender`
     * @param strategy is the specified strategy where deposit is to be made,
     * @param token is the denomination in which the deposit is to be made,
     * @param amount is the amount of token to be deposited in the strategy by the staker
     * @return shares The amount of new shares in the `strategy` created as part of the action.
     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
     * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen).
     *
     * WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended.  This can lead to attack vectors
     *          where the token balance and corresponding strategy shares are not in sync upon reentrancy.
     */
    function depositIntoStrategy(IStrategy strategy, IERC20 token, uint256 amount) external returns (uint256 shares);

    /**
     * @notice Used for depositing an asset into the specified strategy with the resultant shares credited to `staker`,
     * who must sign off on the action.
     * Note that the assets are transferred out/from the `msg.sender`, not from the `staker`; this function is explicitly designed
     * purely to help one address deposit 'for' another.
     * @param strategy is the specified strategy where deposit is to be made,
     * @param token is the denomination in which the deposit is to be made,
     * @param amount is the amount of token to be deposited in the strategy by the staker
     * @param staker the staker that the deposited assets will be credited to
     * @param expiry the timestamp at which the signature expires
     * @param signature is a valid signature from the `staker`. either an ECDSA signature if the `staker` is an EOA, or data to forward
     * following EIP-1271 if the `staker` is a contract
     * @return shares The amount of new shares in the `strategy` created as part of the action.
     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.
     * @dev A signature is required for this function to eliminate the possibility of griefing attacks, specifically those
     * targeting stakers who may be attempting to undelegate.
     * @dev Cannot be called on behalf of a staker that is 'frozen' (this function will revert if the `staker` is frozen).
     *
     *  WARNING: Depositing tokens that allow reentrancy (eg. ERC-777) into a strategy is not recommended.  This can lead to attack vectors
     *          where the token balance and corresponding strategy shares are not in sync upon reentrancy
     */
    function depositIntoStrategyWithSignature(
        IStrategy strategy,
        IERC20 token,
        uint256 amount,
        address staker,
        uint256 expiry,
        bytes memory signature
    ) external returns (uint256 shares);

    /// @notice Used by the DelegationManager to remove a Staker's shares from a particular strategy when entering the withdrawal queue
    function removeShares(address staker, IStrategy strategy, uint256 shares) external;

    /// @notice Used by the DelegationManager to award a Staker some shares that have passed through the withdrawal queue
    function addShares(address staker, IStrategy strategy, uint256 shares) external;

    /// @notice Used by the DelegationManager to convert withdrawn shares to tokens and send them to a recipient
    function withdrawSharesAsTokens(address recipient, IStrategy strategy, uint256 shares, IERC20 token) external;

    /// @notice Returns the current shares of `user` in `strategy`
    function stakerStrategyShares(address user, IStrategy strategy) external view returns (uint256 shares);

    /**
     * @notice Get all details on the staker's deposits and corresponding shares
     * @return (staker's strategies, shares in these strategies)
     */
    function getDeposits(address staker) external view returns (IStrategy[] memory, uint256[] memory);

    /// @notice Simple getter function that returns `stakerStrategyList[staker].length`.
    function stakerStrategyListLength(address staker) external view returns (uint256);

    /**
     * @notice Owner-only function that adds the provided Strategies to the 'whitelist' of strategies that stakers can deposit into
     * @param strategiesToWhitelist Strategies that will be added to the `strategyIsWhitelistedForDeposit` mapping (if they aren't in it already)
     */
    function addStrategiesToDepositWhitelist(IStrategy[] calldata strategiesToWhitelist) external;

    /**
     * @notice Owner-only function that removes the provided Strategies from the 'whitelist' of strategies that stakers can deposit into
     * @param strategiesToRemoveFromWhitelist Strategies that will be removed to the `strategyIsWhitelistedForDeposit` mapping (if they are in it)
     */
    function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external;

    /// @notice Returns the single, central Delegation contract of EigenLayer
    function delegation() external view returns (IDelegationManager);

    /// @notice Returns the address of the `strategyWhitelister`
    function strategyWhitelister() external view returns (address);

// LIMITED BACKWARDS-COMPATIBILITY FOR DEPRECATED FUNCTIONALITY
    // packed struct for queued withdrawals; helps deal with stack-too-deep errors
    struct DeprecatedStruct_WithdrawerAndNonce {
        address withdrawer;
        uint96 nonce;
    }

    /**
     * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored.
     * In functions that operate on existing queued withdrawals -- e.g. `startQueuedWithdrawalWaitingPeriod` or `completeQueuedWithdrawal`,
     * the data is resubmitted and the hash of the submitted data is computed by `calculateWithdrawalRoot` and checked against the
     * stored hash in order to confirm the integrity of the submitted data.
     */
    struct DeprecatedStruct_QueuedWithdrawal {
        IStrategy[] strategies;
        uint256[] shares;
        address staker;
        DeprecatedStruct_WithdrawerAndNonce withdrawerAndNonce;
        uint32 withdrawalStartBlock;
        address delegatedAddress;
    }

    function migrateQueuedWithdrawal(DeprecatedStruct_QueuedWithdrawal memory queuedWithdrawal) external returns (bool, bytes32);

    function calculateWithdrawalRoot(DeprecatedStruct_QueuedWithdrawal memory queuedWithdrawal) external pure returns (bytes32);
}

File 9 of 43 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - amount);
        }

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

File 10 of 43 : OFTCore.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { OApp, Origin } from "../oapp/OApp.sol";
import { OAppOptionsType3 } from "../oapp/libs/OAppOptionsType3.sol";
import { IOAppMsgInspector } from "../oapp/interfaces/IOAppMsgInspector.sol";

import { OAppPreCrimeSimulator } from "../precrime/OAppPreCrimeSimulator.sol";

import { IOFT, SendParam, OFTLimit, OFTReceipt, OFTFeeDetail, MessagingReceipt, MessagingFee } from "./interfaces/IOFT.sol";
import { OFTMsgCodec } from "./libs/OFTMsgCodec.sol";
import { OFTComposeMsgCodec } from "./libs/OFTComposeMsgCodec.sol";

/**
 * @title OFTCore
 * @dev Abstract contract for the OftChain (OFT) token.
 */
abstract contract OFTCore is IOFT, OApp, OAppPreCrimeSimulator, OAppOptionsType3 {
    using OFTMsgCodec for bytes;
    using OFTMsgCodec for bytes32;

    // @notice Provides a conversion rate when swapping between denominations of SD and LD
    //      - shareDecimals == SD == shared Decimals
    //      - localDecimals == LD == local decimals
    // @dev Considers that tokens have different decimal amounts on various chains.
    // @dev eg.
    //  For a token
    //      - locally with 4 decimals --> 1.2345 => uint(12345)
    //      - remotely with 2 decimals --> 1.23 => uint(123)
    //      - The conversion rate would be 10 ** (4 - 2) = 100
    //  @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote,
    //  you can only display 1.23 -> uint(123).
    //  @dev To preserve the dust that would otherwise be lost on that conversion,
    //  we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh
    uint256 public immutable decimalConversionRate;

    // @notice Msg types that are used to identify the various OFT operations.
    // @dev This can be extended in child contracts for non-default oft operations
    // @dev These values are used in things like combineOptions() in OAppOptionsType3.sol.
    uint16 public constant SEND = 1;
    uint16 public constant SEND_AND_CALL = 2;

    // Address of an optional contract to inspect both 'message' and 'options'
    address public msgInspector;

    /**
     * @dev Constructor.
     * @param _localDecimals The decimals of the token on the local chain (this chain).
     * @param _endpoint The address of the LayerZero endpoint.
     * @param _owner The address of the OFT owner.
     */
    constructor(uint8 _localDecimals, address _endpoint, address _owner) OApp(_endpoint, _owner) {
        if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals();
        decimalConversionRate = 10 ** (_localDecimals - sharedDecimals());
    }

    /**
     * @dev Retrieves the shared decimals of the OFT.
     * @return The shared decimals of the OFT.
     *
     * @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap
     * Lowest common decimal denominator between chains.
     * Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).
     * For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.
     * ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615
     */
    function sharedDecimals() public pure virtual returns (uint8) {
        return 4;
    }

    /**
     * @dev Sets the message inspector address for the OFT.
     * @param _msgInspector The address of the message inspector.
     *
     * @dev This is an optional contract that can be used to inspect both 'message' and 'options'.
     * @dev Set it to address(0) to disable it, or set it to a contract address to enable it.
     */
    function setMsgInspector(address _msgInspector) public virtual onlyOwner {
        msgInspector = _msgInspector;
        emit MsgInspectorSet(_msgInspector);
    }

    /**
     * @notice Provides a quote for OFT-related operations.
     * @param _sendParam The parameters for the send operation.
     * @dev _oftCmd The OFT command to be executed.
     * @return oftLimit The OFT limit information.
     * @return oftFeeDetails The details of OFT fees.
     * @return oftReceipt The OFT receipt information.
     */
    function quoteOFT(
        SendParam calldata _sendParam,
        bytes calldata /*_oftCmd*/ // @dev unused in the default implementation.
    )
        external
        view
        virtual
        returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt)
    {
        uint256 minAmountLD = 0; // Unused in the default implementation.
        uint256 maxAmountLD = type(uint64).max; // Unused in the default implementation.
        oftLimit = OFTLimit(minAmountLD, maxAmountLD);

        // Unused in the default implementation; reserved for future complex fee details.
        oftFeeDetails = new OFTFeeDetail[](0);

        // @dev This is the same as the send() operation, but without the actual send.
        // - amountToDebitLD is the amount in local decimals that was be debited from the sender.
        // - amountToCreditLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.
        // @dev The amount credited does NOT always equal the amount the user actually receives.
        // HOWEVER, In the default implementation it is.
        (uint256 amountToDebitLD, uint256 amountToCreditLD) = _debitView(
            _sendParam.amountToSendLD,
            _sendParam.minAmountToCreditLD,
            _sendParam.dstEid
        );
        oftReceipt = OFTReceipt(amountToDebitLD, amountToCreditLD);
    }

    /**
     * @notice Provides a quote for the send() operation.
     * @param _sendParam The parameters for the send() operation.
     * @param _extraOptions Additional options supplied by the caller to be used in the LayerZero message.
     * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
     * @param _composeMsg The composed message for the send() operation.
     * @dev _oftCmd The OFT command to be executed.
     * @return msgFee The calculated LayerZero messaging fee from the send() operation.
     *
     * @dev MessagingFee: LayerZero msg fee
     *  - nativeFee: The native fee.
     *  - lzTokenFee: The lzToken fee.
     */
    function quoteSend(
        SendParam calldata _sendParam,
        bytes calldata _extraOptions,
        bool _payInLzToken,
        bytes calldata _composeMsg,
        bytes calldata /*_oftCmd*/ // @dev unused in the default implementation.
    ) external view virtual returns (MessagingFee memory msgFee) {
        // @dev mock the amount to credit, this is the same operation used in the send().
        // The quote is as similar as possible to the actual send() operation.
        (, uint256 amountToCreditLD) = _debitView(
            _sendParam.amountToSendLD,
            _sendParam.minAmountToCreditLD,
            _sendParam.dstEid
        );

        // @dev Builds the options and OFT message to quote in the endpoint.
        (bytes memory message, bytes memory options) = _buildMsgAndOptions(
            _sendParam,
            _extraOptions,
            _composeMsg,
            amountToCreditLD
        );

        // @dev Calculates the LayerZero fee for the send() operation.
        return _quote(_sendParam.dstEid, message, options, _payInLzToken);
    }

    /**
     * @dev Executes the send operation.
     * @param _sendParam The parameters for the send operation.
     * @param _extraOptions Additional options for the send() operation.
     * @param _fee The calculated fee for the send() operation.
     *      - nativeFee: The native fee.
     *      - lzTokenFee: The lzToken fee.
     * @param _refundAddress The address to receive any excess funds.
     * @param _composeMsg The composed message for the send() operation.
     * @dev _oftCmd The OFT command to be executed.
     * @return msgReceipt The receipt for the send operation.
     * @return oftReceipt The OFT receipt information.
     *
     * @dev MessagingReceipt: LayerZero msg receipt
     *  - guid: The unique identifier for the sent message.
     *  - nonce: The nonce of the sent message.
     *  - fee: The LayerZero fee incurred for the message.
     */
    function send(
        SendParam calldata _sendParam,
        bytes calldata _extraOptions,
        MessagingFee calldata _fee,
        address _refundAddress,
        bytes calldata _composeMsg,
        bytes calldata /*_oftCmd*/ // @dev unused in the default implementation.
    ) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {
        // @dev Applies the token transfers regarding this send() operation.
        // - amountDebitedLD is the amount in local decimals that was ACTUALLY debited from the sender.
        // - amountToCreditLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.
        (uint256 amountDebitedLD, uint256 amountToCreditLD) = _debit(
            _sendParam.amountToSendLD,
            _sendParam.minAmountToCreditLD,
            _sendParam.dstEid
        );

        // @dev Builds the options and OFT message to quote in the endpoint.
        (bytes memory message, bytes memory options) = _buildMsgAndOptions(
            _sendParam,
            _extraOptions,
            _composeMsg,
            amountToCreditLD
        );

        // @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.
        msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);
        // @dev Formulate the OFT receipt.
        oftReceipt = OFTReceipt(amountDebitedLD, amountToCreditLD);

        emit OFTSent(msgReceipt.guid, msg.sender, amountDebitedLD, amountToCreditLD, _composeMsg);
    }

    /**
     * @dev Internal function to build the message and options.
     * @param _sendParam The parameters for the send() operation.
     * @param _extraOptions Additional options for the send() operation.
     * @param _composeMsg The composed message for the send() operation.
     * @param _amountToCreditLD The amount to credit in local decimals.
     * @return message The encoded message.
     * @return options The encoded options.
     */
    function _buildMsgAndOptions(
        SendParam calldata _sendParam,
        bytes calldata _extraOptions,
        bytes calldata _composeMsg,
        uint256 _amountToCreditLD
    ) internal view virtual returns (bytes memory message, bytes memory options) {
        bool hasCompose;
        // @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is.
        (message, hasCompose) = OFTMsgCodec.encode(
            _sendParam.to,
            _toSD(_amountToCreditLD),
            // @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote.
            // EVEN if you dont require an arbitrary payload to be sent... eg. '0x01'
            _composeMsg
        );
        // @dev Change the msg type depending if its composed or not.
        uint16 msgType = hasCompose ? SEND_AND_CALL : SEND;
        // @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3.
        options = combineOptions(_sendParam.dstEid, msgType, _extraOptions);

        // @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector.
        // @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean
        if (msgInspector != address(0)) IOAppMsgInspector(msgInspector).inspect(message, options);
    }

    /**
     * @dev Internal function to handle the receive on the LayerZero endpoint.
     * @param _origin The origin information.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address from the src chain.
     *  - nonce: The nonce of the LayerZero message.
     * @param _guid The unique identifier for the received LayerZero message.
     * @param _message The encoded message.
     * @dev _executor The address of the executor.
     * @dev _extraData Additional data.
     */
    function _lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address /*_executor*/, // @dev unused in the default implementation.
        bytes calldata /*_extraData*/ // @dev unused in the default implementation.
    ) internal virtual override {
        // @dev The src sending chain doesnt know the address length on this chain (potentially non-evm)
        // Thus everything is bytes32() encoded in flight.
        address toAddress = _message.sendTo().bytes32ToAddress();
        // @dev Convert the amount to credit into local decimals.
        uint256 amountToCreditLD = _toLD(_message.amountSD());
        // @dev Credit the amount to the recipient and return the ACTUAL amount the recipient received in local decimals
        uint256 amountReceivedLD = _credit(toAddress, amountToCreditLD, _origin.srcEid);

        if (_message.isComposed()) {
            // @dev Proprietary composeMsg format for the OFT.
            bytes memory composeMsg = OFTComposeMsgCodec.encode(
                _origin.nonce,
                _origin.srcEid,
                amountReceivedLD,
                _message.composeMsg()
            );

            // @dev Stores the lzCompose payload that will be executed in a separate tx.
            // Standardizes functionality for executing arbitrary contract invocation on some non-evm chains.
            // @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed.
            // @dev The index is used when a OApp needs to compose multiple msgs on lzReceive.
            // For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0.
            endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg);
        }

        emit OFTReceived(_guid, toAddress, amountToCreditLD, amountReceivedLD);
    }

    /**
     * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.
     * @param _origin The origin information.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address from the src chain.
     *  - nonce: The nonce of the LayerZero message.
     * @param _guid The unique identifier for the received LayerZero message.
     * @param _message The LayerZero message.
     * @param _executor The address of the off-chain executor.
     * @param _extraData Arbitrary data passed by the msg executor.
     *
     * @dev Enables the preCrime simulator to mock sending lzReceive() messages,
     * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.
     */
    function _lzReceiveSimulate(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) internal virtual override {
        _lzReceive(_origin, _guid, _message, _executor, _extraData);
    }

    /**
     * @dev Internal function to check if peer is considered 'trusted' by the OApp.
     * @param _eid The endpoint ID to check.
     * @param _peer The peer to check.
     * @return Whether the peer passed is considered 'trusted' by the OApp.
     *
     * @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source.
     */
    function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) {
        return peers[_eid] == _peer;
    }

    /**
     * @dev Internal function to remove dust from the given local decimal amount.
     * @param _amountLD The amount in local decimals.
     * @return amountLD The amount after removing dust.
     *
     * @dev Prevents the loss of dust when moving amounts between chains with different decimals.
     * @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).
     */
    function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) {
        return (_amountLD / decimalConversionRate) * decimalConversionRate;
    }

    /**
     * @dev Internal function to convert an amount from shared decimals into local decimals.
     * @param _amountSD The amount in shared decimals.
     * @return amountLD The amount in local decimals.
     */
    function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) {
        return _amountSD * decimalConversionRate;
    }

    /**
     * @dev Internal function to convert an amount from local decimals into shared decimals.
     * @param _amountLD The amount in local decimals.
     * @return amountSD The amount in shared decimals.
     */
    function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) {
        return uint64(_amountLD / decimalConversionRate);
    }

    /**
     * @dev Internal function to mock the amount mutation from a OFT debit() operation.
     * @param _amountToSendLD The amount to send in local decimals.
     * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
     * @dev _dstEid The destination endpoint ID.
     * @return amountToDebitLD The amount to ACTUALLY debit, in local decimals.
     * @return amountToCreditLD The amount to credit on the remote chain, in local decimals.
     *
     * @dev This is where things like fees would be calculated and deducted from the amount to credit on the remote.
     */
    function _debitView(
        uint256 _amountToSendLD,
        uint256 _minAmountToCreditLD,
        uint32 /*_dstEid*/
    ) internal view virtual returns (uint256 amountToDebitLD, uint256 amountToCreditLD) {
        // @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token.
        amountToDebitLD = _removeDust(_amountToSendLD);
        // @dev The amount to credit is the same as the amount to debit in the default implementation.
        amountToCreditLD = amountToDebitLD;

        // @dev Check for slippage.
        if (amountToCreditLD < _minAmountToCreditLD) {
            revert SlippageExceeded(amountToCreditLD, _minAmountToCreditLD);
        }
    }

    /**
     * @dev Internal function to perform a debit operation.
     * @param _amountToSendLD The amount to send in local decimals.
     * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
     * @param _dstEid The destination endpoint ID.
     * @return amountDebitedLD The amount ACTUALLY debited in local decimals.
     * @return amountToCreditLD The amount to credit in local decimals on the remote.
     */
    function _debit(
        uint256 _amountToSendLD,
        uint256 _minAmountToCreditLD,
        uint32 _dstEid
    ) internal virtual returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
        // @dev Caller can indicate it wants to use push vs. pull method by passing an _amountToSendLD of 0.
        if (_amountToSendLD > 0) {
            // @dev Pull the tokens from the caller.
            (amountDebitedLD, amountToCreditLD) = _debitSender(_amountToSendLD, _minAmountToCreditLD, _dstEid);
        } else {
            // @dev Caller has pushed tokens.
            (amountDebitedLD, amountToCreditLD) = _debitThis(_minAmountToCreditLD, _dstEid);
        }
    }

    /**
     * @dev Internal function to perform a debit operation for this chain.
     * @param _amountToSendLD The amount to send in local decimals.
     * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
     * @param _dstEid The destination endpoint ID.
     * @return amountDebitedLD The amount ACTUALLY debited in local decimals.
     * @return amountToCreditLD The amount to credit in local decimals.
     *
     * @dev Defined here but are intended to be override depending on the OFT implementation.
     * @dev This is used when the OFT pulls the tokens from the caller.
     * ie. A user sends has approved the OFT to spend on its behalf.
     */
    function _debitSender(
        uint256 _amountToSendLD,
        uint256 _minAmountToCreditLD,
        uint32 _dstEid
    ) internal virtual returns (uint256 amountDebitedLD, uint256 amountToCreditLD);

    /**
     * @dev Internal function to perform a debit operation for this chain.
     * @param _minAmountToCreditLD The minimum amount to credit in local decimals.
     * @param _dstEid The destination endpoint ID.
     * @return amountDebitedLD The amount ACTUALLY debited in local decimals.
     * @return amountToCreditLD The amount to credit in local decimals.
     *
     * @dev Defined here but are intended to be override depending on the OFT implementation.
     * @dev This is used when the OFT is the recipient of a push operation.
     * ie. A user sends tokens direct to the OFT contract address.
     */
    function _debitThis(
        uint256 _minAmountToCreditLD,
        uint32 _dstEid
    ) internal virtual returns (uint256 amountDebitedLD, uint256 amountToCreditLD);

    /**
     * @dev Internal function to perform a credit operation.
     * @param _to The address to credit.
     * @param _amountToCreditLD The amount to credit in local decimals.
     * @param _srcEid The source endpoint ID.
     * @return amountReceivedLD The amount ACTUALLY received in local decimals.
     *
     * @dev Defined here but are intended to be override depending on the OFT implementation.
     * @dev Depending on OFT implementation the _amountToCreditLD could differ from the amountReceivedLD.
     */
    function _credit(
        address _to,
        uint256 _amountToCreditLD,
        uint32 _srcEid
    ) internal virtual returns (uint256 amountReceivedLD);
}

File 11 of 43 : 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 12 of 43 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 13 of 43 : OApp.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

// @dev Import the 'MessagingFee' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppSender, MessagingFee } from "./OAppSender.sol";
// @dev Import the 'Origin' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppReceiver, Origin } from "./OAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OApp
 * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
 */
abstract contract OApp is OAppSender, OAppReceiver {
    /**
     * @dev Constructor to initialize the OApp with the provided endpoint and owner.
     * @param _endpoint The address of the LOCAL LayerZero endpoint.
     * @param _owner The address of the owner of the OApp.
     */
    constructor(address _endpoint, address _owner) OAppCore(_endpoint, _owner) {}

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol implementation.
     * @return receiverVersion The version of the OAppReceiver.sol implementation.
     */
    function oAppVersion()
        public
        pure
        virtual
        override(OAppSender, OAppReceiver)
        returns (uint64 senderVersion, uint64 receiverVersion)
    {
        return (SENDER_VERSION, RECEIVER_VERSION);
    }
}

File 14 of 43 : OAppOptionsType3.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOAppOptionsType3, EnforcedOptionParam } from "../interfaces/IOAppOptionsType3.sol";

/**
 * @title OAppOptionsType3
 * @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options.
 */
abstract contract OAppOptionsType3 is IOAppOptionsType3, Ownable {
    uint16 internal constant OPTION_TYPE_3 = 3;

    // @dev The "msgType" should be defined in the child contract.
    mapping(uint32 eid => mapping(uint16 msgType => bytes enforcedOption)) public enforcedOptions;

    /**
     * @dev Sets the enforced options for specific endpoint and message type combinations.
     * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.
     * @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.
     * eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay
     * if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().
     */
    function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner {
        for (uint256 i = 0; i < _enforcedOptions.length; i++) {
            // @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining.
            _assertOptionsType3(_enforcedOptions[i].options);
            enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options;
        }

        emit EnforcedOptionSet(_enforcedOptions);
    }

    /**
     * @notice Combines options for a given endpoint and message type.
     * @param _eid The endpoint ID.
     * @param _msgType The OAPP message type.
     * @param _extraOptions Additional options passed by the caller.
     * @return options The combination of caller specified options AND enforced options.
     *
     * @dev If there is an enforced lzReceive option:
     * - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether}
     * - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function.
     * @dev This presence of duplicated options is handled off-chain in the verifier/executor.
     */
    function combineOptions(
        uint32 _eid,
        uint16 _msgType,
        bytes calldata _extraOptions
    ) public view virtual returns (bytes memory) {
        bytes memory enforced = enforcedOptions[_eid][_msgType];

        // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options.
        if (enforced.length == 0) return _extraOptions;

        // No caller options, return enforced
        if (_extraOptions.length == 0) return enforced;

        // @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined.
        if (_extraOptions.length >= 2) {
            _assertOptionsType3(_extraOptions);
            // @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced.
            return bytes.concat(enforced, _extraOptions[2:]);
        }

        // No valid set of options was found.
        revert InvalidOptions(_extraOptions);
    }

    /**
     * @dev Internal function to assert that options are of type 3.
     * @param _options The options to be checked.
     */
    function _assertOptionsType3(bytes calldata _options) internal pure virtual {
        uint16 optionsType = uint16(bytes2(_options[0:2]));
        if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options);
    }
}

File 15 of 43 : IOAppMsgInspector.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

/**
 * @title IOAppMsgInspector
 * @dev Interface for the OApp Message Inspector, allowing examination of message and options contents.
 */
interface IOAppMsgInspector {
    // Custom error message for inspection failure
    error InspectionFailed(bytes message, bytes options);

    /**
     * @notice Allows the inspector to examine LayerZero message contents and optionally throw a revert if invalid.
     * @param _message The message payload to be inspected.
     * @param _options Additional options or parameters for inspection.
     * @return valid A boolean indicating whether the inspection passed (true) or failed (false).
     *
     * @dev Optionally done as a revert, OR use the boolean provided to handle the failure.
     */
    function inspect(bytes calldata _message, bytes calldata _options) external view returns (bool valid);
}

File 16 of 43 : OAppPreCrimeSimulator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IPreCrime } from "./interfaces/IPreCrime.sol";
import { IOAppPreCrimeSimulator, InboundPacket, Origin } from "./interfaces/IOAppPreCrimeSimulator.sol";

/**
 * @title OAppPreCrimeSimulator
 * @dev Abstract contract serving as the base for preCrime simulation functionality in an OApp.
 */
abstract contract OAppPreCrimeSimulator is IOAppPreCrimeSimulator, Ownable {
    // The address of the preCrime implementation.
    address public preCrime;

    /**
     * @dev Retrieves the address of the OApp contract.
     * @return The address of the OApp contract.
     *
     * @dev The simulator contract is the base contract for the OApp by default.
     * @dev If the simulator is a separate contract, override this function.
     */
    function oApp() external view virtual returns (address) {
        return address(this);
    }

    /**
     * @dev Sets the preCrime contract address.
     * @param _preCrime The address of the preCrime contract.
     */
    function setPreCrime(address _preCrime) public virtual onlyOwner {
        preCrime = _preCrime;
        emit PreCrimeSet(_preCrime);
    }

    /**
     * @dev Interface for pre-crime simulations. Always reverts at the end with the simulation results.
     * @param _packets An array of InboundPacket objects representing received packets to be delivered.
     *
     * @dev WARNING: MUST revert at the end with the simulation results.
     * @dev Gives the preCrime implementation the ability to mock sending packets to the lzReceive function,
     * WITHOUT actually executing them.
     */
    function lzReceiveAndRevert(InboundPacket[] calldata _packets) public payable virtual {
        for (uint256 i = 0; i < _packets.length; i++) {
            InboundPacket calldata packet = _packets[i];

            // Ignore packets that are not from trusted peers.
            if (!isPeer(packet.origin.srcEid, packet.origin.sender)) continue;

            // @dev Because a verifier is calling this function, it doesnt have access to executor params:
            //  - address _executor
            //  - bytes calldata _extraData
            // preCrime will NOT work for OApps that rely on these two parameters inside of their _lzReceive().
            // They are instead stubbed to default values, address(0) and bytes("")
            // @dev Calling this.lzReceiveSimulate removes ability for assembly return 0 callstack exit,
            // which would cause the revert to be ignored.
            this.lzReceiveSimulate{ value: packet.value }(
                packet.origin,
                packet.guid,
                packet.message,
                packet.executor,
                packet.extraData
            );
        }

        // @dev Revert with the simulation results. msg.sender must implement IPreCrime.buildSimulationResult().
        revert SimulationResult(IPreCrime(msg.sender).buildSimulationResult());
    }

    /**
     * @dev Is effectively an internal function because msg.sender must be address(this).
     * Allows resetting the call stack for 'internal' calls.
     * @param _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @param _guid The unique identifier of the packet.
     * @param _message The message payload of the packet.
     * @param _executor The executor address for the packet.
     * @param _extraData Additional data for the packet.
     */
    function lzReceiveSimulate(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) external payable virtual {
        // @dev Ensure ONLY can be called 'internally'.
        if (msg.sender != address(this)) revert OnlySelf();
        _lzReceiveSimulate(_origin, _guid, _message, _executor, _extraData);
    }

    /**
     * @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.
     * @param _origin The origin information.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address from the src chain.
     *  - nonce: The nonce of the LayerZero message.
     * @param _guid The GUID of the LayerZero message.
     * @param _message The LayerZero message.
     * @param _executor The address of the off-chain executor.
     * @param _extraData Arbitrary data passed by the msg executor.
     *
     * @dev Enables the preCrime simulator to mock sending lzReceive() messages,
     * routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.
     */
    function _lzReceiveSimulate(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) internal virtual;

    /**
     * @dev checks if the specified peer is considered 'trusted' by the OApp.
     * @param _eid The endpoint Id to check.
     * @param _peer The peer to check.
     * @return Whether the peer passed is considered 'trusted' by the OApp.
     */
    function isPeer(uint32 _eid, bytes32 _peer) public view virtual returns (bool);
}

File 17 of 43 : IOFT.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { MessagingReceipt, MessagingFee } from "../../oapp/OAppSender.sol";

/**
 * @dev Struct representing token parameters for the OFT send() operation.
 */
struct SendParam {
    uint32 dstEid; // Destination endpoint ID.
    bytes32 to; // Recipient address.
    uint256 amountToSendLD; // Amount to send in local decimals.
    uint256 minAmountToCreditLD; // Minimum amount to credit in local decimals.
}

/**
 * @dev Struct representing OFT limit information.
 * @dev These amounts can change dynamically and are up the the specific oft implementation.
 */
struct OFTLimit {
    uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.
    uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.
}

/**
 * @dev Struct representing OFT receipt information.
 */
struct OFTReceipt {
    uint256 amountDebitLD; // Amount of tokens ACTUALLY debited in local decimals.
    // @dev Does not guarantee the recipient will receive the credit amount, as remote implementations can vary depending on the OFT
    // eg. fees COULD be applied on the remote side, so the recipient may receive less than amountCreditLD
    uint256 amountCreditLD; // Amount of tokens to be credited on the remote side.
}

/**
 * @dev Struct representing OFT fee details.
 * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.
 */
struct OFTFeeDetail {
    uint256 feeAmountLD; // Amount of the fee in local decimals.
    string description; // Description of the fee.
}

/**
 * @title IOFT
 * @dev Interface for the OftChain (OFT) token.
 * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.
 */
interface IOFT {
    // Custom error messages
    error InvalidLocalDecimals();
    error SlippageExceeded(uint256 amountToCreditLD, uint256 minAmountToCreditLD);

    // Events
    event MsgInspectorSet(address inspector);
    event OFTSent(
        bytes32 indexed guid, // GUID of the OFT message.
        address indexed fromAddress, // Address of the sender on the src chain.
        uint256 amountDebitedLD, // Amount of tokens ACTUALLY debited from the sender in local decimals.
        uint256 amountToCreditLD, // Amount of tokens to be credited on the remote side in local decimals.
        bytes composeMsg // Composed message for the send() operation.
    );
    event OFTReceived(
        bytes32 indexed guid, // GUID of the OFT message.
        address indexed toAddress, // Address of the recipient on the dst chain.
        uint256 amountToCreditLD, // Amount of tokens to be credited on the remote side in local decimals.
        uint256 amountReceivedLD // Amount of tokens ACTUALLY received by the recipient in local decimals.
    );

    /**
     * @notice Retrieves the major and minor version of the OFT.
     * @return major The major version.
     * @return minor The minor version.
     *
     * @dev major version: Indicates a cross-chain compatible msg encoding with other OFTs.
     * @dev minor version: Indicates a version within the local chains context. eg. OFTAdapter vs. OFT
     * @dev For example, if a new feature is added to the OFT contract, the minor version will be incremented.
     * @dev If a new feature is added to the OFT cross-chain msg encoding, the major version will be incremented.
     * ie. localOFT version(1,1) CAN send messages to remoteOFT version(1,2)
     */
    function oftVersion() external view returns (uint64 major, uint64 minor);

    /**
     * @notice Retrieves the address of the token associated with the OFT.
     * @return token The address of the ERC20 token implementation.
     */
    function token() external view returns (address);

    /**
     * @notice Retrieves the shared decimals of the OFT.
     * @return sharedDecimals The shared decimals of the OFT.
     */
    function sharedDecimals() external view returns (uint8);

    /**
     * @notice Sets the message inspector address for the OFT.
     * @param _msgInspector The address of the message inspector.
     */
    function setMsgInspector(address _msgInspector) external;

    /**
     * @notice Retrieves the address of the message inspector.
     * @return msgInspector The address of the message inspector.
     */
    function msgInspector() external view returns (address);

    /**
     * @notice Provides a quote for OFT-related operations.
     * @param _sendParam The parameters for the send operation.
     * @param _oftCmd The OFT command to be executed.
     * @return limit The OFT limit information.
     * @return oftFeeDetails The details of OFT fees.
     * @return receipt The OFT receipt information.
     */
    function quoteOFT(
        SendParam calldata _sendParam,
        bytes calldata _oftCmd
    ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);

    /**
     * @notice Provides a quote for the send() operation.
     * @param _sendParam The parameters for the send() operation.
     * @param _extraOptions Additional options supplied by the caller to be used in the LayerZero message.
     * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
     * @param _composeMsg The composed message for the send() operation.
     * @param _oftCmd The OFT command to be executed.
     * @return fee The calculated LayerZero messaging fee from the send() operation.
     *
     * @dev MessagingFee: LayerZero msg fee
     *  - nativeFee: The native fee.
     *  - lzTokenFee: The lzToken fee.
     */
    function quoteSend(
        SendParam calldata _sendParam,
        bytes calldata _extraOptions,
        bool _payInLzToken,
        bytes calldata _composeMsg,
        bytes calldata _oftCmd
    ) external view returns (MessagingFee memory);

    /**
     * @notice Executes the send() operation.
     * @param _sendParam The parameters for the send operation.
     * @param _extraOptions Additional options supplied by the caller to be used in the LayerZero message.
     * @param _fee The fee information supplied by the caller.
     *      - nativeFee: The native fee.
     *      - lzTokenFee: The lzToken fee.
     * @param _refundAddress The address to receive any excess funds from fees etc. on the src.
     * @param _composeMsg The composed message for the send() operation.
     * @param _oftCmd The OFT command to be executed.
     * @return receipt The LayerZero messaging receipt from the send() operation.
     * @return oftReceipt The OFT receipt information.
     *
     * @dev MessagingReceipt: LayerZero msg receipt
     *  - guid: The unique identifier for the sent message.
     *  - nonce: The nonce of the sent message.
     *  - fee: The LayerZero fee incurred for the message.
     */
    function send(
        SendParam calldata _sendParam,
        bytes calldata _extraOptions,
        MessagingFee calldata _fee,
        address _refundAddress,
        bytes calldata _composeMsg,
        bytes calldata _oftCmd
    ) external payable returns (MessagingReceipt memory, OFTReceipt memory);
}

File 18 of 43 : OFTMsgCodec.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

library OFTMsgCodec {
    // Offset constants for encoding and decoding OFT messages
    uint8 private constant SEND_TO_OFFSET = 32;
    uint8 private constant SEND_AMOUNT_SD_OFFSET = 40;

    /**
     * @dev Encodes an OFT LayerZero message.
     * @param _sendTo The recipient address.
     * @param _amountShared The amount in shared decimals.
     * @param _composeMsg The composed message.
     * @return _msg The encoded message.
     * @return hasCompose A boolean indicating whether the message has a composed payload.
     */
    function encode(
        bytes32 _sendTo,
        uint64 _amountShared,
        bytes memory _composeMsg
    ) internal view returns (bytes memory _msg, bool hasCompose) {
        hasCompose = _composeMsg.length > 0;
        // @dev Remote chains will want to know the composed function caller ie. msg.sender on the src.
        _msg = hasCompose
            ? abi.encodePacked(_sendTo, _amountShared, addressToBytes32(msg.sender), _composeMsg)
            : abi.encodePacked(_sendTo, _amountShared);
    }

    /**
     * @dev Checks if the OFT message is composed.
     * @param _msg The OFT message.
     * @return A boolean indicating whether the message is composed.
     */
    function isComposed(bytes calldata _msg) internal pure returns (bool) {
        return _msg.length > SEND_AMOUNT_SD_OFFSET;
    }

    /**
     * @dev Retrieves the recipient address from the OFT message.
     * @param _msg The OFT message.
     * @return The recipient address.
     */
    function sendTo(bytes calldata _msg) internal pure returns (bytes32) {
        return bytes32(_msg[:SEND_TO_OFFSET]);
    }

    /**
     * @dev Retrieves the amount in shared decimals from the OFT message.
     * @param _msg The OFT message.
     * @return The amount in shared decimals.
     */
    function amountSD(bytes calldata _msg) internal pure returns (uint64) {
        return uint64(bytes8(_msg[SEND_TO_OFFSET:SEND_AMOUNT_SD_OFFSET]));
    }

    /**
     * @dev Retrieves the composed message from the OFT message.
     * @param _msg The OFT message.
     * @return The composed message.
     */
    function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {
        return _msg[SEND_AMOUNT_SD_OFFSET:];
    }

    /**
     * @dev Converts an address to bytes32.
     * @param _addr The address to convert.
     * @return The bytes32 representation of the address.
     */
    function addressToBytes32(address _addr) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(_addr)));
    }

    /**
     * @dev Converts bytes32 to an address.
     * @param _b The bytes32 value to convert.
     * @return The address representation of bytes32.
     */
    function bytes32ToAddress(bytes32 _b) internal pure returns (address) {
        return address(uint160(uint256(_b)));
    }
}

File 19 of 43 : OFTComposeMsgCodec.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

library OFTComposeMsgCodec {
    // Offset constants for decoding composed messages
    uint8 private constant NONCE_OFFSET = 8;
    uint8 private constant SRC_EID_OFFSET = 12;
    uint8 private constant AMOUNT_LD_OFFSET = 44;
    uint8 private constant COMPOSE_FROM_OFFSET = 76;

    /**
     * @dev Encodes a OFT composed message.
     * @param _nonce The nonce value.
     * @param _srcEid The source endpoint ID.
     * @param _amountLD The amount in local decimals.
     * @param _composeMsg The composed message.
     * @return _msg The encoded Composed message.
     */
    function encode(
        uint64 _nonce,
        uint32 _srcEid,
        uint256 _amountLD,
        bytes memory _composeMsg // 0x[composeFrom][composeMsg]
    ) internal pure returns (bytes memory _msg) {
        _msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg);
    }

    /**
     * @dev Retrieves the nonce from the composed message.
     * @param _msg The message.
     * @return The nonce value.
     */
    function nonce(bytes calldata _msg) internal pure returns (uint64) {
        return uint64(bytes8(_msg[:NONCE_OFFSET]));
    }

    /**
     * @dev Retrieves the source endpoint ID from the composed message.
     * @param _msg The message.
     * @return The source endpoint ID.
     */
    function srcEid(bytes calldata _msg) internal pure returns (uint32) {
        return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET]));
    }

    /**
     * @dev Retrieves the amount in local decimals from the composed message.
     * @param _msg The message.
     * @return The amount in local decimals.
     */
    function amountLD(bytes calldata _msg) internal pure returns (uint256) {
        return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET]));
    }

    /**
     * @dev Retrieves the composeFrom value from the composed message.
     * @param _msg The message.
     * @return The composeFrom value.
     */
    function composeFrom(bytes calldata _msg) internal pure returns (bytes32) {
        return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]);
    }

    /**
     * @dev Retrieves the composed message.
     * @param _msg The message.
     * @return The composed message.
     */
    function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {
        return _msg[COMPOSE_FROM_OFFSET:];
    }

    /**
     * @dev Converts an address to bytes32.
     * @param _addr The address to convert.
     * @return The bytes32 representation of the address.
     */
    function addressToBytes32(address _addr) internal pure returns (bytes32) {
        return bytes32(uint256(uint160(_addr)));
    }

    /**
     * @dev Converts bytes32 to an address.
     * @param _b The bytes32 value to convert.
     * @return The address representation of bytes32.
     */
    function bytes32ToAddress(bytes32 _b) internal pure returns (address) {
        return address(uint160(uint256(_b)));
    }
}

File 20 of 43 : OAppSender.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OAppSender
 * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
 */
abstract contract OAppSender is OAppCore {
    using SafeERC20 for IERC20;

    // Custom error messages
    error NotEnoughNative(uint256 msgValue);
    error LzTokenUnavailable();

    // @dev The version of the OAppSender implementation.
    // @dev Version is bumped when changes are made to this contract.
    uint64 internal constant SENDER_VERSION = 1;

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     *
     * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
     * ie. this is a RECEIVE only OApp.
     * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
     */
    function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
        return (SENDER_VERSION, 0);
    }

    /**
     * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
     * @param _dstEid The destination endpoint ID.
     * @param _message The message payload.
     * @param _options Additional options for the message.
     * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
     * @return fee The calculated MessagingFee for the message.
     *      - nativeFee: The native fee for the message.
     *      - lzTokenFee: The LZ token fee for the message.
     */
    function _quote(
        uint32 _dstEid,
        bytes memory _message,
        bytes memory _options,
        bool _payInLzToken
    ) internal view virtual returns (MessagingFee memory fee) {
        return
            endpoint.quote(
                MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),
                address(this)
            );
    }

    /**
     * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
     * @param _dstEid The destination endpoint ID.
     * @param _message The message payload.
     * @param _options Additional options for the message.
     * @param _fee The calculated LayerZero fee for the message.
     *      - nativeFee: The native fee.
     *      - lzTokenFee: The lzToken fee.
     * @param _refundAddress The address to receive any excess fee values sent to the endpoint.
     * @return receipt The receipt for the sent message.
     *      - guid: The unique identifier for the sent message.
     *      - nonce: The nonce of the sent message.
     *      - fee: The LayerZero fee incurred for the message.
     */
    function _lzSend(
        uint32 _dstEid,
        bytes memory _message,
        bytes memory _options,
        MessagingFee memory _fee,
        address _refundAddress
    ) internal virtual returns (MessagingReceipt memory receipt) {
        // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
        uint256 messageValue = _payNative(_fee.nativeFee);
        if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);

        return
            // solhint-disable-next-line check-send-result
            endpoint.send{ value: messageValue }(
                MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),
                _refundAddress
            );
    }

    /**
     * @dev Internal function to pay the native fee associated with the message.
     * @param _nativeFee The native fee to be paid.
     * @return nativeFee The amount of native currency paid.
     *
     * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
     * this will need to be overridden because msg.value would contain multiple lzFees.
     * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
     * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
     * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
     */
    function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
        if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
        return _nativeFee;
    }

    /**
     * @dev Internal function to pay the LZ token fee associated with the message.
     * @param _lzTokenFee The LZ token fee to be paid.
     *
     * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
     * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
     */
    function _payLzToken(uint256 _lzTokenFee) internal virtual {
        // @dev Cannot cache the token because it is not immutable in the endpoint.
        address lzToken = endpoint.lzToken();
        if (lzToken == address(0)) revert LzTokenUnavailable();

        // Pay LZ token fee by sending tokens to the endpoint.
        IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
    }
}

File 21 of 43 : OAppReceiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";
import { OAppCore } from "./OAppCore.sol";

/**
 * @title OAppReceiver
 * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
 */
abstract contract OAppReceiver is ILayerZeroReceiver, OAppCore {
    // Custom error message for when the caller is not the registered endpoint/
    error OnlyEndpoint(address addr);

    // @dev The version of the OAppReceiver implementation.
    // @dev Version is bumped when changes are made to this contract.
    uint64 internal constant RECEIVER_VERSION = 1;

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     *
     * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.
     * ie. this is a SEND only OApp.
     * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
     */
    function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
        return (0, RECEIVER_VERSION);
    }

    /**
     * @notice Checks if the path initialization is allowed based on the provided origin.
     * @param origin The origin information containing the source endpoint and sender address.
     * @return Whether the path has been initialized.
     *
     * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.
     * @dev This defaults to assuming if a peer has been set, its initialized.
     * Can be overridden by the OApp if there is other logic to determine this.
     */
    function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {
        return peers[origin.srcEid] == origin.sender;
    }

    /**
     * @notice Retrieves the next nonce for a given source endpoint and sender address.
     * @dev _srcEid The source endpoint ID.
     * @dev _sender The sender address.
     * @return nonce The next nonce.
     *
     * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.
     * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.
     * @dev This is also enforced by the OApp.
     * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.
     */
    function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {
        return 0;
    }

    /**
     * @dev Entry point for receiving messages or packets from the endpoint.
     * @param _origin The origin information containing the source endpoint and sender address.
     *  - srcEid: The source chain endpoint ID.
     *  - sender: The sender address on the src chain.
     *  - nonce: The nonce of the message.
     * @param _guid The unique identifier for the received LayerZero message.
     * @param _message The payload of the received message.
     * @param _executor The address of the executor for the received message.
     * @param _extraData Additional arbitrary data provided by the corresponding executor.
     *
     * @dev Entry point for receiving msg/packet from the LayerZero endpoint.
     */
    function lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) public payable virtual {
        // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.
        if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);

        // Ensure that the sender matches the expected peer for the source endpoint.
        if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);

        // Call the internal OApp implementation of lzReceive.
        _lzReceive(_origin, _guid, _message, _executor, _extraData);
    }

    /**
     * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.
     */
    function _lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) internal virtual;
}

File 22 of 43 : OAppCore.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol";

/**
 * @title OAppCore
 * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
 */
abstract contract OAppCore is IOAppCore, Ownable {
    // The LayerZero endpoint associated with the given OApp
    ILayerZeroEndpointV2 public immutable endpoint;

    // Mapping to store peers associated with corresponding endpoints
    mapping(uint32 eid => bytes32 peer) public peers;

    /**
     * @dev Constructor to initialize the OAppCore with the provided endpoint and owner.
     * @param _endpoint The address of the LOCAL Layer Zero endpoint.
     * @param _owner The address of the owner of the OAppCore.
     */
    constructor(address _endpoint, address _owner) {
        _transferOwnership(_owner);
        endpoint = ILayerZeroEndpointV2(_endpoint);
        endpoint.setDelegate(_owner); // @dev By default, the owner is the delegate
    }

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
     * @dev Set this to bytes32(0) to remove the peer address.
     * @dev Peer is a bytes32 to accommodate non-evm chains.
     */
    function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {
        peers[_eid] = _peer;
        emit PeerSet(_eid, _peer);
    }

    /**
     * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
     * ie. the peer is set to bytes32(0).
     * @param _eid The endpoint ID.
     * @return peer The address of the peer associated with the specified endpoint.
     */
    function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
        bytes32 peer = peers[_eid];
        if (peer == bytes32(0)) revert NoPeer(_eid);
        return peer;
    }

    /**
     * @notice Sets the delegate address for the OApp.
     * @param _delegate The address of the delegate to be set.
     *
     * @dev Only the owner/admin of the OApp can call this function.
     * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
     * @dev Defaults to the owner of the OApp.
     */
    function setDelegate(address _delegate) public onlyOwner {
        endpoint.setDelegate(_delegate);
    }
}

File 23 of 43 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.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;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

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

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    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");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @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");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 24 of 43 : ILayerZeroEndpointV2.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { IMessageLibManager } from "./IMessageLibManager.sol";
import { IMessagingComposer } from "./IMessagingComposer.sol";
import { IMessagingChannel } from "./IMessagingChannel.sol";
import { IMessagingContext } from "./IMessagingContext.sol";

struct MessagingParams {
    uint32 dstEid;
    bytes32 receiver;
    bytes message;
    bytes options;
    bool payInLzToken;
}

struct MessagingReceipt {
    bytes32 guid;
    uint64 nonce;
    MessagingFee fee;
}

struct MessagingFee {
    uint256 nativeFee;
    uint256 lzTokenFee;
}

struct Origin {
    uint32 srcEid;
    bytes32 sender;
    uint64 nonce;
}

enum ExecutionState {
    NotExecutable,
    Executable,
    Executed
}

interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext {
    event PacketSent(bytes encodedPayload, bytes options, address sendLibrary);

    event PacketVerified(Origin origin, address receiver, bytes32 payloadHash);

    event PacketDelivered(Origin origin, address receiver);

    event LzReceiveAlert(
        address indexed receiver,
        address indexed executor,
        Origin origin,
        bytes32 guid,
        uint256 gas,
        uint256 value,
        bytes message,
        bytes extraData,
        bytes reason
    );

    event LzTokenSet(address token);

    function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory);

    function send(
        MessagingParams calldata _params,
        address _refundAddress
    ) external payable returns (MessagingReceipt memory);

    function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external;

    function verifiable(
        Origin calldata _origin,
        address _receiver,
        address _receiveLib,
        bytes32 _payloadHash
    ) external view returns (bool);

    function executable(Origin calldata _origin, address _receiver) external view returns (ExecutionState);

    function lzReceive(
        Origin calldata _origin,
        address _receiver,
        bytes32 _guid,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;

    // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order
    function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external;

    function setLzToken(address _lzToken) external;

    function lzToken() external view returns (address);

    function nativeToken() external view returns (address);

    function setDelegate(address _delegate) external;
}

File 25 of 43 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 26 of 43 : IMessageLibManager.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

struct SetConfigParam {
    uint32 eid;
    uint32 configType;
    bytes config;
}

interface IMessageLibManager {
    struct Timeout {
        address lib;
        uint256 expiry;
    }

    event LibraryRegistered(address newLib);
    event DefaultSendLibrarySet(uint32 eid, address newLib);
    event DefaultReceiveLibrarySet(uint32 eid, address oldLib, address newLib);
    event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);
    event SendLibrarySet(address sender, uint32 eid, address newLib);
    event ReceiveLibrarySet(address receiver, uint32 eid, address oldLib, address newLib);
    event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout);

    function registerLibrary(address _lib) external;

    function isRegisteredLibrary(address _lib) external view returns (bool);

    function getRegisteredLibraries() external view returns (address[] memory);

    function setDefaultSendLibrary(uint32 _eid, address _newLib) external;

    function defaultSendLibrary(uint32 _eid) external view returns (address);

    function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _timeout) external;

    function defaultReceiveLibrary(uint32 _eid) external view returns (address);

    function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;

    function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);

    function isSupportedEid(uint32 _eid) external view returns (bool);

    /// ------------------- OApp interfaces -------------------
    function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external;

    function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib);

    function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool);

    function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external;

    function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault);

    function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _gracePeriod) external;

    function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);

    function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;

    function getConfig(
        address _oapp,
        address _lib,
        uint32 _eid,
        uint32 _configType
    ) external view returns (bytes memory config);
}

File 27 of 43 : IMessagingComposer.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingComposer {
    event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message);
    event ComposeDelivered(address from, address to, bytes32 guid, uint16 index);
    event LzComposeAlert(
        address indexed from,
        address indexed to,
        address indexed executor,
        bytes32 guid,
        uint16 index,
        uint256 gas,
        uint256 value,
        bytes message,
        bytes extraData,
        bytes reason
    );

    function composeQueue(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index
    ) external view returns (bytes32 messageHash);

    function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external;

    function lzCompose(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;
}

File 28 of 43 : IMessagingChannel.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingChannel {
    event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce);
    event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);
    event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash);

    function eid() external view returns (uint32);

    // this is an emergency function if a message cannot be verified for some reasons
    // required to provide _nextNonce to avoid race condition
    function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external;

    function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;

    function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external;

    function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32);

    function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);

    function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64);

    function inboundPayloadHash(
        address _receiver,
        uint32 _srcEid,
        bytes32 _sender,
        uint64 _nonce
    ) external view returns (bytes32);
}

File 29 of 43 : IMessagingContext.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IMessagingContext {
    function isSendingMessage() external view returns (bool);

    function getSendContext() external view returns (uint32 dstEid, address sender);
}

File 30 of 43 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 31 of 43 : IOAppCore.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";

/**
 * @title IOAppCore
 */
interface IOAppCore {
    // Custom error messages
    error OnlyPeer(uint32 eid, bytes32 sender);
    error NoPeer(uint32 eid);
    error InvalidEndpointCall();

    // Event emitted when a peer (OApp) is set for a corresponding endpoint
    event PeerSet(uint32 eid, bytes32 peer);

    /**
     * @notice Retrieves the OApp version information.
     * @return senderVersion The version of the OAppSender.sol contract.
     * @return receiverVersion The version of the OAppReceiver.sol contract.
     */
    function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);

    /**
     * @notice Retrieves the LayerZero endpoint associated with the OApp.
     * @return iEndpoint The LayerZero endpoint as an interface.
     */
    function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);

    /**
     * @notice Retrieves the peer (OApp) associated with a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @return peer The peer address (OApp instance) associated with the corresponding endpoint.
     */
    function peers(uint32 _eid) external view returns (bytes32 peer);

    /**
     * @notice Sets the peer address (OApp instance) for a corresponding endpoint.
     * @param _eid The endpoint ID.
     * @param _peer The address of the peer to be associated with the corresponding endpoint.
     */
    function setPeer(uint32 _eid, bytes32 _peer) external;

    /**
     * @notice Sets the delegate address for the OApp Core.
     * @param _delegate The address of the delegate to be set.
     */
    function setDelegate(address _delegate) external;
}

File 32 of 43 : ILayerZeroReceiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { Origin } from "./ILayerZeroEndpointV2.sol";

interface ILayerZeroReceiver {
    function allowInitializePath(Origin calldata _origin) external view returns (bool);

    // todo: move to OAppReceiver? it is just convention for executor. we may can change it in a new Receiver version
    function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64);

    function lzReceive(
        Origin calldata _origin,
        bytes32 _guid,
        bytes calldata _message,
        address _executor,
        bytes calldata _extraData
    ) external payable;
}

File 33 of 43 : IOAppOptionsType3.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

/**
 * @dev Struct representing enforced option parameters.
 */
struct EnforcedOptionParam {
    uint32 eid; // Endpoint ID
    uint16 msgType; // Message Type
    bytes options; // Additional options
}

/**
 * @title IOAppOptionsType3
 * @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options.
 */
interface IOAppOptionsType3 {
    // Custom error message for invalid options
    error InvalidOptions(bytes options);

    // Event emitted when enforced options are set
    event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions);

    /**
     * @notice Sets enforced options for specific endpoint and message type combinations.
     * @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
     */
    function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external;

    /**
     * @notice Combines options for a given endpoint and message type.
     * @param _eid The endpoint ID.
     * @param _msgType The OApp message type.
     * @param _extraOptions Additional options passed by the caller.
     * @return options The combination of caller specified options AND enforced options.
     */
    function combineOptions(
        uint32 _eid,
        uint16 _msgType,
        bytes calldata _extraOptions
    ) external view returns (bytes memory options);
}

File 34 of 43 : IPreCrime.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;
struct PreCrimePeer {
    uint32 eid;
    bytes32 preCrime;
    bytes32 oApp;
}

// TODO not done yet
interface IPreCrime {
    error OnlyOffChain();

    // for simulate()
    error PacketOversize(uint256 max, uint256 actual);
    error PacketUnsorted();
    error SimulationFailed(bytes reason);

    // for preCrime()
    error SimulationResultNotFound(uint32 eid);
    error InvalidSimulationResult(uint32 eid, bytes reason);
    error CrimeFound(bytes crime);

    function getConfig(bytes[] calldata _packets, uint256[] calldata _packetMsgValues) external returns (bytes memory);

    function simulate(
        bytes[] calldata _packets,
        uint256[] calldata _packetMsgValues
    ) external payable returns (bytes memory);

    function buildSimulationResult() external view returns (bytes memory);

    function preCrime(
        bytes[] calldata _packets,
        uint256[] calldata _packetMsgValues,
        bytes[] calldata _simulations
    ) external;

    function version() external view returns (uint64 major, uint8 minor);
}

File 35 of 43 : IOAppPreCrimeSimulator.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

// @dev Import the Origin so it's exposed to OAppPreCrimeSimulator implementers.
// solhint-disable-next-line no-unused-import
import { InboundPacket, Origin } from "../libs/Packet.sol";

/**
 * @title IOAppPreCrimeSimulator Interface
 * @dev Interface for the preCrime simulation functionality in an OApp.
 */
interface IOAppPreCrimeSimulator {
    // @dev simulation result used in PreCrime implementation
    error SimulationResult(bytes result);
    error OnlySelf();

    /**
     * @dev Emitted when the preCrime contract address is set.
     * @param preCrimeAddress The address of the preCrime contract.
     */
    event PreCrimeSet(address preCrimeAddress);

    /**
     * @dev Retrieves the address of the preCrime contract implementation.
     * @return The address of the preCrime contract.
     */
    function preCrime() external view returns (address);

    /**
     * @dev Retrieves the address of the OApp contract.
     * @return The address of the OApp contract.
     */
    function oApp() external view returns (address);

    /**
     * @dev Sets the preCrime contract address.
     * @param _preCrime The address of the preCrime contract.
     */
    function setPreCrime(address _preCrime) external;

    /**
     * @dev Mocks receiving a packet, then reverts with a series of data to infer the state/result.
     * @param _packets An array of LayerZero InboundPacket objects representing received packets.
     */
    function lzReceiveAndRevert(InboundPacket[] calldata _packets) external payable;

    /**
     * @dev checks if the specified peer is considered 'trusted' by the OApp.
     * @param _eid The endpoint Id to check.
     * @param _peer The peer to check.
     * @return Whether the peer passed is considered 'trusted' by the OApp.
     */
    function isPeer(uint32 _eid, bytes32 _peer) external view returns (bool);
}

File 36 of 43 : Packet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";

/**
 * @title InboundPacket
 * @dev Structure representing an inbound packet received by the contract.
 */
struct InboundPacket {
    Origin origin; // Origin information of the packet.
    uint32 dstEid; // Destination endpointId of the packet.
    address receiver; // Receiver address for the packet.
    bytes32 guid; // Unique identifier of the packet.
    uint256 value; // msg.value of the packet.
    address executor; // Executor address for the packet.
    bytes message; // Message payload of the packet.
    bytes extraData; // Additional arbitrary data for the packet.
}

/**
 * @title PacketDecoder
 * @dev Library for decoding LayerZero packets.
 */
library PacketDecoder {
    using PacketV1Codec for bytes;

    /**
     * @dev Decode an inbound packet from the given packet data.
     * @param _packet The packet data to decode.
     * @return packet An InboundPacket struct representing the decoded packet.
     */
    function decode(bytes calldata _packet) internal pure returns (InboundPacket memory packet) {
        packet.origin = Origin(_packet.srcEid(), _packet.sender(), _packet.nonce());
        packet.dstEid = _packet.dstEid();
        packet.receiver = _packet.receiverB20();
        packet.guid = _packet.guid();
        packet.message = _packet.message();
    }

    /**
     * @dev Decode multiple inbound packets from the given packet data and associated message values.
     * @param _packets An array of packet data to decode.
     * @param _packetMsgValues An array of associated message values for each packet.
     * @return packets An array of InboundPacket structs representing the decoded packets.
     */
    function decode(
        bytes[] calldata _packets,
        uint256[] memory _packetMsgValues
    ) internal pure returns (InboundPacket[] memory packets) {
        packets = new InboundPacket[](_packets.length);
        for (uint256 i = 0; i < _packets.length; i++) {
            bytes calldata packet = _packets[i];
            packets[i] = PacketDecoder.decode(packet);
            // @dev Allows the verifier to specify the msg.value that gets passed in lzReceive.
            packets[i].value = _packetMsgValues[i];
        }
    }
}

File 37 of 43 : PacketV1Codec.sol
// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.22;

import { Packet } from "../../interfaces/ISendLib.sol";
import { AddressCast } from "../../libs/AddressCast.sol";

library PacketV1Codec {
    using AddressCast for address;
    using AddressCast for bytes32;

    uint8 internal constant PACKET_VERSION = 1;

    // header (version + nonce + path)
    // version
    uint256 private constant PACKET_VERSION_OFFSET = 0;
    //    nonce
    uint256 private constant NONCE_OFFSET = 1;
    //    path
    uint256 private constant SRC_EID_OFFSET = 9;
    uint256 private constant SENDER_OFFSET = 13;
    uint256 private constant DST_EID_OFFSET = 45;
    uint256 private constant RECEIVER_OFFSET = 49;
    // payload (guid + message)
    uint256 private constant GUID_OFFSET = 81; // keccak256(nonce + path)
    uint256 private constant MESSAGE_OFFSET = 113;

    function encode(Packet memory _packet) internal pure returns (bytes memory encodedPacket) {
        encodedPacket = abi.encodePacked(
            PACKET_VERSION,
            _packet.nonce,
            _packet.srcEid,
            _packet.sender.toBytes32(),
            _packet.dstEid,
            _packet.receiver,
            _packet.guid,
            _packet.message
        );
    }

    function encodePacketHeader(Packet memory _packet) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                PACKET_VERSION,
                _packet.nonce,
                _packet.srcEid,
                _packet.sender.toBytes32(),
                _packet.dstEid,
                _packet.receiver
            );
    }

    function encodePayload(Packet memory _packet) internal pure returns (bytes memory) {
        return abi.encodePacked(_packet.guid, _packet.message);
    }

    function header(bytes calldata _packet) internal pure returns (bytes calldata) {
        return _packet[0:GUID_OFFSET];
    }

    function version(bytes calldata _packet) internal pure returns (uint8) {
        return uint8(bytes1(_packet[PACKET_VERSION_OFFSET:NONCE_OFFSET]));
    }

    function nonce(bytes calldata _packet) internal pure returns (uint64) {
        return uint64(bytes8(_packet[NONCE_OFFSET:SRC_EID_OFFSET]));
    }

    function srcEid(bytes calldata _packet) internal pure returns (uint32) {
        return uint32(bytes4(_packet[SRC_EID_OFFSET:SENDER_OFFSET]));
    }

    function sender(bytes calldata _packet) internal pure returns (bytes32) {
        return bytes32(_packet[SENDER_OFFSET:DST_EID_OFFSET]);
    }

    function senderAddressB20(bytes calldata _packet) internal pure returns (address) {
        return sender(_packet).toAddress();
    }

    function dstEid(bytes calldata _packet) internal pure returns (uint32) {
        return uint32(bytes4(_packet[DST_EID_OFFSET:RECEIVER_OFFSET]));
    }

    function receiver(bytes calldata _packet) internal pure returns (bytes32) {
        return bytes32(_packet[RECEIVER_OFFSET:GUID_OFFSET]);
    }

    function receiverB20(bytes calldata _packet) internal pure returns (address) {
        return receiver(_packet).toAddress();
    }

    function guid(bytes calldata _packet) internal pure returns (bytes32) {
        return bytes32(_packet[GUID_OFFSET:MESSAGE_OFFSET]);
    }

    function message(bytes calldata _packet) internal pure returns (bytes calldata) {
        return bytes(_packet[MESSAGE_OFFSET:]);
    }

    function payload(bytes calldata _packet) internal pure returns (bytes calldata) {
        return bytes(_packet[GUID_OFFSET:]);
    }

    function payloadHash(bytes calldata _packet) internal pure returns (bytes32) {
        return keccak256(payload(_packet));
    }
}

File 38 of 43 : ISendLib.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { MessagingFee } from "./ILayerZeroEndpointV2.sol";
import { IMessageLib } from "./IMessageLib.sol";

struct Packet {
    uint64 nonce;
    uint32 srcEid;
    address sender;
    uint32 dstEid;
    bytes32 receiver;
    bytes32 guid;
    bytes message;
}

interface ISendLib is IMessageLib {
    function send(
        Packet calldata _packet,
        bytes calldata _options,
        bool _payInLzToken
    ) external returns (MessagingFee memory, bytes memory encodedPacket);

    function quote(
        Packet calldata _packet,
        bytes calldata _options,
        bool _payInLzToken
    ) external view returns (MessagingFee memory);

    function setTreasury(address _treasury) external;

    function withdrawFee(address _to, uint256 _amount) external;

    function withdrawLzTokenFee(address _lzToken, address _to, uint256 _amount) external;
}

File 39 of 43 : AddressCast.sol
// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.22;

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

library AddressCast {
    function toBytes32(bytes calldata _addressBytes) internal pure returns (bytes32 result) {
        if (_addressBytes.length > 32) revert Errors.InvalidAddress();
        result = bytes32(_addressBytes);
        unchecked {
            uint256 offset = 32 - _addressBytes.length;
            result = result >> (offset * 8);
        }
    }

    function toBytes32(address _address) internal pure returns (bytes32 result) {
        result = bytes32(uint256(uint160(_address)));
    }

    function toBytes(bytes32 _addressBytes32, uint256 _size) internal pure returns (bytes memory result) {
        if (_size == 0 || _size > 32) revert Errors.InvalidSizeForAddress();
        result = new bytes(_size);
        unchecked {
            uint256 offset = 256 - _size * 8;
            assembly {
                mstore(add(result, 32), shl(offset, _addressBytes32))
            }
        }
    }

    function toAddress(bytes32 _addressBytes32) internal pure returns (address result) {
        result = address(uint160(uint256(_addressBytes32)));
    }

    function toAddress(bytes calldata _addressBytes) internal pure returns (address result) {
        if (_addressBytes.length != 20) revert Errors.InvalidAddress();
        result = address(bytes20(_addressBytes));
    }
}

File 40 of 43 : IMessageLib.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import { SetConfigParam } from "./IMessageLibManager.sol";

enum MessageLibType {
    Send,
    Receive,
    SendAndReceive
}

interface IMessageLib is IERC165 {
    function setConfig(address _oapp, SetConfigParam[] calldata _config) external;

    function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view returns (bytes memory config);

    function isSupportedEid(uint32 _eid) external view returns (bool);

    // message libs of same major version are compatible
    function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion);

    function messageLibType() external view returns (MessageLibType);
}

File 41 of 43 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 42 of 43 : Errors.sol
// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.22;

library Errors {
    error LzTokenUnavailable();
    error OnlyAltToken();
    error InvalidReceiveLibrary();
    error InvalidNonce(uint64 nonce);
    error InvalidArgument();
    error InvalidExpiry();
    error InvalidAmount(uint256 required, uint256 supplied);
    error OnlyRegisteredOrDefaultLib();
    error OnlyRegisteredLib();
    error OnlyNonDefaultLib();
    error Unauthorized();
    error DefaultSendLibUnavailable();
    error DefaultReceiveLibUnavailable();
    error PathNotInitializable();
    error PathNotVerifiable();
    error OnlySendLib();
    error OnlyReceiveLib();
    error UnsupportedEid();
    error UnsupportedInterface();
    error AlreadyRegistered();
    error SameValue();
    error InvalidPayloadHash();
    error PayloadHashNotFound(bytes32 expected, bytes32 actual);
    error ComposeNotFound(bytes32 expected, bytes32 actual);
    error ComposeExists();
    error SendReentrancy();
    error NotImplemented();
    error InvalidAddress();
    error InvalidSizeForAddress();
    error InsufficientFee(
        uint256 requiredNative,
        uint256 suppliedNative,
        uint256 requiredLzToken,
        uint256 suppliedLzToken
    );
    error ZeroLzTokenFee();
}

File 43 of 43 : ISignatureUtils.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;

/**
 * @title The interface for common signature utilities.
 * @author Layr Labs, Inc.
 * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
 */
interface ISignatureUtils {
    // @notice Struct that bundles together a signature and an expiration time for the signature. Used primarily for stack management.
    struct SignatureWithExpiry {
        // the signature itself, formatted as a single bytes object
        bytes signature;
        // the expiration timestamp (UTC) of the signature
        uint256 expiry;
    }

    // @notice Struct that bundles together a signature, a salt for uniqueness, and an expiration time for the signature. Used primarily for stack management.
    struct SignatureWithSaltAndExpiry {
        // the signature itself, formatted as a single bytes object
        bytes signature;
        // the salt used to generate the signature
        bytes32 salt;
        // the expiration timestamp (UTC) of the signature
        uint256 expiry;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

API
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_lst","type":"address"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address","name":"_lzEndpoint","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[],"name":"InvalidLocalDecimals","type":"error"},{"inputs":[{"internalType":"bytes","name":"options","type":"bytes"}],"name":"InvalidOptions","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[],"name":"OnlySelf","type":"error"},{"inputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"name":"SimulationResult","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountToCreditLD","type":"uint256"},{"internalType":"uint256","name":"minAmountToCreditLD","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AssetReceived","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"indexed":false,"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"EnforcedOptionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"inspector","type":"address"}],"name":"MsgInspectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountToCreditLD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountDebitedLD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountToCreditLD","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"composeMsg","type":"bytes"}],"name":"OFTSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"preCrimeAddress","type":"address"}],"name":"PreCrimeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"lstAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ortAmount","type":"uint256"}],"name":"Restaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"ortAmount","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"SEND","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEND_AND_CALL","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountLastSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountSnapshotToPreviousSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"assetSnapshotRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_msgType","type":"uint16"},{"internalType":"bytes","name":"_extraOptions","type":"bytes"}],"name":"combineOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"contractAccountLastSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"contractAccountSnapshotToPreviousSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimalConversionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegationManager","outputs":[{"internalType":"contract IDelegationManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"}],"name":"enforcedOptions","outputs":[{"internalType":"bytes","name":"enforcedOption","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"isPeer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lrtToLst","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lst","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lstToLrt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct InboundPacket[]","name":"_packets","type":"tuple[]"}],"name":"lzReceiveAndRevert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceiveSimulate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"minAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"msgInspector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oApp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"oftVersion","outputs":[{"internalType":"uint64","name":"major","type":"uint64"},{"internalType":"uint64","name":"minor","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preCrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountToSendLD","type":"uint256"},{"internalType":"uint256","name":"minAmountToCreditLD","type":"uint256"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"quoteOFT","outputs":[{"components":[{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"uint256","name":"maxAmountLD","type":"uint256"}],"internalType":"struct OFTLimit","name":"oftLimit","type":"tuple"},{"components":[{"internalType":"uint256","name":"feeAmountLD","type":"uint256"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct OFTFeeDetail[]","name":"oftFeeDetails","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"amountDebitLD","type":"uint256"},{"internalType":"uint256","name":"amountCreditLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountToSendLD","type":"uint256"},{"internalType":"uint256","name":"minAmountToCreditLD","type":"uint256"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bytes","name":"_extraOptions","type":"bytes"},{"internalType":"bool","name":"_payInLzToken","type":"bool"},{"internalType":"bytes","name":"_composeMsg","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"quoteSend","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"msgFee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"restake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"restakedOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountToSendLD","type":"uint256"},{"internalType":"uint256","name":"minAmountToCreditLD","type":"uint256"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bytes","name":"_extraOptions","type":"bytes"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"_refundAddress","type":"address"},{"internalType":"bytes","name":"_composeMsg","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"send","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct MessagingReceipt","name":"msgReceipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountDebitLD","type":"uint256"},{"internalType":"uint256","name":"amountCreditLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"setEnforcedOptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_msgInspector","type":"address"}],"name":"setMsgInspector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_preCrime","type":"address"}],"name":"setPreCrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsManager","type":"address"}],"name":"setRewardsManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharedDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"snapshotAccountBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"snapshotContractAccountBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"snapshotNativeRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyManager","outputs":[{"internalType":"contract IStrategyManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalSupplySnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"transferAssetToRewardsManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_shares","type":"uint256[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c0604052606460115534801562000015575f80fd5b50604051620053683803806200536883398101604081905262000038916200072b565b84848233838360128484818181816200005133620001d0565b6200005c81620001d0565b6001600160a01b03828116608081905260405163ca5eb5e160e01b815291831660048301529063ca5eb5e1906024015f604051808303815f87803b158015620000a3575f80fd5b505af1158015620000b6573d5f803e3d5ffd5b5050505050505050620000ce6200021f60201b60201c565b60ff168360ff161015620000f5576040516301e9714b60e41b815260040160405180910390fd5b62000102600484620007db565b6200010f90600a620008f6565b60a0525060089150620001259050838262000996565b50600962000134828262000996565b50506001600a555050600d80546001600160a01b038089166001600160a01b031992831617909255600e805492881692821692909217909155600f8054821673779d1b5315df083e3f9e94cb495983500ba8e90717905560108054909116731b7b8f6b258f95cf9596eabb9aa18b62940eb0a8179055505042600b5550620001c533670de0b6b3a764000062000224565b505050505062000aae565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600490565b6001600160a01b0382166200027f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b6200028c5f838362000323565b8060075f8282546200029f919062000a62565b90915550506001600160a01b0382165f9081526005602052604081208054839290620002cd90849062000a62565b90915550506040518181526001600160a01b038316905f907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36200031f5f8383620005eb565b5050565b5f6200032e6200061b565b9050833b151580156200034a57506001600160a01b0384163014155b1562000434576001600160a01b038085165f8181526013602090815260408083209488168084529482528083208054908790558484526014835281842086855283528184208785528352818420819055601283528184209484529382528083209483529390529190912054831115620003c4575f620003ff565b5f8281526012602090815260408083206001600160a01b03808a1685529083528184209088168452909152902054620003ff90849062000a78565b5f8381526012602090815260408083206001600160a01b03808b168552908352818420908916845290915290205550620004d8565b5f8181526016602090815260408083206001600160a01b038816845290915290205482111562000465575f62000494565b5f8181526016602090815260408083206001600160a01b03881684529091529020546200049490839062000a78565b5f8281526016602090815260408083206001600160a01b03891684528252808320939093556017815282822080549085905560188252838320858452909152919020555b823b15158015620004f257506001600160a01b0383163014155b156200057b576001600160a01b038084165f8181526013602090815260408083209489168084529482528083208054908790558484526014835281842086855283528184208785528352818420819055601283528184209484529382528083209483529390529182208054919285926200056e90849062000a62565b90915550620005e5915050565b5f8181526016602090815260408083206001600160a01b038716845290915281208054849290620005ae90849062000a62565b90915550506001600160a01b0383165f90815260176020908152604080832080549085905560188352818420858552909252909120555b50505050565b5f620005f66200061b565b90506200060260075490565b5f9182526019602052604090912055505050565b505050565b5f62015180600b544262000630919062000a78565b6200063c919062000a8e565b6200064990600162000a62565b905090565b634e487b7160e01b5f52604160045260245ffd5b5f82601f83011262000672575f80fd5b81516001600160401b03808211156200068f576200068f6200064e565b604051601f8301601f19908116603f01168101908282118183101715620006ba57620006ba6200064e565b8160405283815260209250866020858801011115620006d7575f80fd5b5f91505b83821015620006fa5785820183015181830184015290820190620006db565b5f602085830101528094505050505092915050565b80516001600160a01b038116811462000726575f80fd5b919050565b5f805f805f60a0868803121562000740575f80fd5b85516001600160401b038082111562000757575f80fd5b6200076589838a0162000662565b965060208801519150808211156200077b575f80fd5b506200078a8882890162000662565b9450506200079b604087016200070f565b9250620007ab606087016200070f565b9150620007bb608087016200070f565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b60ff8281168282160390811115620007f757620007f7620007c7565b92915050565b600181815b808511156200083d57815f1904821115620008215762000821620007c7565b808516156200082f57918102915b93841c939080029062000802565b509250929050565b5f826200085557506001620007f7565b816200086357505f620007f7565b81600181146200087c57600281146200088757620008a7565b6001915050620007f7565b60ff8411156200089b576200089b620007c7565b50506001821b620007f7565b5060208310610133831016604e8410600b8410161715620008cc575081810a620007f7565b620008d88383620007fd565b805f1904821115620008ee57620008ee620007c7565b029392505050565b5f6200090660ff84168362000845565b9392505050565b600181811c908216806200092257607f821691505b6020821081036200094157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200061657805f5260205f20601f840160051c810160208510156200096e5750805b601f840160051c820191505b818110156200098f575f81556001016200097a565b5050505050565b81516001600160401b03811115620009b257620009b26200064e565b620009ca81620009c384546200090d565b8462000947565b602080601f83116001811462000a00575f8415620009e85750858301515b5f19600386901b1c1916600185901b17855562000a5a565b5f85815260208120601f198616915b8281101562000a305788860151825594840194600190910190840162000a0f565b508582101562000a4e57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b80820180821115620007f757620007f7620007c7565b81810381811115620007f757620007f7620007c7565b5f8262000aa957634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05161485262000b165f395f81816108c001528181612d64015281816130ff015261313801525f818161068501528181610d6601528181611df60152818161247b01528181612866015281816129930152818161324801526132ff01526148525ff3fe6080604052600436106102eb575f3560e01c806306fdde0314610370578063095ea7b31461039a5780630a8ddc5e146103c95780630c8aa637146103ea578063111ecdad1461042357806313137d651461044f578063134d4f2514610462578063156a0d0f1461048957806317442b701461048957806318160ddd146104a957806318e8cb96146104bd5780631f5e1334146104dc57806323b872dd146104f0578063313ce5671461050f5780633400288b14610530578063395093511461054f57806339b70e381461056e5780633aaa607f1461058d57806346a40f75146105b857806349e46017146105e45780634e2648e31461060557806352ae2879146106245780635535d461146106365780635a0dfe4d146106555780635e280f111461067457806363bdf199146106a75780636c1efe8f146106d25780636fc1b31e146106fd57806370a082311461071c578063715018a61461073b5780637d25a05e1461074f5780638055082514610788578063813bc123146107be5780638286b4ee146107fa578063857749b0146108195780638d17437c1461082c5780638da5cb5b1461084b5780639559d3261461085f57806395d89b411461089b578063963efcaa146108af5780639b2cb5d8146108e2578063a457c2d7146108f7578063a8c62e7614610916578063a9059cbb14610935578063afeb7e2914610954578063b731ea0a1461098a578063b98bd070146109a9578063bb0b6a53146109c8578063bc70b354146109f3578063bce1b52014610a12578063bd815db014610a31578063c1e3650014610a44578063ca5eb5e114610a72578063d045a0dc14610a91578063d252d99714610aa4578063d424388514610ada578063dd62ed3e14610af9578063defe205314610b3d578063e449f34114610b5c578063e479232814610b7b578063ea4d3c9b14610bb1578063eae4c19f14610bd0578063f2fde38b14610be5578063f6fc7eb614610c04578063fc0c546a14610624578063ff7bd03d14610c18575f80fd5b3661036c5760405134815233905f907f322d0c4befd4c2dd440740b711488a1638fd7d8eeb25f9dacede84083db428c99060200160405180910390a35f610330610c37565b90503460155f8381526020019081526020015f205f8282546103529190613588565b90915550506007545f828152601960205260409020819055005b5f80fd5b34801561037b575f80fd5b50610384610c64565b60405161039191906135e8565b60405180910390f35b3480156103a5575f80fd5b506103b96103b436600461361e565b610cf4565b6040519015158152602001610391565b3480156103d4575f80fd5b506103e86103e3366004613648565b610d0a565b005b3480156103f5575f80fd5b50610415610404366004613663565b60196020525f908152604090205481565b604051908152602001610391565b34801561042e575f80fd5b50600454610442906001600160a01b031681565b604051610391919061367a565b6103e861045d3660046136e1565b610d64565b34801561046d575f80fd5b50610476600281565b60405161ffff9091168152602001610391565b348015610494575f80fd5b50604080516001808252602082015201610391565b3480156104b4575f80fd5b50600754610415565b3480156104c8575f80fd5b50600d54610442906001600160a01b031681565b3480156104e7575f80fd5b50610476600181565b3480156104fb575f80fd5b506103b961050a366004613779565b610e13565b34801561051a575f80fd5b5060125b60405160ff9091168152602001610391565b34801561053b575f80fd5b506103e861054a3660046137ca565b610ebd565b34801561055a575f80fd5b506103b961056936600461361e565b610f41565b348015610579575f80fd5b50600f54610442906001600160a01b031681565b348015610598575f80fd5b506104156105a7366004613648565b601b6020525f908152604090205481565b3480156105c3575f80fd5b506105d76105d2366004613801565b610f7c565b60405161039191906138c8565b6105f76105f23660046138d6565b610fe4565b6040516103919291906139af565b348015610610575f80fd5b5061041561061f366004613663565b6110d6565b34801561062f575f80fd5b5030610442565b348015610641575f80fd5b506103846106503660046139fc565b611142565b348015610660575f80fd5b506103b961066f3660046137ca565b6111e4565b34801561067f575f80fd5b506104427f000000000000000000000000000000000000000000000000000000000000000081565b3480156106b2575f80fd5b506104156106c1366004613648565b60176020525f908152604090205481565b3480156106dd575f80fd5b506104156106ec366004613663565b60156020525f908152604090205481565b348015610708575f80fd5b506103e8610717366004613648565b6111ff565b348015610727575f80fd5b50610415610736366004613648565b611284565b348015610746575f80fd5b506103e861129e565b34801561075a575f80fd5b506107706107693660046137ca565b5f92915050565b6040516001600160401b039091168152602001610391565b348015610793575f80fd5b506104156107a2366004613a2d565b601660209081525f928352604080842090915290825290205481565b3480156107c9575f80fd5b506104156107d8366004613a5b565b601260209081525f938452604080852082529284528284209052825290205481565b348015610805575f80fd5b50610415610814366004613663565b6112d8565b348015610824575f80fd5b50600461051e565b348015610837575f80fd5b506103e8610846366004613648565b611309565b348015610856575f80fd5b5061044261156f565b34801561086a575f80fd5b50610415610879366004613779565b601460209081525f938452604080852082529284528284209052825290205481565b3480156108a6575f80fd5b5061038461157d565b3480156108ba575f80fd5b506104157f000000000000000000000000000000000000000000000000000000000000000081565b3480156108ed575f80fd5b5061041560115481565b348015610902575f80fd5b506103b961091136600461361e565b61158c565b348015610921575f80fd5b50600e54610442906001600160a01b031681565b348015610940575f80fd5b506103b961094f36600461361e565b611624565b34801561095f575f80fd5b5061041561096e36600461361e565b601860209081525f928352604080842090915290825290205481565b348015610995575f80fd5b50600254610442906001600160a01b031681565b3480156109b4575f80fd5b506103e86109c3366004613ada565b611630565b3480156109d3575f80fd5b506104156109e2366004613b0c565b60016020525f908152604090205481565b3480156109fe575f80fd5b50610384610a0d366004613b25565b6117b3565b348015610a1d575f80fd5b506103e8610a2c366004613663565b611928565b6103e8610a3f366004613ada565b611b8d565b348015610a4f575f80fd5b50610a63610a5e366004613b81565b611cf7565b60405161039193929190613bd0565b348015610a7d575f80fd5b506103e8610a8c366004613648565b611db0565b6103e8610a9f3660046136e1565b611e5b565b348015610aaf575f80fd5b50610415610abe366004613c5c565b601360209081525f928352604080842090915290825290205481565b348015610ae5575f80fd5b506103e8610af4366004613648565b611e8a565b348015610b04575f80fd5b50610415610b13366004613c5c565b6001600160a01b039182165f90815260066020908152604080832093909416825291909152205490565b348015610b48575f80fd5b50600c54610442906001600160a01b031681565b348015610b67575f80fd5b506103e8610b76366004613d16565b611f04565b348015610b86575f80fd5b50610415610b9536600461361e565b601a60209081525f928352604080842090915290825290205481565b348015610bbc575f80fd5b50601054610442906001600160a01b031681565b348015610bdb575f80fd5b50610415600b5481565b348015610bf0575f80fd5b506103e8610bff366004613648565b6121b3565b348015610c0f575f80fd5b50610415610c37565b348015610c23575f80fd5b506103b9610c32366004613d9b565b612253565b5f62015180600b5442610c4a9190613db5565b610c549190613dc8565b610c5f906001613588565b905090565b606060088054610c7390613de7565b80601f0160208091040260200160405190810160405280929190818152602001828054610c9f90613de7565b8015610cea5780601f10610cc157610100808354040283529160200191610cea565b820191905f5260205f20905b815481529060010190602001808311610ccd57829003601f168201915b5050505050905090565b5f610d00338484612287565b5060015b92915050565b33610d1361156f565b6001600160a01b031614610d425760405162461bcd60e51b8152600401610d3990613e19565b60405180910390fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610daf57336040516391ac5e4f60e01b8152600401610d39919061367a565b60208701803590610dc990610dc4908a613b0c565b6123aa565b14610dfb57610ddb6020880188613b0c565b876020013560405163309afaf360e21b8152600401610d39929190613e4e565b610e0a878787878787876123e5565b50505050505050565b5f610e1f848484612537565b6001600160a01b0384165f90815260066020908152604080832033845290915290205482811015610ea35760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b6064820152608401610d39565b610eb08533858403612287565b60019150505b9392505050565b33610ec661156f565b6001600160a01b031614610eec5760405162461bcd60e51b8152600401610d3990613e19565b63ffffffff82165f9081526001602052604090819020829055517f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b90610f359084908490613e4e565b60405180910390a15050565b335f8181526006602090815260408083206001600160a01b03871684529091528120549091610d00918590610f77908690613588565b612287565b610f84613539565b5f610fa460408b013560608c0135610f9f60208e018e613b0c565b612707565b9150505f80610fb78c8c8c8b8b8861274a565b9092509050610fd4610fcc60208e018e613b0c565b83838c61285c565b9c9b505050505050505050505050565b610fec613551565b610ff4613539565b5f8061101a8d604001358e606001358f5f0160208101906110159190613b0c565b61292f565b915091505f8061102e8f8f8f8d8d8861274a565b915091506110608f5f0160208101906110479190613b0c565b83838f80360381019061105a9190613e64565b8f612962565b95506040518060400160405280858152602001848152509450336001600160a01b0316865f01517fee6b77e8cd280835aecc97812d736c35faad222d91b12de19c7ed912e9aed71b86868e8e6040516110bc9493929190613ebc565b60405180910390a350505050995099975050505050505050565b600e54604051637a8b263760e01b8152600481018390525f916001600160a01b031690637a8b2637906024015b602060405180830381865afa15801561111e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d049190613ee5565b600360209081525f92835260408084209091529082529020805461116590613de7565b80601f016020809104026020016040519081016040528092919081815260200182805461119190613de7565b80156111dc5780601f106111b3576101008083540402835291602001916111dc565b820191905f5260205f20905b8154815290600101906020018083116111bf57829003601f168201915b505050505081565b63ffffffff919091165f908152600160205260409020541490565b3361120861156f565b6001600160a01b03161461122e5760405162461bcd60e51b8152600401610d3990613e19565b600480546001600160a01b0319166001600160a01b0383161790556040517ff0be4f1e87349231d80c36b33f9e8639658eeaf474014dee15a3e6a4d44141979061127990839061367a565b60405180910390a150565b6001600160a01b03165f9081526005602052604090205490565b336112a761156f565b6001600160a01b0316146112cd5760405162461bcd60e51b8152600401610d3990613e19565b6112d65f612a68565b565b600e546040516338f6b94760e21b8152600481018390525f916001600160a01b03169063e3dae51c90602401611103565b3361131261156f565b6001600160a01b0316146113385760405162461bcd60e51b8152600401610d3990613e19565b6002600a540361135a5760405162461bcd60e51b8152600401610d3990613efc565b6002600a55600c546001600160a01b03166113a95760405162461bcd60e51b815260206004820152600f60248201526e10b932bbb0b93239a6b0b730b3b2b960891b6044820152606401610d39565b6001600160a01b03811661144857600c546040515f916001600160a01b03169047908381818185875af1925050503d805f8114611401576040519150601f19603f3d011682016040523d82523d5f602084013e611406565b606091505b50509050806114425760405162461bcd60e51b8152602060048201526008602482015267217375636365737360c01b6044820152606401610d39565b50611567565b6040516370a0823160e01b815281905f906001600160a01b038316906370a082319061147890309060040161367a565b602060405180830381865afa158015611493573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b79190613ee5565b600c5460405163a9059cbb60e01b81529192506001600160a01b038085169263a9059cbb926114ec9216908590600401613f33565b6020604051808303815f875af1158015611508573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152c9190613f4c565b6115645760405162461bcd60e51b815260206004820152600960248201526810ba3930b739b332b960b91b6044820152606401610d39565b50505b506001600a55565b5f546001600160a01b031690565b606060098054610c7390613de7565b335f9081526006602090815260408083206001600160a01b03861684529091528120548281101561160d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610d39565b61161a3385858403612287565b5060019392505050565b5f610d00338484612537565b3361163961156f565b6001600160a01b03161461165f5760405162461bcd60e51b8152600401610d3990613e19565b5f5b81811015611781576116a383838381811061167e5761167e613f67565b90506020028101906116909190613f7b565b61169e906040810190613f99565b612ab7565b8282828181106116b5576116b5613f67565b90506020028101906116c79190613f7b565b6116d5906040810190613f99565b60035f8686868181106116ea576116ea613f67565b90506020028101906116fc9190613f7b565b61170a906020810190613b0c565b63ffffffff1663ffffffff1681526020019081526020015f205f86868681811061173657611736613f67565b90506020028101906117489190613f7b565b611759906040810190602001613fdb565b61ffff16815260208101919091526040015f2091611778919083614038565b50600101611661565b507fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b6748282604051610f359291906140f1565b63ffffffff84165f90815260036020908152604080832061ffff871684529091528120805460609291906117e690613de7565b80601f016020809104026020016040519081016040528092919081815260200182805461181290613de7565b801561185d5780601f106118345761010080835404028352916020019161185d565b820191905f5260205f20905b81548152906001019060200180831161184057829003601f168201915b5050505050905080515f036118ab5783838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509294506119209350505050565b5f8390036118ba579050611920565b60028310611903576118cc8484612ab7565b806118da84600281886141d0565b6040516020016118ec939291906141f7565b604051602081830303815290604052915050611920565b8383604051639a6d49cd60e01b8152600401610d3992919061421d565b949350505050565b6002600a540361194a5760405162461bcd60e51b8152600401610d3990613efc565b6002600a556011548110156119715760405162461bcd60e51b8152600401610d3990614230565b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906119a590339030908690600401614257565b6020604051808303815f875af11580156119c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119e59190613f4c565b611a215760405162461bcd60e51b815260206004820152600d60248201526c217472616e7366657246726f6d60981b6044820152606401610d39565b600d54600f5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611a57929116908590600401613f33565b6020604051808303815f875af1158015611a73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a979190613f4c565b50600f54600e54600d546040516373d0285560e11b81525f936001600160a01b039081169363e7a050aa93611ad6939183169216908790600401614257565b6020604051808303815f875af1158015611af2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b169190613ee5565b335f908152601b6020526040812080549293508392909190611b39908490613588565b90915550611b4990503382612afd565b604080518381526020810183905233917fa217c421e0e9357b7b1815d752952b142ddc0e23f9f14ecb8233f8f83d563c4d910160405180910390a250506001600a55565b5f5b81811015611c7a5736838383818110611baa57611baa613f67565b9050602002810190611bbc919061427b565b9050611bd8611bce6020830183613b0c565b60208301356111e4565b611be25750611c72565b3063d045a0dc60c08301358360a0810135611c01610100830183613f99565b611c12610100890160e08a01613648565b611c206101208a018a613f99565b6040518963ffffffff1660e01b8152600401611c4297969594939291906142a4565b5f604051808303818588803b158015611c59575f80fd5b505af1158015611c6b573d5f803e3d5ffd5b5050505050505b600101611b8f565b50336001600160a01b0316638e9e70996040518163ffffffff1660e01b81526004015f60405180830381865afa158015611cb6573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611cdd9190810190614329565b604051638351eea760e01b8152600401610d3991906135e8565b604080518082019091525f80825260208201526060611d14613539565b6040805180820182525f8082526001600160401b03602080840182905284518381529081019094529195509182611d6d565b604080518082019091525f815260606020820152815260200190600190039081611d465790505b5093505f80611d8c60408b013560608c0135610f9f60208e018e613b0c565b604080518082019091529182526020820152969a9599509597509395505050505050565b33611db961156f565b6001600160a01b031614611ddf5760405162461bcd60e51b8152600401610d3990613e19565b60405163ca5eb5e160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ca5eb5e190611e2b90849060040161367a565b5f604051808303815f87803b158015611e42575f80fd5b505af1158015611e54573d5f803e3d5ffd5b5050505050565b333014611e7b5760405163029a949d60e31b815260040160405180910390fd5b610e0a87878787878787610dfb565b33611e9361156f565b6001600160a01b031614611eb95760405162461bcd60e51b8152600401610d3990613e19565b600280546001600160a01b0319166001600160a01b0383161790556040517fd48d879cef83a1c0bdda516f27b13ddb1b3f8bbac1c9e1511bb2a659c24277609061127990839061367a565b6002600a5403611f265760405162461bcd60e51b8152600401610d3990613efc565b6002600a558051600114611f7c5760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c79206f6e65207769746864726177616c20617420612074696d650000006044820152606401610d39565b5f815f81518110611f8f57611f8f613f67565b60200260200101519050601154811015611fbb5760405162461bcd60e51b8152600401610d3990614230565b80611fc533611284565b10156120005760405162461bcd60e51b815260206004820152600a6024820152691e3130b630b731b2a7b360b11b6044820152606401610d39565b6040805160018082528183019092525f91816020015b604080516060808201835280825260208201525f918101919091528152602001906001900390816120165750506040805160018082528183019092529192505f9190602080830190803683375050600e5482519293506001600160a01b0316918391505f9061208757612087613f67565b6001600160a01b03909216602092830291909101820152604080516060810182528381529182018690523390820152825183905f906120c8576120c8613f67565b60209081029190910101526010546040516306ec6e8160e11b81526001600160a01b0390911690630dd8dd02906121039085906004016143b7565b5f604051808303815f875af115801561211e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612145919081019061449a565b506121503384612bdc565b335f908152601b60205260408120805485929061216e908490613db5565b909155505060405183815233907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f759060200160405180910390a250506001600a555050565b336121bc61156f565b6001600160a01b0316146121e25760405162461bcd60e51b8152600401610d3990613e19565b6001600160a01b0381166122475760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610d39565b61225081612a68565b50565b5f60208201803590600190839061226a9086613b0c565b63ffffffff16815260208101919091526040015f20541492915050565b6001600160a01b0383166122e95760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610d39565b6001600160a01b03821661234a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610d39565b6001600160a01b038381165f8181526006602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b63ffffffff81165f9081526001602052604081205480610d045760405163f6ff4fb760e01b815263ffffffff84166004820152602401610d39565b5f6123f66123f38787612d25565b90565b90505f61240b6124068888612d3c565b612d5e565b90505f612425838361242060208e018e613b0c565b612d92565b905060288711156124e5575f61246161244460608d0160408e0161451a565b61245160208e018e613b0c565b8461245c8d8d612da5565b612def565b604051633e5ac80960e11b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637cb59012906124b69087908e905f908790600401614535565b5f604051808303815f87803b1580156124cd575f80fd5b505af11580156124df573d5f803e3d5ffd5b50505050505b60408051838152602081018390526001600160a01b038516918b917f80a66cf84dc0b742c17c4672ee6687d7cb340ab0e5d367ac6b02bed1a6489f8d910160405180910390a350505050505050505050565b6001600160a01b03831661259b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610d39565b6001600160a01b0382166125fd5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610d39565b612608838383612e21565b6001600160a01b0383165f908152600560205260409020548181101561267f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610d39565b6001600160a01b038085165f908152600560205260408082208585039055918516815290812080548492906126b5908490613588565b92505081905550826001600160a01b0316846001600160a01b03165f805160206147fd833981519152846040516126ee91815260200190565b60405180910390a36127018484846130d4565b50505050565b5f80612712856130fc565b915081905083811015612742576040516371c4efed60e01b81526004810182905260248101859052604401610d39565b935093915050565b6060805f61279a896020013561275f86613132565b88888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061315d92505050565b90935090505f816127ac5760016127af565b60025b90506127c96127c160208c018c613b0c565b828b8b6117b3565b6004549093506001600160a01b03161561284f576004805460405163043a78eb60e01b81526001600160a01b039091169163043a78eb9161280e918891889101614565565b602060405180830381865afa158015612829573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061284d9190613f4c565b505b5050965096945050505050565b612864613539565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ddc28c586040518060a001604052808863ffffffff1681526020016128b3896123aa565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b81526004016128e8929190614589565b6040805180830381865afa158015612902573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612926919061462f565b95945050505050565b5f80841561294c576129428585856131d7565b9092509050612742565b61295684846131f3565b90969095509350505050565b61296a613551565b5f612977845f015161321e565b602085015190915015612991576129918460200151613245565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632637a450826040518060a001604052808b63ffffffff1681526020016129e18c6123aa565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401612a1c929190614589565b60806040518083038185885af1158015612a38573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190612a5d9190614649565b979650505050505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f612ac560028284866141d0565b612ace916146ae565b60f01c905060038114612af8578282604051639a6d49cd60e01b8152600401610d3992919061421d565b505050565b6001600160a01b038216612b535760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610d39565b612b5e5f8383612e21565b8060075f828254612b6f9190613588565b90915550506001600160a01b0382165f9081526005602052604081208054839290612b9b908490613588565b90915550506040518181526001600160a01b038316905f905f805160206147fd8339815191529060200160405180910390a3612bd85f83836130d4565b5050565b6001600160a01b038216612c3c5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610d39565b612c47825f83612e21565b6001600160a01b0382165f9081526005602052604090205481811015612cba5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610d39565b6001600160a01b0383165f908152600560205260408120838303905560078054849290612ce8908490613db5565b90915550506040518281525f906001600160a01b038516905f805160206147fd8339815191529060200160405180910390a3612af8835f846130d4565b5f612d3360208284866141d0565b610eb6916146de565b5f612d4b6028602084866141d0565b612d54916146fb565b60c01c9392505050565b5f610d047f00000000000000000000000000000000000000000000000000000000000000006001600160401b038416614729565b5f612d9d8484612afd565b509092915050565b6060612db482602881866141d0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929695505050505050565b606084848484604051602001612e089493929190614740565b6040516020818303038152906040529050949350505050565b5f612e2a610c37565b9050833b15158015612e4557506001600160a01b0384163014155b15612f29576001600160a01b038085165f8181526013602090815260408083209488168084529482528083208054908790558484526014835281842086855283528184208785528352818420819055601283528184209484529382528083209483529390529190912054831115612ebc575f612ef5565b5f8281526012602090815260408083206001600160a01b03808a1685529083528184209088168452909152902054612ef5908490613db5565b5f8381526012602090815260408083206001600160a01b03808b168552908352818420908916845290915290205550612fc9565b5f8181526016602090815260408083206001600160a01b0388168452909152902054821115612f58575f612f85565b5f8181526016602090815260408083206001600160a01b0388168452909152902054612f85908390613db5565b5f8281526016602090815260408083206001600160a01b03891684528252808320939093556017815282822080549085905560188252838320858452909152919020555b823b15158015612fe257506001600160a01b0383163014155b15613067576001600160a01b038084165f81815260136020908152604080832094891680845294825280832080549087905584845260148352818420868552835281842087855283528184208190556012835281842094845293825280832094835293905291822080549192859261305b908490613588565b90915550612701915050565b5f8181526016602090815260408083206001600160a01b038716845290915281208054849290613098908490613588565b90915550506001600160a01b0383165f908152601760209081526040808320805490859055601883528184208585529092529091205550505050565b5f6130dd610c37565b90506130e860075490565b5f9182526019602052604090912055505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006131288184613dc8565b610d049190614729565b5f610d047f000000000000000000000000000000000000000000000000000000000000000083613dc8565b80516060901515806131a657848460405160200161319292919091825260c01b6001600160c01b031916602082015260280190565b6040516020818303038152906040526131cd565b848433856040516020016131bd9493929190614791565b6040516020818303038152906040525b9150935093915050565b5f806131e4858585612707565b90925090506127423383612bdc565b5f8061320861320130611284565b8585612707565b90925090506132173083612bdc565b9250929050565b5f813414613241576040516304fb820960e51b8152346004820152602401610d39565b5090565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132c691906147d0565b90506001600160a01b0381166132ef576040516329b99a9560e11b815260040160405180910390fd5b612bd86001600160a01b038216337f000000000000000000000000000000000000000000000000000000000000000085612701846323b872dd60e01b85858560405160240161334093929190614257565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091525f6133c6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134439092919063ffffffff16565b805190915015612af857808060200190518101906133e49190613f4c565b612af85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d39565b606061192084845f8585843b61349b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d39565b5f80866001600160a01b031685876040516134b691906147eb565b5f6040518083038185875af1925050503d805f81146134f0576040519150601f19603f3d011682016040523d82523d5f602084013e6134f5565b606091505b5091509150612a5d8282866060831561350f575081610eb6565b82511561351f5782518084602001fd5b8160405162461bcd60e51b8152600401610d3991906135e8565b60405180604001604052805f81526020015f81525090565b604080516060810182525f808252602082015290810161356f613539565b905290565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610d0457610d04613574565b5f5b838110156135b557818101518382015260200161359d565b50505f910152565b5f81518084526135d481602086016020860161359b565b601f01601f19169290920160200192915050565b602081525f610eb660208301846135bd565b6001600160a01b0381168114612250575f80fd5b8035613619816135fa565b919050565b5f806040838503121561362f575f80fd5b823561363a816135fa565b946020939093013593505050565b5f60208284031215613658575f80fd5b8135610eb6816135fa565b5f60208284031215613673575f80fd5b5035919050565b6001600160a01b0391909116815260200190565b5f6060828403121561369e575f80fd5b50919050565b5f8083601f8401126136b4575f80fd5b5081356001600160401b038111156136ca575f80fd5b602083019150836020828501011115613217575f80fd5b5f805f805f805f60e0888a0312156136f7575f80fd5b613701898961368e565b96506060880135955060808801356001600160401b0380821115613723575f80fd5b61372f8b838c016136a4565b909750955060a08a01359150613744826135fa565b90935060c08901359080821115613759575f80fd5b506137668a828b016136a4565b989b979a50959850939692959293505050565b5f805f6060848603121561378b575f80fd5b8335613796816135fa565b925060208401356137a6816135fa565b929592945050506040919091013590565b803563ffffffff81168114613619575f80fd5b5f80604083850312156137db575f80fd5b61363a836137b7565b5f6080828403121561369e575f80fd5b8015158114612250575f80fd5b5f805f805f805f80610100898b031215613819575f80fd5b6138238a8a6137e4565b975060808901356001600160401b038082111561383e575f80fd5b61384a8c838d016136a4565b909950975060a08b0135915061385f826137f4565b90955060c08a01359080821115613874575f80fd5b6138808c838d016136a4565b909650945060e08b0135915080821115613898575f80fd5b506138a58b828c016136a4565b999c989b5096995094979396929594505050565b80518252602090810151910152565b60408101610d0482846138b9565b5f805f805f805f805f898b036101408112156138f0575f80fd5b6138fa8c8c6137e4565b995060808b01356001600160401b0380821115613915575f80fd5b6139218e838f016136a4565b909b5099508991506040609f198401121561393a575f80fd5b60a08d01985061394c60e08e0161360e565b97506101008d0135925080831115613962575f80fd5b61396e8e848f016136a4565b90975095506101208d013592508691508083111561398a575f80fd5b50506139988c828d016136a4565b915080935050809150509295985092959850929598565b825181526020808401516001600160401b03169082015260408084015160c08301916139dd908401826138b9565b50610eb660808301846138b9565b803561ffff81168114613619575f80fd5b5f8060408385031215613a0d575f80fd5b613a16836137b7565b9150613a24602084016139eb565b90509250929050565b5f8060408385031215613a3e575f80fd5b823591506020830135613a50816135fa565b809150509250929050565b5f805f60608486031215613a6d575f80fd5b833592506020840135613a7f816135fa565b91506040840135613a8f816135fa565b809150509250925092565b5f8083601f840112613aaa575f80fd5b5081356001600160401b03811115613ac0575f80fd5b6020830191508360208260051b8501011115613217575f80fd5b5f8060208385031215613aeb575f80fd5b82356001600160401b03811115613b00575f80fd5b61295685828601613a9a565b5f60208284031215613b1c575f80fd5b610eb6826137b7565b5f805f8060608587031215613b38575f80fd5b613b41856137b7565b9350613b4f602086016139eb565b925060408501356001600160401b03811115613b69575f80fd5b613b75878288016136a4565b95989497509550505050565b5f805f60a08486031215613b93575f80fd5b613b9d85856137e4565b925060808401356001600160401b03811115613bb7575f80fd5b613bc3868287016136a4565b9497909650939450505050565b5f60a08201613bdf83876138b9565b604060a0604085015281865180845260c08601915060c08160051b870101935060208089015f5b83811015613c455788870360bf19018552815180518852830151838801879052613c32878901826135bd565b9750509382019390820190600101613c06565b5050505050508091505061192060608301846138b9565b5f8060408385031215613c6d575f80fd5b8235613c78816135fa565b91506020830135613a50816135fa565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b0381118282101715613cbe57613cbe613c88565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613cec57613cec613c88565b604052919050565b5f6001600160401b03821115613d0c57613d0c613c88565b5060051b60200190565b5f6020808385031215613d27575f80fd5b82356001600160401b03811115613d3c575f80fd5b8301601f81018513613d4c575f80fd5b8035613d5f613d5a82613cf4565b613cc4565b81815260059190911b82018301908381019087831115613d7d575f80fd5b928401925b82841015612a5d57833582529284019290840190613d82565b5f60608284031215613dab575f80fd5b610eb6838361368e565b81810381811115610d0457610d04613574565b5f82613de257634e487b7160e01b5f52601260045260245ffd5b500490565b600181811c90821680613dfb57607f821691505b60208210810361369e57634e487b7160e01b5f52602260045260245ffd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b63ffffffff929092168252602082015260400190565b5f60408284031215613e74575f80fd5b613e7c613c9c565b82358152602083013560208201528091505092915050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201525f613edb606083018486613e94565b9695505050505050565b5f60208284031215613ef5575f80fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6001600160a01b03929092168252602082015260400190565b5f60208284031215613f5c575f80fd5b8151610eb6816137f4565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112613f8f575f80fd5b9190910192915050565b5f808335601e19843603018112613fae575f80fd5b8301803591506001600160401b03821115613fc7575f80fd5b602001915036819003821315613217575f80fd5b5f60208284031215613feb575f80fd5b610eb6826139eb565b601f821115612af857805f5260205f20601f840160051c810160208510156140195750805b601f840160051c820191505b81811015611e54575f8155600101614025565b6001600160401b0383111561404f5761404f613c88565b6140638361405d8354613de7565b83613ff4565b5f601f841160018114614094575f851561407d5750838201355b5f19600387901b1c1916600186901b178355611e54565b5f83815260208120601f198716915b828110156140c357868501358255602094850194600190920191016140a3565b50868210156140df575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208082528181018390525f906040808401600586901b8501820187855b888110156141c257878303603f190184528135368b9003605e19018112614134575f80fd5b8a01606063ffffffff614146836137b7565b16855261ffff6141578984016139eb565b168886015286820135601e19833603018112614171575f80fd5b9091018781019190356001600160401b0381111561418d575f80fd5b80360383131561419b575f80fd5b81888701526141ad8287018285613e94565b9689019695505050918601915060010161410f565b509098975050505050505050565b5f80858511156141de575f80fd5b838611156141ea575f80fd5b5050820193919092039150565b5f845161420881846020890161359b565b8201838582375f930192835250909392505050565b602081525f611920602083018486613e94565b6020808252600d908201526c0f1b5a5b931c9d105b5bdd5b9d609a1b604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b5f823561013e19833603018112613f8f575f80fd5b6001600160401b0381168114612250575f80fd5b63ffffffff6142b2896137b7565b168152602088013560208201525f60408901356142ce81614290565b6001600160401b031660408301526060820188905260e0608083018190526142f99083018789613e94565b6001600160a01b03861660a084015282810360c084015261431b818587613e94565b9a9950505050505050505050565b5f60208284031215614339575f80fd5b81516001600160401b038082111561434f575f80fd5b818401915084601f830112614362575f80fd5b81518181111561437457614374613c88565b614387601f8201601f1916602001613cc4565b915080825285602082850101111561439d575f80fd5b6143ae81602084016020860161359b565b50949350505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b838110156141c257888303603f19018552815180516060808652815190860181905260808601918a01905f905b808210156144345782516001600160a01b03168452928b0192918b01916001919091019061440b565b50505081890151858203868b01528051808352908a01915f91908b01905b808310156144725783518252928b019260019290920191908b0190614452565b50928901516001600160a01b03169589019590955250948701949250908601906001016143de565b5f60208083850312156144ab575f80fd5b82516001600160401b038111156144c0575f80fd5b8301601f810185136144d0575f80fd5b80516144de613d5a82613cf4565b81815260059190911b820183019083810190878311156144fc575f80fd5b928401925b82841015612a5d57835182529284019290840190614501565b5f6020828403121561452a575f80fd5b8135610eb681614290565b60018060a01b038516815283602082015261ffff83166040820152608060608201525f613edb60808301846135bd565b604081525f61457760408301856135bd565b828103602084015261292681856135bd565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a060808401526145be60e08401826135bd565b90506060850151603f198483030160a08501526145db82826135bd565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f60408284031215614611575f80fd5b614619613c9c565b9050815181526020820151602082015292915050565b5f6040828403121561463f575f80fd5b610eb68383614601565b5f60808284031215614659575f80fd5b604051606081016001600160401b038111828210171561467b5761467b613c88565b60405282518152602083015161469081614290565b60208201526146a28460408501614601565b60408201529392505050565b6001600160f01b031981358181169160028510156146d65780818660020360031b1b83161692505b505092915050565b80356020831015610d04575f19602084900360031b1b1692915050565b6001600160c01b031981358181169160088510156146d65760089490940360031b84901b1690921692915050565b8082028115828204841417610d0457610d04613574565b60c085901b6001600160c01b031916815260e084901b6001600160e01b0319166008820152600c810183905281515f9061478181602c85016020870161359b565b91909101602c0195945050505050565b84815260018060c01b03198460c01b1660208201528260288201525f82516147c081604885016020870161359b565b9190910160480195945050505050565b5f602082840312156147e0575f80fd5b8151610eb6816135fa565b5f8251613f8f81846020870161359b56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122031aecfc7680d6e699c1ad9409e6914763aede77bdf2f04cb1698f403b809653564736f6c6343000816003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000178e141a0e3b34152f73ff610437a7bf9b83267a000000000000000000000000879944a8cb437a5f8061361f82a6d4eed59070b50000000000000000000000006edce65403992e310a62460808c4b910d972f10f000000000000000000000000000000000000000000000000000000000000000e4c617965726c657373207245544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056c72455448000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106102eb575f3560e01c806306fdde0314610370578063095ea7b31461039a5780630a8ddc5e146103c95780630c8aa637146103ea578063111ecdad1461042357806313137d651461044f578063134d4f2514610462578063156a0d0f1461048957806317442b701461048957806318160ddd146104a957806318e8cb96146104bd5780631f5e1334146104dc57806323b872dd146104f0578063313ce5671461050f5780633400288b14610530578063395093511461054f57806339b70e381461056e5780633aaa607f1461058d57806346a40f75146105b857806349e46017146105e45780634e2648e31461060557806352ae2879146106245780635535d461146106365780635a0dfe4d146106555780635e280f111461067457806363bdf199146106a75780636c1efe8f146106d25780636fc1b31e146106fd57806370a082311461071c578063715018a61461073b5780637d25a05e1461074f5780638055082514610788578063813bc123146107be5780638286b4ee146107fa578063857749b0146108195780638d17437c1461082c5780638da5cb5b1461084b5780639559d3261461085f57806395d89b411461089b578063963efcaa146108af5780639b2cb5d8146108e2578063a457c2d7146108f7578063a8c62e7614610916578063a9059cbb14610935578063afeb7e2914610954578063b731ea0a1461098a578063b98bd070146109a9578063bb0b6a53146109c8578063bc70b354146109f3578063bce1b52014610a12578063bd815db014610a31578063c1e3650014610a44578063ca5eb5e114610a72578063d045a0dc14610a91578063d252d99714610aa4578063d424388514610ada578063dd62ed3e14610af9578063defe205314610b3d578063e449f34114610b5c578063e479232814610b7b578063ea4d3c9b14610bb1578063eae4c19f14610bd0578063f2fde38b14610be5578063f6fc7eb614610c04578063fc0c546a14610624578063ff7bd03d14610c18575f80fd5b3661036c5760405134815233905f907f322d0c4befd4c2dd440740b711488a1638fd7d8eeb25f9dacede84083db428c99060200160405180910390a35f610330610c37565b90503460155f8381526020019081526020015f205f8282546103529190613588565b90915550506007545f828152601960205260409020819055005b5f80fd5b34801561037b575f80fd5b50610384610c64565b60405161039191906135e8565b60405180910390f35b3480156103a5575f80fd5b506103b96103b436600461361e565b610cf4565b6040519015158152602001610391565b3480156103d4575f80fd5b506103e86103e3366004613648565b610d0a565b005b3480156103f5575f80fd5b50610415610404366004613663565b60196020525f908152604090205481565b604051908152602001610391565b34801561042e575f80fd5b50600454610442906001600160a01b031681565b604051610391919061367a565b6103e861045d3660046136e1565b610d64565b34801561046d575f80fd5b50610476600281565b60405161ffff9091168152602001610391565b348015610494575f80fd5b50604080516001808252602082015201610391565b3480156104b4575f80fd5b50600754610415565b3480156104c8575f80fd5b50600d54610442906001600160a01b031681565b3480156104e7575f80fd5b50610476600181565b3480156104fb575f80fd5b506103b961050a366004613779565b610e13565b34801561051a575f80fd5b5060125b60405160ff9091168152602001610391565b34801561053b575f80fd5b506103e861054a3660046137ca565b610ebd565b34801561055a575f80fd5b506103b961056936600461361e565b610f41565b348015610579575f80fd5b50600f54610442906001600160a01b031681565b348015610598575f80fd5b506104156105a7366004613648565b601b6020525f908152604090205481565b3480156105c3575f80fd5b506105d76105d2366004613801565b610f7c565b60405161039191906138c8565b6105f76105f23660046138d6565b610fe4565b6040516103919291906139af565b348015610610575f80fd5b5061041561061f366004613663565b6110d6565b34801561062f575f80fd5b5030610442565b348015610641575f80fd5b506103846106503660046139fc565b611142565b348015610660575f80fd5b506103b961066f3660046137ca565b6111e4565b34801561067f575f80fd5b506104427f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f81565b3480156106b2575f80fd5b506104156106c1366004613648565b60176020525f908152604090205481565b3480156106dd575f80fd5b506104156106ec366004613663565b60156020525f908152604090205481565b348015610708575f80fd5b506103e8610717366004613648565b6111ff565b348015610727575f80fd5b50610415610736366004613648565b611284565b348015610746575f80fd5b506103e861129e565b34801561075a575f80fd5b506107706107693660046137ca565b5f92915050565b6040516001600160401b039091168152602001610391565b348015610793575f80fd5b506104156107a2366004613a2d565b601660209081525f928352604080842090915290825290205481565b3480156107c9575f80fd5b506104156107d8366004613a5b565b601260209081525f938452604080852082529284528284209052825290205481565b348015610805575f80fd5b50610415610814366004613663565b6112d8565b348015610824575f80fd5b50600461051e565b348015610837575f80fd5b506103e8610846366004613648565b611309565b348015610856575f80fd5b5061044261156f565b34801561086a575f80fd5b50610415610879366004613779565b601460209081525f938452604080852082529284528284209052825290205481565b3480156108a6575f80fd5b5061038461157d565b3480156108ba575f80fd5b506104157f00000000000000000000000000000000000000000000000000005af3107a400081565b3480156108ed575f80fd5b5061041560115481565b348015610902575f80fd5b506103b961091136600461361e565b61158c565b348015610921575f80fd5b50600e54610442906001600160a01b031681565b348015610940575f80fd5b506103b961094f36600461361e565b611624565b34801561095f575f80fd5b5061041561096e36600461361e565b601860209081525f928352604080842090915290825290205481565b348015610995575f80fd5b50600254610442906001600160a01b031681565b3480156109b4575f80fd5b506103e86109c3366004613ada565b611630565b3480156109d3575f80fd5b506104156109e2366004613b0c565b60016020525f908152604090205481565b3480156109fe575f80fd5b50610384610a0d366004613b25565b6117b3565b348015610a1d575f80fd5b506103e8610a2c366004613663565b611928565b6103e8610a3f366004613ada565b611b8d565b348015610a4f575f80fd5b50610a63610a5e366004613b81565b611cf7565b60405161039193929190613bd0565b348015610a7d575f80fd5b506103e8610a8c366004613648565b611db0565b6103e8610a9f3660046136e1565b611e5b565b348015610aaf575f80fd5b50610415610abe366004613c5c565b601360209081525f928352604080842090915290825290205481565b348015610ae5575f80fd5b506103e8610af4366004613648565b611e8a565b348015610b04575f80fd5b50610415610b13366004613c5c565b6001600160a01b039182165f90815260066020908152604080832093909416825291909152205490565b348015610b48575f80fd5b50600c54610442906001600160a01b031681565b348015610b67575f80fd5b506103e8610b76366004613d16565b611f04565b348015610b86575f80fd5b50610415610b9536600461361e565b601a60209081525f928352604080842090915290825290205481565b348015610bbc575f80fd5b50601054610442906001600160a01b031681565b348015610bdb575f80fd5b50610415600b5481565b348015610bf0575f80fd5b506103e8610bff366004613648565b6121b3565b348015610c0f575f80fd5b50610415610c37565b348015610c23575f80fd5b506103b9610c32366004613d9b565b612253565b5f62015180600b5442610c4a9190613db5565b610c549190613dc8565b610c5f906001613588565b905090565b606060088054610c7390613de7565b80601f0160208091040260200160405190810160405280929190818152602001828054610c9f90613de7565b8015610cea5780601f10610cc157610100808354040283529160200191610cea565b820191905f5260205f20905b815481529060010190602001808311610ccd57829003601f168201915b5050505050905090565b5f610d00338484612287565b5060015b92915050565b33610d1361156f565b6001600160a01b031614610d425760405162461bcd60e51b8152600401610d3990613e19565b60405180910390fd5b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b7f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b03163314610daf57336040516391ac5e4f60e01b8152600401610d39919061367a565b60208701803590610dc990610dc4908a613b0c565b6123aa565b14610dfb57610ddb6020880188613b0c565b876020013560405163309afaf360e21b8152600401610d39929190613e4e565b610e0a878787878787876123e5565b50505050505050565b5f610e1f848484612537565b6001600160a01b0384165f90815260066020908152604080832033845290915290205482811015610ea35760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b6064820152608401610d39565b610eb08533858403612287565b60019150505b9392505050565b33610ec661156f565b6001600160a01b031614610eec5760405162461bcd60e51b8152600401610d3990613e19565b63ffffffff82165f9081526001602052604090819020829055517f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b90610f359084908490613e4e565b60405180910390a15050565b335f8181526006602090815260408083206001600160a01b03871684529091528120549091610d00918590610f77908690613588565b612287565b610f84613539565b5f610fa460408b013560608c0135610f9f60208e018e613b0c565b612707565b9150505f80610fb78c8c8c8b8b8861274a565b9092509050610fd4610fcc60208e018e613b0c565b83838c61285c565b9c9b505050505050505050505050565b610fec613551565b610ff4613539565b5f8061101a8d604001358e606001358f5f0160208101906110159190613b0c565b61292f565b915091505f8061102e8f8f8f8d8d8861274a565b915091506110608f5f0160208101906110479190613b0c565b83838f80360381019061105a9190613e64565b8f612962565b95506040518060400160405280858152602001848152509450336001600160a01b0316865f01517fee6b77e8cd280835aecc97812d736c35faad222d91b12de19c7ed912e9aed71b86868e8e6040516110bc9493929190613ebc565b60405180910390a350505050995099975050505050505050565b600e54604051637a8b263760e01b8152600481018390525f916001600160a01b031690637a8b2637906024015b602060405180830381865afa15801561111e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d049190613ee5565b600360209081525f92835260408084209091529082529020805461116590613de7565b80601f016020809104026020016040519081016040528092919081815260200182805461119190613de7565b80156111dc5780601f106111b3576101008083540402835291602001916111dc565b820191905f5260205f20905b8154815290600101906020018083116111bf57829003601f168201915b505050505081565b63ffffffff919091165f908152600160205260409020541490565b3361120861156f565b6001600160a01b03161461122e5760405162461bcd60e51b8152600401610d3990613e19565b600480546001600160a01b0319166001600160a01b0383161790556040517ff0be4f1e87349231d80c36b33f9e8639658eeaf474014dee15a3e6a4d44141979061127990839061367a565b60405180910390a150565b6001600160a01b03165f9081526005602052604090205490565b336112a761156f565b6001600160a01b0316146112cd5760405162461bcd60e51b8152600401610d3990613e19565b6112d65f612a68565b565b600e546040516338f6b94760e21b8152600481018390525f916001600160a01b03169063e3dae51c90602401611103565b3361131261156f565b6001600160a01b0316146113385760405162461bcd60e51b8152600401610d3990613e19565b6002600a540361135a5760405162461bcd60e51b8152600401610d3990613efc565b6002600a55600c546001600160a01b03166113a95760405162461bcd60e51b815260206004820152600f60248201526e10b932bbb0b93239a6b0b730b3b2b960891b6044820152606401610d39565b6001600160a01b03811661144857600c546040515f916001600160a01b03169047908381818185875af1925050503d805f8114611401576040519150601f19603f3d011682016040523d82523d5f602084013e611406565b606091505b50509050806114425760405162461bcd60e51b8152602060048201526008602482015267217375636365737360c01b6044820152606401610d39565b50611567565b6040516370a0823160e01b815281905f906001600160a01b038316906370a082319061147890309060040161367a565b602060405180830381865afa158015611493573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b79190613ee5565b600c5460405163a9059cbb60e01b81529192506001600160a01b038085169263a9059cbb926114ec9216908590600401613f33565b6020604051808303815f875af1158015611508573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061152c9190613f4c565b6115645760405162461bcd60e51b815260206004820152600960248201526810ba3930b739b332b960b91b6044820152606401610d39565b50505b506001600a55565b5f546001600160a01b031690565b606060098054610c7390613de7565b335f9081526006602090815260408083206001600160a01b03861684529091528120548281101561160d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610d39565b61161a3385858403612287565b5060019392505050565b5f610d00338484612537565b3361163961156f565b6001600160a01b03161461165f5760405162461bcd60e51b8152600401610d3990613e19565b5f5b81811015611781576116a383838381811061167e5761167e613f67565b90506020028101906116909190613f7b565b61169e906040810190613f99565b612ab7565b8282828181106116b5576116b5613f67565b90506020028101906116c79190613f7b565b6116d5906040810190613f99565b60035f8686868181106116ea576116ea613f67565b90506020028101906116fc9190613f7b565b61170a906020810190613b0c565b63ffffffff1663ffffffff1681526020019081526020015f205f86868681811061173657611736613f67565b90506020028101906117489190613f7b565b611759906040810190602001613fdb565b61ffff16815260208101919091526040015f2091611778919083614038565b50600101611661565b507fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b6748282604051610f359291906140f1565b63ffffffff84165f90815260036020908152604080832061ffff871684529091528120805460609291906117e690613de7565b80601f016020809104026020016040519081016040528092919081815260200182805461181290613de7565b801561185d5780601f106118345761010080835404028352916020019161185d565b820191905f5260205f20905b81548152906001019060200180831161184057829003601f168201915b5050505050905080515f036118ab5783838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152509294506119209350505050565b5f8390036118ba579050611920565b60028310611903576118cc8484612ab7565b806118da84600281886141d0565b6040516020016118ec939291906141f7565b604051602081830303815290604052915050611920565b8383604051639a6d49cd60e01b8152600401610d3992919061421d565b949350505050565b6002600a540361194a5760405162461bcd60e51b8152600401610d3990613efc565b6002600a556011548110156119715760405162461bcd60e51b8152600401610d3990614230565b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd906119a590339030908690600401614257565b6020604051808303815f875af11580156119c1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119e59190613f4c565b611a215760405162461bcd60e51b815260206004820152600d60248201526c217472616e7366657246726f6d60981b6044820152606401610d39565b600d54600f5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611a57929116908590600401613f33565b6020604051808303815f875af1158015611a73573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a979190613f4c565b50600f54600e54600d546040516373d0285560e11b81525f936001600160a01b039081169363e7a050aa93611ad6939183169216908790600401614257565b6020604051808303815f875af1158015611af2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b169190613ee5565b335f908152601b6020526040812080549293508392909190611b39908490613588565b90915550611b4990503382612afd565b604080518381526020810183905233917fa217c421e0e9357b7b1815d752952b142ddc0e23f9f14ecb8233f8f83d563c4d910160405180910390a250506001600a55565b5f5b81811015611c7a5736838383818110611baa57611baa613f67565b9050602002810190611bbc919061427b565b9050611bd8611bce6020830183613b0c565b60208301356111e4565b611be25750611c72565b3063d045a0dc60c08301358360a0810135611c01610100830183613f99565b611c12610100890160e08a01613648565b611c206101208a018a613f99565b6040518963ffffffff1660e01b8152600401611c4297969594939291906142a4565b5f604051808303818588803b158015611c59575f80fd5b505af1158015611c6b573d5f803e3d5ffd5b5050505050505b600101611b8f565b50336001600160a01b0316638e9e70996040518163ffffffff1660e01b81526004015f60405180830381865afa158015611cb6573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611cdd9190810190614329565b604051638351eea760e01b8152600401610d3991906135e8565b604080518082019091525f80825260208201526060611d14613539565b6040805180820182525f8082526001600160401b03602080840182905284518381529081019094529195509182611d6d565b604080518082019091525f815260606020820152815260200190600190039081611d465790505b5093505f80611d8c60408b013560608c0135610f9f60208e018e613b0c565b604080518082019091529182526020820152969a9599509597509395505050505050565b33611db961156f565b6001600160a01b031614611ddf5760405162461bcd60e51b8152600401610d3990613e19565b60405163ca5eb5e160e01b81526001600160a01b037f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f169063ca5eb5e190611e2b90849060040161367a565b5f604051808303815f87803b158015611e42575f80fd5b505af1158015611e54573d5f803e3d5ffd5b5050505050565b333014611e7b5760405163029a949d60e31b815260040160405180910390fd5b610e0a87878787878787610dfb565b33611e9361156f565b6001600160a01b031614611eb95760405162461bcd60e51b8152600401610d3990613e19565b600280546001600160a01b0319166001600160a01b0383161790556040517fd48d879cef83a1c0bdda516f27b13ddb1b3f8bbac1c9e1511bb2a659c24277609061127990839061367a565b6002600a5403611f265760405162461bcd60e51b8152600401610d3990613efc565b6002600a558051600114611f7c5760405162461bcd60e51b815260206004820152601d60248201527f4f6e6c79206f6e65207769746864726177616c20617420612074696d650000006044820152606401610d39565b5f815f81518110611f8f57611f8f613f67565b60200260200101519050601154811015611fbb5760405162461bcd60e51b8152600401610d3990614230565b80611fc533611284565b10156120005760405162461bcd60e51b815260206004820152600a6024820152691e3130b630b731b2a7b360b11b6044820152606401610d39565b6040805160018082528183019092525f91816020015b604080516060808201835280825260208201525f918101919091528152602001906001900390816120165750506040805160018082528183019092529192505f9190602080830190803683375050600e5482519293506001600160a01b0316918391505f9061208757612087613f67565b6001600160a01b03909216602092830291909101820152604080516060810182528381529182018690523390820152825183905f906120c8576120c8613f67565b60209081029190910101526010546040516306ec6e8160e11b81526001600160a01b0390911690630dd8dd02906121039085906004016143b7565b5f604051808303815f875af115801561211e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612145919081019061449a565b506121503384612bdc565b335f908152601b60205260408120805485929061216e908490613db5565b909155505060405183815233907f0f5bb82176feb1b5e747e28471aa92156a04d9f3ab9f45f28e2d704232b93f759060200160405180910390a250506001600a555050565b336121bc61156f565b6001600160a01b0316146121e25760405162461bcd60e51b8152600401610d3990613e19565b6001600160a01b0381166122475760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610d39565b61225081612a68565b50565b5f60208201803590600190839061226a9086613b0c565b63ffffffff16815260208101919091526040015f20541492915050565b6001600160a01b0383166122e95760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610d39565b6001600160a01b03821661234a5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610d39565b6001600160a01b038381165f8181526006602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b63ffffffff81165f9081526001602052604081205480610d045760405163f6ff4fb760e01b815263ffffffff84166004820152602401610d39565b5f6123f66123f38787612d25565b90565b90505f61240b6124068888612d3c565b612d5e565b90505f612425838361242060208e018e613b0c565b612d92565b905060288711156124e5575f61246161244460608d0160408e0161451a565b61245160208e018e613b0c565b8461245c8d8d612da5565b612def565b604051633e5ac80960e11b81529091506001600160a01b037f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f1690637cb59012906124b69087908e905f908790600401614535565b5f604051808303815f87803b1580156124cd575f80fd5b505af11580156124df573d5f803e3d5ffd5b50505050505b60408051838152602081018390526001600160a01b038516918b917f80a66cf84dc0b742c17c4672ee6687d7cb340ab0e5d367ac6b02bed1a6489f8d910160405180910390a350505050505050505050565b6001600160a01b03831661259b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610d39565b6001600160a01b0382166125fd5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610d39565b612608838383612e21565b6001600160a01b0383165f908152600560205260409020548181101561267f5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610d39565b6001600160a01b038085165f908152600560205260408082208585039055918516815290812080548492906126b5908490613588565b92505081905550826001600160a01b0316846001600160a01b03165f805160206147fd833981519152846040516126ee91815260200190565b60405180910390a36127018484846130d4565b50505050565b5f80612712856130fc565b915081905083811015612742576040516371c4efed60e01b81526004810182905260248101859052604401610d39565b935093915050565b6060805f61279a896020013561275f86613132565b88888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061315d92505050565b90935090505f816127ac5760016127af565b60025b90506127c96127c160208c018c613b0c565b828b8b6117b3565b6004549093506001600160a01b03161561284f576004805460405163043a78eb60e01b81526001600160a01b039091169163043a78eb9161280e918891889101614565565b602060405180830381865afa158015612829573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061284d9190613f4c565b505b5050965096945050505050565b612864613539565b7f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b031663ddc28c586040518060a001604052808863ffffffff1681526020016128b3896123aa565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b81526004016128e8929190614589565b6040805180830381865afa158015612902573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612926919061462f565b95945050505050565b5f80841561294c576129428585856131d7565b9092509050612742565b61295684846131f3565b90969095509350505050565b61296a613551565b5f612977845f015161321e565b602085015190915015612991576129918460200151613245565b7f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b0316632637a450826040518060a001604052808b63ffffffff1681526020016129e18c6123aa565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401612a1c929190614589565b60806040518083038185885af1158015612a38573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190612a5d9190614649565b979650505050505050565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f612ac560028284866141d0565b612ace916146ae565b60f01c905060038114612af8578282604051639a6d49cd60e01b8152600401610d3992919061421d565b505050565b6001600160a01b038216612b535760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610d39565b612b5e5f8383612e21565b8060075f828254612b6f9190613588565b90915550506001600160a01b0382165f9081526005602052604081208054839290612b9b908490613588565b90915550506040518181526001600160a01b038316905f905f805160206147fd8339815191529060200160405180910390a3612bd85f83836130d4565b5050565b6001600160a01b038216612c3c5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610d39565b612c47825f83612e21565b6001600160a01b0382165f9081526005602052604090205481811015612cba5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610d39565b6001600160a01b0383165f908152600560205260408120838303905560078054849290612ce8908490613db5565b90915550506040518281525f906001600160a01b038516905f805160206147fd8339815191529060200160405180910390a3612af8835f846130d4565b5f612d3360208284866141d0565b610eb6916146de565b5f612d4b6028602084866141d0565b612d54916146fb565b60c01c9392505050565b5f610d047f00000000000000000000000000000000000000000000000000005af3107a40006001600160401b038416614729565b5f612d9d8484612afd565b509092915050565b6060612db482602881866141d0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250929695505050505050565b606084848484604051602001612e089493929190614740565b6040516020818303038152906040529050949350505050565b5f612e2a610c37565b9050833b15158015612e4557506001600160a01b0384163014155b15612f29576001600160a01b038085165f8181526013602090815260408083209488168084529482528083208054908790558484526014835281842086855283528184208785528352818420819055601283528184209484529382528083209483529390529190912054831115612ebc575f612ef5565b5f8281526012602090815260408083206001600160a01b03808a1685529083528184209088168452909152902054612ef5908490613db5565b5f8381526012602090815260408083206001600160a01b03808b168552908352818420908916845290915290205550612fc9565b5f8181526016602090815260408083206001600160a01b0388168452909152902054821115612f58575f612f85565b5f8181526016602090815260408083206001600160a01b0388168452909152902054612f85908390613db5565b5f8281526016602090815260408083206001600160a01b03891684528252808320939093556017815282822080549085905560188252838320858452909152919020555b823b15158015612fe257506001600160a01b0383163014155b15613067576001600160a01b038084165f81815260136020908152604080832094891680845294825280832080549087905584845260148352818420868552835281842087855283528184208190556012835281842094845293825280832094835293905291822080549192859261305b908490613588565b90915550612701915050565b5f8181526016602090815260408083206001600160a01b038716845290915281208054849290613098908490613588565b90915550506001600160a01b0383165f908152601760209081526040808320805490859055601883528184208585529092529091205550505050565b5f6130dd610c37565b90506130e860075490565b5f9182526019602052604090912055505050565b5f7f00000000000000000000000000000000000000000000000000005af3107a40006131288184613dc8565b610d049190614729565b5f610d047f00000000000000000000000000000000000000000000000000005af3107a400083613dc8565b80516060901515806131a657848460405160200161319292919091825260c01b6001600160c01b031916602082015260280190565b6040516020818303038152906040526131cd565b848433856040516020016131bd9493929190614791565b6040516020818303038152906040525b9150935093915050565b5f806131e4858585612707565b90925090506127423383612bdc565b5f8061320861320130611284565b8585612707565b90925090506132173083612bdc565b9250929050565b5f813414613241576040516304fb820960e51b8152346004820152602401610d39565b5090565b5f7f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f6001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132c691906147d0565b90506001600160a01b0381166132ef576040516329b99a9560e11b815260040160405180910390fd5b612bd86001600160a01b038216337f0000000000000000000000006edce65403992e310a62460808c4b910d972f10f85612701846323b872dd60e01b85858560405160240161334093929190614257565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091525f6133c6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134439092919063ffffffff16565b805190915015612af857808060200190518101906133e49190613f4c565b612af85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610d39565b606061192084845f8585843b61349b5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d39565b5f80866001600160a01b031685876040516134b691906147eb565b5f6040518083038185875af1925050503d805f81146134f0576040519150601f19603f3d011682016040523d82523d5f602084013e6134f5565b606091505b5091509150612a5d8282866060831561350f575081610eb6565b82511561351f5782518084602001fd5b8160405162461bcd60e51b8152600401610d3991906135e8565b60405180604001604052805f81526020015f81525090565b604080516060810182525f808252602082015290810161356f613539565b905290565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610d0457610d04613574565b5f5b838110156135b557818101518382015260200161359d565b50505f910152565b5f81518084526135d481602086016020860161359b565b601f01601f19169290920160200192915050565b602081525f610eb660208301846135bd565b6001600160a01b0381168114612250575f80fd5b8035613619816135fa565b919050565b5f806040838503121561362f575f80fd5b823561363a816135fa565b946020939093013593505050565b5f60208284031215613658575f80fd5b8135610eb6816135fa565b5f60208284031215613673575f80fd5b5035919050565b6001600160a01b0391909116815260200190565b5f6060828403121561369e575f80fd5b50919050565b5f8083601f8401126136b4575f80fd5b5081356001600160401b038111156136ca575f80fd5b602083019150836020828501011115613217575f80fd5b5f805f805f805f60e0888a0312156136f7575f80fd5b613701898961368e565b96506060880135955060808801356001600160401b0380821115613723575f80fd5b61372f8b838c016136a4565b909750955060a08a01359150613744826135fa565b90935060c08901359080821115613759575f80fd5b506137668a828b016136a4565b989b979a50959850939692959293505050565b5f805f6060848603121561378b575f80fd5b8335613796816135fa565b925060208401356137a6816135fa565b929592945050506040919091013590565b803563ffffffff81168114613619575f80fd5b5f80604083850312156137db575f80fd5b61363a836137b7565b5f6080828403121561369e575f80fd5b8015158114612250575f80fd5b5f805f805f805f80610100898b031215613819575f80fd5b6138238a8a6137e4565b975060808901356001600160401b038082111561383e575f80fd5b61384a8c838d016136a4565b909950975060a08b0135915061385f826137f4565b90955060c08a01359080821115613874575f80fd5b6138808c838d016136a4565b909650945060e08b0135915080821115613898575f80fd5b506138a58b828c016136a4565b999c989b5096995094979396929594505050565b80518252602090810151910152565b60408101610d0482846138b9565b5f805f805f805f805f898b036101408112156138f0575f80fd5b6138fa8c8c6137e4565b995060808b01356001600160401b0380821115613915575f80fd5b6139218e838f016136a4565b909b5099508991506040609f198401121561393a575f80fd5b60a08d01985061394c60e08e0161360e565b97506101008d0135925080831115613962575f80fd5b61396e8e848f016136a4565b90975095506101208d013592508691508083111561398a575f80fd5b50506139988c828d016136a4565b915080935050809150509295985092959850929598565b825181526020808401516001600160401b03169082015260408084015160c08301916139dd908401826138b9565b50610eb660808301846138b9565b803561ffff81168114613619575f80fd5b5f8060408385031215613a0d575f80fd5b613a16836137b7565b9150613a24602084016139eb565b90509250929050565b5f8060408385031215613a3e575f80fd5b823591506020830135613a50816135fa565b809150509250929050565b5f805f60608486031215613a6d575f80fd5b833592506020840135613a7f816135fa565b91506040840135613a8f816135fa565b809150509250925092565b5f8083601f840112613aaa575f80fd5b5081356001600160401b03811115613ac0575f80fd5b6020830191508360208260051b8501011115613217575f80fd5b5f8060208385031215613aeb575f80fd5b82356001600160401b03811115613b00575f80fd5b61295685828601613a9a565b5f60208284031215613b1c575f80fd5b610eb6826137b7565b5f805f8060608587031215613b38575f80fd5b613b41856137b7565b9350613b4f602086016139eb565b925060408501356001600160401b03811115613b69575f80fd5b613b75878288016136a4565b95989497509550505050565b5f805f60a08486031215613b93575f80fd5b613b9d85856137e4565b925060808401356001600160401b03811115613bb7575f80fd5b613bc3868287016136a4565b9497909650939450505050565b5f60a08201613bdf83876138b9565b604060a0604085015281865180845260c08601915060c08160051b870101935060208089015f5b83811015613c455788870360bf19018552815180518852830151838801879052613c32878901826135bd565b9750509382019390820190600101613c06565b5050505050508091505061192060608301846138b9565b5f8060408385031215613c6d575f80fd5b8235613c78816135fa565b91506020830135613a50816135fa565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b0381118282101715613cbe57613cbe613c88565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613cec57613cec613c88565b604052919050565b5f6001600160401b03821115613d0c57613d0c613c88565b5060051b60200190565b5f6020808385031215613d27575f80fd5b82356001600160401b03811115613d3c575f80fd5b8301601f81018513613d4c575f80fd5b8035613d5f613d5a82613cf4565b613cc4565b81815260059190911b82018301908381019087831115613d7d575f80fd5b928401925b82841015612a5d57833582529284019290840190613d82565b5f60608284031215613dab575f80fd5b610eb6838361368e565b81810381811115610d0457610d04613574565b5f82613de257634e487b7160e01b5f52601260045260245ffd5b500490565b600181811c90821680613dfb57607f821691505b60208210810361369e57634e487b7160e01b5f52602260045260245ffd5b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b63ffffffff929092168252602082015260400190565b5f60408284031215613e74575f80fd5b613e7c613c9c565b82358152602083013560208201528091505092915050565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b848152836020820152606060408201525f613edb606083018486613e94565b9695505050505050565b5f60208284031215613ef5575f80fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6001600160a01b03929092168252602082015260400190565b5f60208284031215613f5c575f80fd5b8151610eb6816137f4565b634e487b7160e01b5f52603260045260245ffd5b5f8235605e19833603018112613f8f575f80fd5b9190910192915050565b5f808335601e19843603018112613fae575f80fd5b8301803591506001600160401b03821115613fc7575f80fd5b602001915036819003821315613217575f80fd5b5f60208284031215613feb575f80fd5b610eb6826139eb565b601f821115612af857805f5260205f20601f840160051c810160208510156140195750805b601f840160051c820191505b81811015611e54575f8155600101614025565b6001600160401b0383111561404f5761404f613c88565b6140638361405d8354613de7565b83613ff4565b5f601f841160018114614094575f851561407d5750838201355b5f19600387901b1c1916600186901b178355611e54565b5f83815260208120601f198716915b828110156140c357868501358255602094850194600190920191016140a3565b50868210156140df575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208082528181018390525f906040808401600586901b8501820187855b888110156141c257878303603f190184528135368b9003605e19018112614134575f80fd5b8a01606063ffffffff614146836137b7565b16855261ffff6141578984016139eb565b168886015286820135601e19833603018112614171575f80fd5b9091018781019190356001600160401b0381111561418d575f80fd5b80360383131561419b575f80fd5b81888701526141ad8287018285613e94565b9689019695505050918601915060010161410f565b509098975050505050505050565b5f80858511156141de575f80fd5b838611156141ea575f80fd5b5050820193919092039150565b5f845161420881846020890161359b565b8201838582375f930192835250909392505050565b602081525f611920602083018486613e94565b6020808252600d908201526c0f1b5a5b931c9d105b5bdd5b9d609a1b604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b5f823561013e19833603018112613f8f575f80fd5b6001600160401b0381168114612250575f80fd5b63ffffffff6142b2896137b7565b168152602088013560208201525f60408901356142ce81614290565b6001600160401b031660408301526060820188905260e0608083018190526142f99083018789613e94565b6001600160a01b03861660a084015282810360c084015261431b818587613e94565b9a9950505050505050505050565b5f60208284031215614339575f80fd5b81516001600160401b038082111561434f575f80fd5b818401915084601f830112614362575f80fd5b81518181111561437457614374613c88565b614387601f8201601f1916602001613cc4565b915080825285602082850101111561439d575f80fd5b6143ae81602084016020860161359b565b50949350505050565b5f60208083018184528085518083526040925060408601915060408160051b8701018488015f5b838110156141c257888303603f19018552815180516060808652815190860181905260808601918a01905f905b808210156144345782516001600160a01b03168452928b0192918b01916001919091019061440b565b50505081890151858203868b01528051808352908a01915f91908b01905b808310156144725783518252928b019260019290920191908b0190614452565b50928901516001600160a01b03169589019590955250948701949250908601906001016143de565b5f60208083850312156144ab575f80fd5b82516001600160401b038111156144c0575f80fd5b8301601f810185136144d0575f80fd5b80516144de613d5a82613cf4565b81815260059190911b820183019083810190878311156144fc575f80fd5b928401925b82841015612a5d57835182529284019290840190614501565b5f6020828403121561452a575f80fd5b8135610eb681614290565b60018060a01b038516815283602082015261ffff83166040820152608060608201525f613edb60808301846135bd565b604081525f61457760408301856135bd565b828103602084015261292681856135bd565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a060808401526145be60e08401826135bd565b90506060850151603f198483030160a08501526145db82826135bd565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f60408284031215614611575f80fd5b614619613c9c565b9050815181526020820151602082015292915050565b5f6040828403121561463f575f80fd5b610eb68383614601565b5f60808284031215614659575f80fd5b604051606081016001600160401b038111828210171561467b5761467b613c88565b60405282518152602083015161469081614290565b60208201526146a28460408501614601565b60408201529392505050565b6001600160f01b031981358181169160028510156146d65780818660020360031b1b83161692505b505092915050565b80356020831015610d04575f19602084900360031b1b1692915050565b6001600160c01b031981358181169160088510156146d65760089490940360031b84901b1690921692915050565b8082028115828204841417610d0457610d04613574565b60c085901b6001600160c01b031916815260e084901b6001600160e01b0319166008820152600c810183905281515f9061478181602c85016020870161359b565b91909101602c0195945050505050565b84815260018060c01b03198460c01b1660208201528260288201525f82516147c081604885016020870161359b565b9190910160480195945050505050565b5f602082840312156147e0575f80fd5b8151610eb6816135fa565b5f8251613f8f81846020870161359b56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122031aecfc7680d6e699c1ad9409e6914763aede77bdf2f04cb1698f403b809653564736f6c63430008160033

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

00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000178e141a0e3b34152f73ff610437a7bf9b83267a000000000000000000000000879944a8cb437a5f8061361f82a6d4eed59070b50000000000000000000000006edce65403992e310a62460808c4b910d972f10f000000000000000000000000000000000000000000000000000000000000000e4c617965726c657373207245544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056c72455448000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): Layerless rETH
Arg [1] : _symbol (string): lrETH
Arg [2] : _lst (address): 0x178E141a0E3b34152f73Ff610437A7bf9B83267A
Arg [3] : _strategy (address): 0x879944A8cB437a5f8061361f82A6d4EED59070b5
Arg [4] : _lzEndpoint (address): 0x6EDCE65403992e310A62460808c4b910D972f10f

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 000000000000000000000000178e141a0e3b34152f73ff610437a7bf9b83267a
Arg [3] : 000000000000000000000000879944a8cb437a5f8061361f82a6d4eed59070b5
Arg [4] : 0000000000000000000000006edce65403992e310a62460808c4b910d972f10f
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [6] : 4c617965726c6573732072455448000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [8] : 6c72455448000000000000000000000000000000000000000000000000000000


[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.