FTM Price: $0.696099 (+1.08%)
 

Overview

FTM Balance

Fantom LogoFantom LogoFantom Logo0 FTM

FTM Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute940510142024-10-09 3:09:381 min ago1728443378IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0039397425.38496933
Execute940509782024-10-09 3:09:101 min ago1728443350IN
0xD56e4eAb...27b9aC7cc
0 FTM0.003939225.38148991
Execute940507862024-10-09 3:06:553 mins ago1728443215IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040237625.92633997
Execute940506232024-10-09 3:04:595 mins ago1728443099IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040226625.91920465
Execute940506212024-10-09 3:04:575 mins ago1728443097IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040226225.91897611
Execute940504662024-10-09 3:02:537 mins ago1728442973IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040228125.92390228
Execute940504652024-10-09 3:02:527 mins ago1728442972IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040231625.92430856
Execute940500232024-10-09 2:57:1413 mins ago1728442634IN
0xD56e4eAb...27b9aC7cc
0 FTM0.004076826.26993437
Execute940495752024-10-09 2:51:5718 mins ago1728442317IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040839426.31407384
Execute940494542024-10-09 2:50:3120 mins ago1728442231IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040806326.29273762
Execute940494362024-10-09 2:50:1920 mins ago1728442219IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0040801126.28939177
Execute940490222024-10-09 2:45:3525 mins ago1728441935IN
0xD56e4eAb...27b9aC7cc
0 FTM0.004214327.15784943
Execute940490192024-10-09 2:45:3325 mins ago1728441933IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0042148927.15784943
Execute940479882024-10-09 2:33:3237 mins ago1728441212IN
0xD56e4eAb...27b9aC7cc
0 FTM0.004288127.63344245
Execute940477962024-10-09 2:31:1839 mins ago1728441078IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0042843627.60542798
Execute940477412024-10-09 2:30:4140 mins ago1728441041IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0043947828.31891734
Execute940459442024-10-09 2:07:561 hr ago1728439676IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0047932530.88435087
Execute940455282024-10-09 2:02:111 hr ago1728439331IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0048950231.5400964
Execute940453892024-10-09 2:00:111 hr ago1728439211IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0048981831.5604387
Withdraw Fee Fro...940453762024-10-09 2:00:011 hr ago1728439201IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0017123431.56453798
Execute940453602024-10-09 1:59:461 hr ago1728439186IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0048983731.56167157
Execute940451202024-10-09 1:56:231 hr ago1728438983IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0049022931.5914453
Execute940442662024-10-09 1:44:141 hr ago1728438254IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0049864132.12896816
Execute940440022024-10-09 1:40:591 hr ago1728438059IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0050004132.22145337
Execute940438282024-10-09 1:38:441 hr ago1728437924IN
0xD56e4eAb...27b9aC7cc
0 FTM0.0050191332.34205359
View all transactions

Latest 1 internal transaction

Parent Transaction Hash Block From To
679942342023-09-09 0:23:23396 days ago1694219003  Contract Creation0 FTM
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VerifierNetwork

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 20000 runs

Other Settings:
default evmVersion, BSL 1.1 license
File 1 of 31 : VerifierNetwork.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.19;

import "@layerzerolabs/lz-evm-v1-0.8/contracts/interfaces/ILayerZeroUltraLightNodeV2.sol";

import "../Worker.sol";
import "./MultiSig.sol";
import "./interfaces/IVerifier.sol";
import "./interfaces/IVerifierFeeLib.sol";
import "./interfaces/IUltraLightNode.sol";
import {DeliveryState} from "../MessageLibBase.sol";

struct ExecuteParam {
    uint32 vid;
    address target;
    bytes callData;
    uint expiration;
    bytes signatures;
}

contract VerifierNetwork is Worker, MultiSig, IVerifier {
    // to uniquely identify this VerifierNetwork instance
    // set to endpoint v1 eid if available OR endpoint v2 eid % 30_000
    uint32 public immutable vid;

    mapping(uint32 dstEid => DstConfig) public dstConfig;
    mapping(bytes32 executableHash => bool used) public usedHashes;

    event VerifySignaturesFailed(uint idx);
    event ExecuteFailed(uint _index, bytes _data);
    event HashAlreadyUsed(ExecuteParam param, bytes32 _hash);
    event VerifierFeePaid(uint fee);

    // ========================= Constructor =========================

    /// @dev VerifierNetwork doesn't have a roleAdmin (address(0x0))
    /// @dev Supports all of ULNv2, ULN301, ULN302 and more
    /// @param _messageLibs array of message lib addresses that are granted the MESSAGE_LIB_ROLE
    /// @param _priceFeed price feed address
    /// @param _signers array of signer addresses for multisig
    /// @param _quorum quorum for multisig
    /// @param _admins array of admin addresses that are granted the ADMIN_ROLE
    constructor(
        uint32 _vid,
        address[] memory _messageLibs,
        address _priceFeed,
        address[] memory _signers,
        uint64 _quorum,
        address[] memory _admins
    ) Worker(_messageLibs, _priceFeed, 12000, address(0x0), _admins) MultiSig(_signers, _quorum) {
        vid = _vid;
    }

    // ========================= Modifier =========================

    /// @dev depending on role, restrict access to only self or admin
    /// @dev ALLOWLIST, DENYLIST, MESSAGE_LIB_ROLE can only be granted/revoked by self
    /// @dev ADMIN_ROLE can only be granted/revoked by admin
    /// @dev reverts if not one of the above roles
    /// @param _role role to check
    modifier onlySelfOrAdmin(bytes32 _role) {
        if (_role == ALLOWLIST || _role == DENYLIST || _role == MESSAGE_LIB_ROLE) {
            // self required
            require(address(this) == msg.sender, "Verifier: caller must be self");
        } else if (_role == ADMIN_ROLE) {
            // admin required
            _checkRole(ADMIN_ROLE);
        } else {
            revert("Verifier: invalid role");
        }
        _;
    }

    modifier onlySelf() {
        require(address(this) == msg.sender, "Verifier: caller must be self");
        _;
    }

    // ========================= OnlySelf =========================

    /// @dev set signers for multisig
    /// @dev function sig 0x31cb6105
    /// @param _signer signer address
    /// @param _active true to add, false to remove
    function setSigner(address _signer, bool _active) external onlySelf {
        _setSigner(_signer, _active);
    }

    /// @dev set quorum for multisig
    /// @dev function sig 0x8585c945
    /// @param _quorum to set
    function setQuorum(uint64 _quorum) external onlySelf {
        _setQuorum(_quorum);
    }

    /// @dev one function to verify and deliver to ULN302 and more (does not support ULN301)
    /// @dev if last verifier, can use this function to save overhead gas on deliver
    /// @dev function sig 0xb724b133
    /// @param _uln IUltraLightNode compatible contract
    /// @param _packetHeader packet header
    /// @param _payloadHash payload hash
    /// @param _confirmations block confirmations
    function verifyAndDeliver(
        IUltraLightNode _uln,
        bytes calldata _packetHeader,
        bytes32 _payloadHash,
        uint64 _confirmations
    ) external onlySelf {
        require(hasRole(MESSAGE_LIB_ROLE, address(_uln)), "Verifier: invalid uln");
        _uln.verify(_packetHeader, _payloadHash, _confirmations);
        // if deliverable, deliver. else, skip or it will revert in uln
        if (_uln.deliverable(_packetHeader, _payloadHash) == DeliveryState.Deliverable) {
            _uln.deliver(_packetHeader, _payloadHash);
        }
    }

    // ========================= OnlySelf / OnlyAdmin =========================

    /// @dev overrides AccessControl to allow self/admin to grant role'
    /// @dev function sig 0x2f2ff15d
    /// @param _role role to grant
    /// @param _account account to grant role to
    function grantRole(bytes32 _role, address _account) public override onlySelfOrAdmin(_role) {
        _grantRole(_role, _account);
    }

    /// @dev overrides AccessControl to allow self/admin to revoke role
    /// @dev function sig 0xd547741f
    /// @param _role role to revoke
    /// @param _account account to revoke role from
    function revokeRole(bytes32 _role, address _account) public override onlySelfOrAdmin(_role) {
        _revokeRole(_role, _account);
    }

    // ========================= OnlyQuorum =========================

    // @notice function for quorum to change admin without going through execute function
    // @dev calldata in the case is abi.encode new admin address
    function quorumChangeAdmin(ExecuteParam calldata _param) external {
        require(_param.expiration > block.timestamp, "Verifier: expired");
        require(_param.target == address(this), "Verifier: invalid target");
        require(_param.vid == vid, "Verifier: invalid vid");

        // generate and validate hash
        bytes32 hash = hashCallData(_param.vid, _param.target, _param.callData, _param.expiration);
        (bool sigsValid, ) = verifySignatures(hash, _param.signatures);
        require(sigsValid, "Verifier: invalid signatures");
        require(!usedHashes[hash], "Verifier: hash already used");

        usedHashes[hash] = true;
        _grantRole(ADMIN_ROLE, abi.decode(_param.callData, (address)));
    }

    // ========================= OnlyAdmin =========================

    /// @param _params array of DstConfigParam
    function setDstConfig(DstConfigParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
        for (uint i = 0; i < _params.length; ++i) {
            DstConfigParam calldata param = _params[i];
            dstConfig[param.dstEid] = DstConfig(param.gas, param.multiplierBps, param.floorMarginUSD);
        }
        emit SetDstConfig(_params);
    }

    /// @dev takes a list of instructions and executes them in order
    /// @dev if any of the instructions fail, it will emit an error event and continue to execute the rest of the instructions
    /// @param _params array of ExecuteParam, includes target, callData, expiration, signatures
    function execute(ExecuteParam[] calldata _params) external onlyRole(ADMIN_ROLE) {
        for (uint i = 0; i < _params.length; ++i) {
            ExecuteParam calldata param = _params[i];
            // 1. skip if invalid vid
            if (param.vid != vid) {
                continue;
            }

            // 2. skip if expired
            if (param.expiration <= block.timestamp) {
                continue;
            }

            // generate and validate hash
            bytes32 hash = hashCallData(param.vid, param.target, param.callData, param.expiration);

            // 3. check signatures
            (bool sigsValid, ) = verifySignatures(hash, param.signatures);
            if (!sigsValid) {
                emit VerifySignaturesFailed(i);
                continue;
            }

            // 4. should check hash
            bool shouldCheckHash = _shouldCheckHash(bytes4(param.callData));
            if (shouldCheckHash) {
                if (usedHashes[hash]) {
                    emit HashAlreadyUsed(param, hash);
                    continue;
                } else {
                    usedHashes[hash] = true; // prevent reentry and replay attack
                }
            }

            (bool success, bytes memory rtnData) = param.target.call(param.callData);
            if (!success) {
                if (shouldCheckHash) {
                    // need to unset the usedHash otherwise it cant be used
                    usedHashes[hash] = false;
                }
                // emit an event in any case
                emit ExecuteFailed(i, rtnData);
            }
        }
    }

    /// @dev to support ULNv2
    /// @dev the withdrawFee function for ULN30X is built in the Worker contract
    /// @param _lib message lib address
    /// @param _to address to withdraw to
    /// @param _amount amount to withdraw
    function withdrawFeeFromUlnV2(address _lib, address payable _to, uint _amount) external onlyRole(ADMIN_ROLE) {
        require(hasRole(MESSAGE_LIB_ROLE, _lib), "Verifier: Invalid message lib");
        ILayerZeroUltraLightNodeV2(_lib).withdrawNative(_to, _amount);
    }

    // ========================= OnlyMessageLib =========================

    /// @dev for ULN301, ULN302 and more to assign job
    /// @dev verifier network can reject job from _sender by adding/removing them from allowlist/denylist
    /// @param _param assign job param
    /// @param _options verifier options
    function assignJob(
        AssignJobParam calldata _param,
        bytes calldata _options
    ) external payable onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_param.sender) returns (uint totalFee) {
        IVerifierFeeLib.FeeParams memory feeParams = IVerifierFeeLib.FeeParams(
            priceFeed,
            _param.dstEid,
            _param.confirmations,
            _param.sender,
            quorum,
            defaultMultiplierBps
        );
        totalFee = IVerifierFeeLib(workerFeeLib).getFeeOnSend(feeParams, dstConfig[_param.dstEid], _options);
    }

    /// @dev to support ULNv2
    /// @dev verifier network can reject job from _sender by adding/removing them from allowlist/denylist
    /// @param _dstEid destination EndpointId
    /// @param //_outboundProofType outbound proof type
    /// @param _confirmations block confirmations
    /// @param _sender message sender address
    function assignJob(
        uint16 _dstEid,
        uint16 /*_outboundProofType*/,
        uint64 _confirmations,
        address _sender
    ) external onlyRole(MESSAGE_LIB_ROLE) onlyAcl(_sender) returns (uint totalFee) {
        IVerifierFeeLib.FeeParams memory params = IVerifierFeeLib.FeeParams(
            priceFeed,
            _dstEid,
            _confirmations,
            _sender,
            quorum,
            defaultMultiplierBps
        );
        // ULNV2 does not have verifier options
        totalFee = IVerifierFeeLib(workerFeeLib).getFeeOnSend(params, dstConfig[_dstEid], bytes(""));
        emit VerifierFeePaid(totalFee);
    }

    // ========================= View =========================

    /// @dev getFee can revert if _sender doesn't pass ACL
    /// @param _dstEid destination EndpointId
    /// @param _confirmations block confirmations
    /// @param _sender message sender address
    /// @param _options verifier options
    /// @return fee fee in native amount
    function getFee(
        uint32 _dstEid,
        uint64 _confirmations,
        address _sender,
        bytes calldata _options
    ) external view onlyAcl(_sender) returns (uint fee) {
        IVerifierFeeLib.FeeParams memory params = IVerifierFeeLib.FeeParams(
            priceFeed,
            _dstEid,
            _confirmations,
            _sender,
            quorum,
            defaultMultiplierBps
        );
        return IVerifierFeeLib(workerFeeLib).getFee(params, dstConfig[_dstEid], _options);
    }

    /// @dev to support ULNv2
    /// @dev getFee can revert if _sender doesn't pass ACL
    /// @param _dstEid destination EndpointId
    /// @param //_outboundProofType outbound proof type
    /// @param _confirmations block confirmations
    /// @param _sender message sender address
    function getFee(
        uint16 _dstEid,
        uint16 /*_outboundProofType*/,
        uint64 _confirmations,
        address _sender
    ) public view onlyAcl(_sender) returns (uint fee) {
        IVerifierFeeLib.FeeParams memory params = IVerifierFeeLib.FeeParams(
            priceFeed,
            _dstEid,
            _confirmations,
            _sender,
            quorum,
            defaultMultiplierBps
        );
        return IVerifierFeeLib(workerFeeLib).getFee(params, dstConfig[_dstEid], bytes(""));
    }

    /// @param _target target address
    /// @param _callData call data
    /// @param _expiration expiration timestamp
    /// @return hash of above
    function hashCallData(
        uint32 _vid,
        address _target,
        bytes calldata _callData,
        uint _expiration
    ) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(_vid, _target, _expiration, _callData));
    }

    // ========================= Internal =========================

    /// @dev to save gas, we don't check hash for some functions (where replaying won't change the state)
    /// @dev for example, some administrative functions like changing signers, the contract should check hash to double spending
    /// @dev should ensure that all onlySelf functions have unique functionSig
    /// @param _functionSig function signature
    /// @return true if should check hash
    function _shouldCheckHash(bytes4 _functionSig) internal pure returns (bool) {
        // never check for these selectors to save gas
        return
            _functionSig != IUltraLightNode.verify.selector && // 0x0223536e, replaying won't change the state
            _functionSig != this.verifyAndDeliver.selector && // 0xb724b133, replaying calls deliver on top of verify, which will be rejected at uln if not deliverable
            _functionSig != ILayerZeroUltraLightNodeV2.updateHash.selector; // 0x704316e5, replaying will be revert at uln
    }
}

File 2 of 31 : MessagingStructs.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

struct PacketForQuote {
    address sender;
    uint32 dstEid;
    bytes message;
}

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

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

File 3 of 31 : ILayerZeroEndpointV2.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

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

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

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

struct MessagingFee {
    uint nativeFee;
    uint lzTokenFee;
}

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

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

    event PacketReceived(Origin origin, address receiver);

    event LzReceiveFailed(Origin origin, address receiver, bytes reason);

    event LayerZeroTokenSet(address token);

    function quote(
        address _sender,
        uint32 _dstEid,
        bytes calldata _message,
        bool _payInLzToken,
        bytes calldata _options
    ) external view returns (MessagingFee memory);

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

    function sendWithAlt(
        MessagingParams calldata _params,
        uint _lzTokenFee,
        uint _altTokenFee
    ) external returns (MessagingReceipt memory);

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

    function deliverable(Origin calldata _origin, address _receiveLib, address _receiver) external view returns (bool);

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

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

    function setLayerZeroToken(address _layerZeroToken) external;

    function layerZeroToken() external view returns (address);

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

File 4 of 31 : IMessageLib.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {MessagingFee, SetConfigParam} from "./ILayerZeroEndpointV2.sol";
import {Packet, PacketForQuote} from "../MessagingStructs.sol";

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

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

    function setTreasury(address _treasury) external;

    function setConfig(address _oapp, uint32 _eid, SetConfigParam[] calldata _config) external;

    function snapshotConfig(uint32[] calldata _eids, address _oapp) external;

    function resetConfig(uint32[] calldata _eids, address _oapp) external;

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

    function getDefaultConfig(uint32 _eid, uint32 _configType) external view returns (bytes memory);

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

    function withdrawFee(address _to, uint _amount) external;

    function withdrawLzTokenFee(address _lzToken, address _to, uint _amount) external;

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

File 5 of 31 : IMessageLibManager.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

struct SetConfigParam {
    uint32 configType;
    bytes config;
}

interface IMessageLibManager {
    struct Timeout {
        address lib;
        uint 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, uint expiry);
    event SendLibrarySet(address sender, uint32 eid, address newLib);
    event ReceiveLibrarySet(address receiver, uint32 eid, address oldLib, address newLib);
    event ReceiveLibraryTimoutSet(address receiver, uint32 eid, address oldLib, uint 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, uint _timeout) external;

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

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

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

    function defaultConfig(address _lib, uint32 _eid, uint32 _configType) external view returns (bytes memory);

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

    /// ------------------- OApp interfaces -------------------
    function setSendLibrary(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(uint32 _eid, address _newLib, uint _gracePeriod) external;

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

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

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

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

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

    function snapshotConfig(address _lib, uint32[] calldata _eids) external;

    function resetConfig(address _lib, uint32[] calldata _eids) external;
}

File 6 of 31 : IMessagingChannel.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

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

    function eid() external view returns (uint32);

    // this is an emergency function if a message can not be delivered for some reasons
    // required to provide _nextNonce to avoid race condition
    function skip(uint32 _srcEid, bytes32 _sender, uint64 _nonce) 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);

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

File 7 of 31 : IMessagingComposer.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

interface IMessagingComposer {
    event ComposedMessageDelivered(address receiver, address composer, bytes32 guid, bytes message);
    event ComposedMessageReceived(address receiver, address composer, bytes32 guid);
    event LzComposeFailed(address receiver, address composer, bytes32 guid, bytes reason);

    function deliverComposedMessage(address _composer, bytes32 _guid, bytes calldata _message) external;

    function lzCompose(
        address _receiver,
        address _composer,
        bytes32 _guid,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable returns (bool, bytes memory);
}

File 8 of 31 : IMessagingContext.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

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

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

File 9 of 31 : Errors.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.0;

library Errors {
    // Invalid Argument (http: 400)
    string internal constant INVALID_ARGUMENT = "LZ10000";
    string internal constant ONLY_REGISTERED = "LZ10001";
    string internal constant ONLY_REGISTERED_OR_DEFAULT = "LZ10002";
    string internal constant INVALID_AMOUNT = "LZ10003";
    string internal constant INVALID_NONCE = "LZ10004";
    string internal constant SAME_VALUE = "LZ10005";
    string internal constant UNSORTED = "LZ10006";
    string internal constant INVALID_VERSION = "LZ10007";
    string internal constant INVALID_EID = "LZ10008";
    string internal constant INVALID_SIZE = "LZ10009";
    string internal constant ONLY_NON_DEFAULT = "LZ10010";
    string internal constant INVALID_VERIFIERS = "LZ10011";
    string internal constant INVALID_WORKER_ID = "LZ10012";
    string internal constant DUPLICATED_OPTION = "LZ10013";
    string internal constant INVALID_LEGACY_OPTION = "LZ10014";
    string internal constant INVALID_VERIFIER_OPTION = "LZ10015";
    string internal constant INVALID_WORKER_OPTIONS = "LZ10016";
    string internal constant INVALID_EXECUTOR_OPTION = "LZ10017";
    string internal constant INVALID_ADDRESS = "LZ10018";

    // Out of Range (http: 400)
    string internal constant OUT_OF_RANGE = "LZ20000";

    // Invalid State (http: 400)
    string internal constant INVALID_STATE = "LZ30000";
    string internal constant SEND_REENTRANCY = "LZ30001";
    string internal constant RECEIVE_REENTRANCY = "LZ30002";
    string internal constant COMPOSE_REENTRANCY = "LZ30003";

    // Permission Denied (http: 403)
    string internal constant PERMISSION_DENIED = "LZ50000";

    // Not Found (http: 404)
    string internal constant NOT_FOUND = "LZ60000";

    // Already Exists (http: 409)
    string internal constant ALREADY_EXISTS = "LZ80000";

    // Not Implemented (http: 501)
    string internal constant NOT_IMPLEMENTED = "LZC0000";
    string internal constant UNSUPPORTED_INTERFACE = "LZC0001";
    string internal constant UNSUPPORTED_OPTION_TYPE = "LZC0002";

    // Unavailable (http: 503)
    string internal constant UNAVAILABLE = "LZD0000";
    string internal constant NATIVE_COIN_UNAVAILABLE = "LZD0001";
    string internal constant TOKEN_UNAVAILABLE = "LZD0002";
    string internal constant DEFAULT_LIBRARY_UNAVAILABLE = "LZD0003";
    string internal constant VERIFIERS_UNAVAILABLE = "LZD0004";
}

File 10 of 31 : ILayerZeroUltraLightNodeV2.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

interface ILayerZeroUltraLightNodeV2 {
    // Relayer functions
    function validateTransactionProof(
        uint16 _srcChainId,
        address _dstAddress,
        uint _gasLimit,
        bytes32 _lookupHash,
        bytes32 _blockData,
        bytes calldata _transactionProof
    ) external;

    // an Oracle delivers the block data using updateHash()
    function updateHash(uint16 _srcChainId, bytes32 _lookupHash, uint _confirmations, bytes32 _blockData) external;

    // can only withdraw the receivable of the msg.sender
    function withdrawNative(address payable _to, uint _amount) external;

    function withdrawZRO(address _to, uint _amount) external;

    // view functions
    function getAppConfig(
        uint16 _remoteChainId,
        address _userApplicationAddress
    ) external view returns (ApplicationConfiguration memory);

    function accruedNativeFee(address _address) external view returns (uint);

    struct ApplicationConfiguration {
        uint16 inboundProofLibraryVersion;
        uint64 inboundBlockConfirmations;
        address relayer;
        uint16 outboundProofType;
        uint64 outboundBlockConfirmations;
        address oracle;
    }

    event HashReceived(
        uint16 indexed srcChainId,
        address indexed oracle,
        bytes32 lookupHash,
        bytes32 blockData,
        uint confirmations
    );
    event RelayerParams(bytes adapterParams, uint16 outboundProofType);
    event Packet(bytes payload);
    event InvalidDst(
        uint16 indexed srcChainId,
        bytes srcAddress,
        address indexed dstAddress,
        uint64 nonce,
        bytes32 payloadHash
    );
    event PacketReceived(
        uint16 indexed srcChainId,
        bytes srcAddress,
        address indexed dstAddress,
        uint64 nonce,
        bytes32 payloadHash
    );
    event AppConfigUpdated(address indexed userApplication, uint indexed configType, bytes newConfig);
    event AddInboundProofLibraryForChain(uint16 indexed chainId, address lib);
    event EnableSupportedOutboundProof(uint16 indexed chainId, uint16 proofType);
    event SetChainAddressSize(uint16 indexed chainId, uint size);
    event SetDefaultConfigForChainId(
        uint16 indexed chainId,
        uint16 inboundProofLib,
        uint64 inboundBlockConfirm,
        address relayer,
        uint16 outboundProofType,
        uint64 outboundBlockConfirm,
        address oracle
    );
    event SetDefaultAdapterParamsForChainId(uint16 indexed chainId, uint16 indexed proofType, bytes adapterParams);
    event SetLayerZeroToken(address indexed tokenAddress);
    event SetRemoteUln(uint16 indexed chainId, bytes32 uln);
    event SetTreasury(address indexed treasuryAddress);
    event WithdrawZRO(address indexed msgSender, address indexed to, uint amount);
    event WithdrawNative(address indexed msgSender, address indexed to, uint amount);
}

File 11 of 31 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

File 12 of 31 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

File 13 of 31 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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 Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling 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 14 of 31 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 15 of 31 : 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 16 of 31 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 17 of 31 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32")
            mstore(0x1c, hash)
            message := keccak256(0x00, 0x3c)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, "\x19\x01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            data := keccak256(ptr, 0x42)
        }
    }

    /**
     * @dev Returns an Ethereum Signed Data with intended validator, created from a
     * `validator` and `data` according to the version 0 of EIP-191.
     *
     * See {recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x00", validator, data));
    }
}

File 18 of 31 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 19 of 31 : 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 20 of 31 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 21 of 31 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

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

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 22 of 31 : MessageLibBase.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.19;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Errors.sol";

import "./interfaces/ILayerZeroExecutor.sol";
import "./interfaces/ILayerZeroTreasury.sol";

struct WorkerOptions {
    uint8 workerId;
    bytes options;
}

enum DeliveryState {
    Signing,
    Deliverable,
    Delivered,
    Waiting
}

abstract contract MessageLibBase is Ownable {
    address internal immutable endpoint;
    uint32 internal immutable localEid;
    uint internal immutable treasuryGasCap;

    // config
    address public treasury;

    // accumulated fees for workers and treasury
    mapping(address worker => uint) public fees;

    event ExecutorFeePaid(address executor, uint fee);
    event TreasurySet(address treasury);

    // only the endpoint can call SEND() and setConfig()
    modifier onlyEndpoint() {
        require(endpoint == msg.sender, Errors.PERMISSION_DENIED);
        _;
    }

    constructor(address _endpoint, uint32 _localEid, uint _treasuryGasCap) {
        endpoint = _endpoint;
        localEid = _localEid;
        treasuryGasCap = _treasuryGasCap;
    }

    // ======================= Internal =======================
    function _assertMessageSize(uint _actual, uint _max) internal pure {
        require(_actual <= _max, Errors.INVALID_SIZE);
    }

    function _sendToExecutor(
        address _executor,
        uint32 _dstEid,
        address _sender,
        uint _msgSize,
        bytes memory _executorOptions
    ) internal returns (uint executorFee) {
        executorFee = ILayerZeroExecutor(_executor).assignJob(_dstEid, _sender, _msgSize, _executorOptions);
        if (executorFee > 0) {
            fees[_executor] += executorFee;
        }
        emit ExecutorFeePaid(_executor, executorFee);
    }

    function _sendToTreasury(
        address _sender,
        uint32 _dstEid,
        uint _totalNativeFee,
        bool _payInLzToken
    ) internal returns (uint treasuryNativeFee, uint lzTokenFee) {
        // fee should be in lzTokenFee if payInLzToken, otherwise in native
        (treasuryNativeFee, lzTokenFee) = _quoteTreasuryFee(_sender, _dstEid, _totalNativeFee, _payInLzToken);
        // if payInLzToken, handle in messagelib / endpoint
        if (treasuryNativeFee > 0) {
            fees[treasury] += treasuryNativeFee;
        }
    }

    function _quote(
        address _sender,
        uint32 _dstEid,
        uint _msgSize,
        bool _payInLzToken,
        bytes calldata _options
    ) internal view returns (uint, uint) {
        require(_options.length > 0, Errors.INVALID_ARGUMENT);

        (bytes memory executorOptions, WorkerOptions[] memory otherWorkerOptions) = _getExecutorAndOtherOptions(
            _options
        );

        // quote other workers
        (uint nativeFee, address executor, uint maxMsgSize) = _quoteWorkers(_sender, _dstEid, otherWorkerOptions);

        // assert msg size
        _assertMessageSize(_msgSize, maxMsgSize);

        // quote executor
        nativeFee += ILayerZeroExecutor(executor).getFee(_dstEid, _sender, _msgSize, executorOptions);

        // quote treasury
        (uint treasuryNativeFee, uint lzTokenFee) = _quoteTreasuryFee(_sender, _dstEid, nativeFee, _payInLzToken);
        if (treasuryNativeFee > 0) {
            nativeFee += treasuryNativeFee;
        }

        return (nativeFee, lzTokenFee);
    }

    function _quoteTreasuryFee(
        address _sender,
        uint32 _eid,
        uint _totalFee,
        bool _payInLzToken
    ) internal view returns (uint nativeFee, uint lzTokenFee) {
        if (treasury != address(0x0)) {
            try ILayerZeroTreasury(treasury).getFee(_sender, _eid, _totalFee, _payInLzToken) returns (
                uint treasuryFee
            ) {
                // success
                if (_payInLzToken) {
                    lzTokenFee = treasuryFee;
                } else {
                    // pay in native, make sure that the treasury fee is not higher than the cap
                    uint gasFeeEstimate = tx.gasprice * treasuryGasCap;
                    // cap is the max of total fee and gasFeeEstimate. this is to prevent apps from forcing the cap to 0.
                    uint nativeFeeCap = _totalFee > gasFeeEstimate ? _totalFee : gasFeeEstimate;
                    // to prevent the treasury from returning an overly high value to break the path
                    nativeFee = treasuryFee > nativeFeeCap ? nativeFeeCap : treasuryFee;
                }
            } catch {
                // failure, something wrong with treasury contract, charge nothing and continue
            }
        }
    }

    function _transferNative(address _to, uint _amount) internal {
        (bool success, ) = _to.call{value: _amount}("");
        require(success, Errors.INVALID_STATE);
    }

    // for msg.sender only
    function _assertAndDebitAmount(address _to, uint _amount) internal {
        uint fee = fees[msg.sender];
        require(_to != address(0x0) && _amount <= fee, Errors.INVALID_ARGUMENT);
        unchecked {
            fees[msg.sender] = fee - _amount;
        }
    }

    function _setTreasury(address _treasury) internal {
        treasury = _treasury;
        emit TreasurySet(_treasury);
    }

    // ======================= Virtual =======================
    // For implementation to override
    function _quoteWorkers(
        address _oapp,
        uint32 _eid,
        WorkerOptions[] memory _options
    ) internal view virtual returns (uint nativeFee, address executor, uint maxMsgSize);

    function _getExecutorAndOtherOptions(
        bytes calldata _options
    ) internal view virtual returns (bytes memory executorOptions, WorkerOptions[] memory otherWorkerOptions);
}

File 23 of 31 : Worker.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.19;

import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLib.sol";
import "./interfaces/IWorker.sol";

abstract contract Worker is AccessControl, Pausable, IWorker {
    bytes32 internal constant MESSAGE_LIB_ROLE = keccak256("MESSAGE_LIB_ROLE");
    bytes32 internal constant ALLOWLIST = keccak256("ALLOWLIST");
    bytes32 internal constant DENYLIST = keccak256("DENYLIST");
    bytes32 internal constant ADMIN_ROLE = keccak256("ADMIN_ROLE");

    address public workerFeeLib;

    uint64 public allowlistSize;
    uint16 public defaultMultiplierBps;
    address public priceFeed;

    // ========================= Constructor =========================

    /// @param _messageLibs array of message lib addresses that are granted the MESSAGE_LIB_ROLE
    /// @param _priceFeed price feed address
    /// @param _defaultMultiplierBps default multiplier for worker fee
    /// @param _roleAdmin address that is granted the DEFAULT_ADMIN_ROLE (can grant and revoke all roles)
    /// @param _admins array of admin addresses that are granted the ADMIN_ROLE
    constructor(
        address[] memory _messageLibs,
        address _priceFeed,
        uint16 _defaultMultiplierBps,
        address _roleAdmin,
        address[] memory _admins
    ) {
        defaultMultiplierBps = _defaultMultiplierBps;
        priceFeed = _priceFeed;

        if (_roleAdmin != address(0x0)) {
            _grantRole(DEFAULT_ADMIN_ROLE, _roleAdmin); // _roleAdmin can grant and revoke all roles
        }

        for (uint i = 0; i < _messageLibs.length; ++i) {
            _grantRole(MESSAGE_LIB_ROLE, _messageLibs[i]);
        }

        for (uint i = 0; i < _admins.length; ++i) {
            _grantRole(ADMIN_ROLE, _admins[i]);
        }
    }

    // ========================= Modifier =========================

    modifier onlyAcl(address _sender) {
        require(hasAcl(_sender), "Worker: not allowed");
        _;
    }

    /// @dev Access control list using allowlist and denylist
    /// @dev 1) if one address is in the denylist -> deny
    /// @dev 2) else if address in the allowlist OR allowlist is empty (allows everyone)-> allow
    /// @dev 3) else deny
    /// @param _sender address to check
    function hasAcl(address _sender) public view returns (bool) {
        if (hasRole(DENYLIST, _sender)) {
            return false;
        } else if (allowlistSize == 0 || hasRole(ALLOWLIST, _sender)) {
            return true;
        } else {
            return false;
        }
    }

    // ========================= OnyDefaultAdmin =========================

    /// @dev flag to pause execution of workers (if used with whenNotPaused modifier)
    /// @param _paused true to pause, false to unpause
    function setPaused(bool _paused) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_paused) {
            _pause();
        } else {
            _unpause();
        }
    }

    // ========================= OnlyAdmin =========================

    /// @param _priceFeed price feed address
    function setPriceFeed(address _priceFeed) external onlyRole(ADMIN_ROLE) {
        priceFeed = _priceFeed;
        emit SetPriceFeed(_priceFeed);
    }

    /// @param _workerFeeLib worker fee lib address
    function setWorkerFeeLib(address _workerFeeLib) external onlyRole(ADMIN_ROLE) {
        workerFeeLib = _workerFeeLib;
        emit SetWorkerLib(_workerFeeLib);
    }

    /// @param _multiplierBps default multiplier for worker fee
    function setDefaultMultiplierBps(uint16 _multiplierBps) external onlyRole(ADMIN_ROLE) {
        defaultMultiplierBps = _multiplierBps;
        emit SetDefaultMultiplierBps(_multiplierBps);
    }

    /// @dev supports withdrawing fee from ULN301, ULN302 and more
    /// @param _lib message lib address
    /// @param _to address to withdraw fee to
    /// @param _amount amount to withdraw
    function withdrawFee(address _lib, address _to, uint _amount) external onlyRole(ADMIN_ROLE) {
        require(hasRole(MESSAGE_LIB_ROLE, _lib), "Worker: Invalid message lib");
        IMessageLib(_lib).withdrawFee(_to, _amount);
        emit Withdraw(_lib, _to, _amount);
    }

    // ========================= Internal Functions =========================

    /// @dev overrides AccessControl to allow for counting of allowlistSize
    /// @param _role role to grant
    /// @param _account address to grant role to
    function _grantRole(bytes32 _role, address _account) internal override {
        if (_role == ALLOWLIST && !hasRole(_role, _account)) {
            ++allowlistSize;
        }
        super._grantRole(_role, _account);
    }

    /// @dev overrides AccessControl to allow for counting of allowlistSize
    /// @param _role role to revoke
    /// @param _account address to revoke role from
    function _revokeRole(bytes32 _role, address _account) internal override {
        if (_role == ALLOWLIST && hasRole(_role, _account)) {
            --allowlistSize;
        }
        super._revokeRole(_role, _account);
    }

    /// @dev overrides AccessControl to disable renouncing of roles
    function renounceRole(bytes32 /*role*/, address /*account*/) public pure override {
        revert("Worker: cannot renounce role");
    }
}

File 24 of 31 : ILayerZeroExecutor.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

interface ILayerZeroExecutor {
    // @notice query price and assign jobs at the same time
    // @param _dstEid - the destination endpoint identifier
    // @param _sender - the source sending contract address. executors may apply price discrimination to senders
    // @param _calldataSize - dynamic data size of message + caller params
    // @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
    function assignJob(
        uint32 _dstEid,
        address _sender,
        uint _calldataSize,
        bytes calldata _options
    ) external payable returns (uint price);

    // @notice query the executor price for relaying the payload and its proof to the destination chain
    // @param _dstEid - the destination endpoint identifier
    // @param _sender - the source sending contract address. executors may apply price discrimination to senders
    // @param _calldataSize - dynamic data size of message + caller params
    // @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
    function getFee(
        uint32 _dstEid,
        address _sender,
        uint _calldataSize,
        bytes calldata _options
    ) external view returns (uint price);
}

File 25 of 31 : ILayerZeroTreasury.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

interface ILayerZeroTreasury {
    function getFee(address _sender, uint32 _eid, uint _totalFee, bool _payInLzToken) external view returns (uint);
}

File 26 of 31 : IWorker.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

interface IWorker {
    event SetWorkerLib(address workerLib);
    event SetPriceFeed(address priceFeed);
    event SetDefaultMultiplierBps(uint16 multiplierBps);
    event Withdraw(address lib, address to, uint amount);

    function setPriceFeed(address _priceFeed) external;

    function priceFeed() external view returns (address);

    function setDefaultMultiplierBps(uint16 _multiplierBps) external;

    function defaultMultiplierBps() external view returns (uint16);

    function withdrawFee(address _lib, address _to, uint _amount) external;
}

File 27 of 31 : MultiSig.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.19;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

abstract contract MultiSig {
    enum Errors {
        NoError,
        SignatureError,
        DuplicatedSigner,
        SignerNotInCommittee
    }

    mapping(address signer => bool active) public signers;
    uint64 public signerSize;
    uint64 public quorum;

    event UpdateSigner(address _signer, bool _active);
    event UpdateQuorum(uint64 _quorum);

    modifier onlySigner() {
        require(signers[msg.sender], "MultiSig: caller must be signer");
        _;
    }

    constructor(address[] memory _signers, uint64 _quorum) {
        require(_signers.length >= _quorum && _quorum > 0, "MultiSig: signers too few");

        address lastSigner = address(0);
        for (uint i = 0; i < _signers.length; i++) {
            address signer = _signers[i];
            require(signer > lastSigner, "MultiSig: signers not sorted"); // to ensure no duplicates
            signers[signer] = true;
            lastSigner = signer;
        }
        signerSize = uint64(_signers.length);
        quorum = _quorum;
    }

    function _setSigner(address _signer, bool _active) internal {
        require(signers[_signer] != _active, "MultiSig: signer already in that state");
        signers[_signer] = _active;
        signerSize = _active ? signerSize + 1 : signerSize - 1;
        require(signerSize >= quorum, "MultiSig: committee size < threshold");
        emit UpdateSigner(_signer, _active);
    }

    function _setQuorum(uint64 _quorum) internal {
        require(_quorum <= signerSize && _quorum > 0, "MultiSig: invalid quorum");
        quorum = _quorum;
        emit UpdateQuorum(_quorum);
    }

    function verifySignatures(bytes32 _hash, bytes calldata _signatures) public view returns (bool, Errors) {
        if (_signatures.length != uint(quorum) * 65) {
            return (false, Errors.SignatureError);
        }

        bytes32 messageDigest = _getEthSignedMessageHash(_hash);

        address lastSigner = address(0); // There cannot be a signer with address 0.
        for (uint i = 0; i < quorum; i++) {
            bytes calldata signature = _signatures[i * 65:(i + 1) * 65];
            (address currentSigner, ECDSA.RecoverError error) = ECDSA.tryRecover(messageDigest, signature);

            if (error != ECDSA.RecoverError.NoError) return (false, Errors.SignatureError);
            if (currentSigner <= lastSigner) return (false, Errors.DuplicatedSigner); // prevent duplicate signatures
            if (!signers[currentSigner]) return (false, Errors.SignerNotInCommittee); // signature is not in committee
            lastSigner = currentSigner;
        }
        return (true, Errors.NoError);
    }

    function _getEthSignedMessageHash(bytes32 _messageHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
    }
}

File 28 of 31 : ILayerZeroVerifier.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

interface ILayerZeroVerifier {
    struct AssignJobParam {
        uint32 dstEid;
        bytes packetHeader;
        bytes32 payloadHash;
        uint64 confirmations;
        address sender;
    }

    // @notice query price and assign jobs at the same time
    // @param _dstEid - the destination endpoint identifier
    // @param _packetHeader - version + nonce + path
    // @param _payloadHash - hash of guid + message
    // @param _confirmations - block confirmation delay before relaying blocks
    // @param _sender - the source sending contract address
    // @param _options - options
    function assignJob(AssignJobParam calldata _param, bytes calldata _options) external payable returns (uint fee);

    // @notice query the verifier fee for relaying block information to the destination chain
    // @param _dstEid the destination endpoint identifier
    // @param _confirmations - block confirmation delay before relaying blocks
    // @param _sender - the source sending contract address
    // @param _options - options
    function getFee(
        uint32 _dstEid,
        uint64 _confirmations,
        address _sender,
        bytes calldata _options
    ) external view returns (uint fee);
}

File 29 of 31 : IUltraLightNode.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

import {DeliveryState} from "../../MessageLibBase.sol";

interface IUltraLightNode {
    function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external;

    function deliver(bytes calldata _packetHeader, bytes32 _payloadHash) external;

    function deliverable(bytes calldata _packetHeader, bytes32 _payloadHash) external view returns (DeliveryState);
}

File 30 of 31 : IVerifier.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

import "../../interfaces/IWorker.sol";
import "./ILayerZeroVerifier.sol";

interface IVerifier is IWorker, ILayerZeroVerifier {
    struct DstConfigParam {
        uint32 dstEid;
        uint64 gas;
        uint16 multiplierBps;
        uint128 floorMarginUSD;
    }

    struct DstConfig {
        uint64 gas;
        uint16 multiplierBps;
        uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
    }

    event SetDstConfig(DstConfigParam[] params);

    function dstConfig(uint32 _dstEid) external view returns (uint64, uint16, uint128);
}

File 31 of 31 : IVerifierFeeLib.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity >=0.8.0;

import "./IVerifier.sol";

interface IVerifierFeeLib {
    struct FeeParams {
        address priceFeed;
        uint32 dstEid;
        uint64 confirmations;
        address sender;
        uint64 quorum;
        uint16 defaultMultiplierBps;
    }

    function getFeeOnSend(
        FeeParams memory _params,
        IVerifier.DstConfig memory _dstConfig,
        bytes memory _options
    ) external payable returns (uint fee);

    function getFee(
        FeeParams calldata _params,
        IVerifier.DstConfig calldata _dstConfig,
        bytes calldata _options
    ) external view returns (uint fee);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint32","name":"_vid","type":"uint32"},{"internalType":"address[]","name":"_messageLibs","type":"address[]"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"address[]","name":"_signers","type":"address[]"},{"internalType":"uint64","name":"_quorum","type":"uint64"},{"internalType":"address[]","name":"_admins","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"ExecuteFailed","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"vid","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"indexed":false,"internalType":"struct ExecuteParam","name":"param","type":"tuple"},{"indexed":false,"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"HashAlreadyUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"multiplierBps","type":"uint16"}],"name":"SetDefaultMultiplierBps","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"uint64","name":"gas","type":"uint64"},{"internalType":"uint16","name":"multiplierBps","type":"uint16"},{"internalType":"uint128","name":"floorMarginUSD","type":"uint128"}],"indexed":false,"internalType":"struct IVerifier.DstConfigParam[]","name":"params","type":"tuple[]"}],"name":"SetDstConfig","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"priceFeed","type":"address"}],"name":"SetPriceFeed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"workerLib","type":"address"}],"name":"SetWorkerLib","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"_quorum","type":"uint64"}],"name":"UpdateQuorum","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_signer","type":"address"},{"indexed":false,"internalType":"bool","name":"_active","type":"bool"}],"name":"UpdateSigner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"VerifierFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"idx","type":"uint256"}],"name":"VerifySignaturesFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"lib","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowlistSize","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes","name":"packetHeader","type":"bytes"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"internalType":"uint64","name":"confirmations","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"internalType":"struct ILayerZeroVerifier.AssignJobParam","name":"_param","type":"tuple"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"assignJob","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstEid","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint64","name":"_confirmations","type":"uint64"},{"internalType":"address","name":"_sender","type":"address"}],"name":"assignJob","outputs":[{"internalType":"uint256","name":"totalFee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultMultiplierBps","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"}],"name":"dstConfig","outputs":[{"internalType":"uint64","name":"gas","type":"uint64"},{"internalType":"uint16","name":"multiplierBps","type":"uint16"},{"internalType":"uint128","name":"floorMarginUSD","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"vid","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"internalType":"struct ExecuteParam[]","name":"_params","type":"tuple[]"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"uint64","name":"_confirmations","type":"uint64"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_dstEid","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint64","name":"_confirmations","type":"uint64"},{"internalType":"address","name":"_sender","type":"address"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"hasAcl","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_vid","type":"uint32"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_callData","type":"bytes"},{"internalType":"uint256","name":"_expiration","type":"uint256"}],"name":"hashCallData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"vid","type":"uint32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"expiration","type":"uint256"},{"internalType":"bytes","name":"signatures","type":"bytes"}],"internalType":"struct ExecuteParam","name":"_param","type":"tuple"}],"name":"quorumChangeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_role","type":"bytes32"},{"internalType":"address","name":"_account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_multiplierBps","type":"uint16"}],"name":"setDefaultMultiplierBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"uint64","name":"gas","type":"uint64"},{"internalType":"uint16","name":"multiplierBps","type":"uint16"},{"internalType":"uint128","name":"floorMarginUSD","type":"uint128"}],"internalType":"struct IVerifier.DstConfigParam[]","name":"_params","type":"tuple[]"}],"name":"setDstConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeed","type":"address"}],"name":"setPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_quorum","type":"uint64"}],"name":"setQuorum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"bool","name":"_active","type":"bool"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_workerFeeLib","type":"address"}],"name":"setWorkerFeeLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerSize","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"signers","outputs":[{"internalType":"bool","name":"active","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"executableHash","type":"bytes32"}],"name":"usedHashes","outputs":[{"internalType":"bool","name":"used","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IUltraLightNode","name":"_uln","type":"address"},{"internalType":"bytes","name":"_packetHeader","type":"bytes"},{"internalType":"bytes32","name":"_payloadHash","type":"bytes32"},{"internalType":"uint64","name":"_confirmations","type":"uint64"}],"name":"verifyAndDeliver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"},{"internalType":"bytes","name":"_signatures","type":"bytes"}],"name":"verifySignatures","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"enum MultiSig.Errors","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vid","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_lib","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_lib","type":"address"},{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawFeeFromUlnV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"workerFeeLib","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b506040516200499f3803806200499f833981016040819052620000349162000514565b6001805460ff61ffff60e81b01191661017760ed1b179055600280546001600160a01b0319166001600160a01b03861617905582828686612ee060008660005b8551811015620000df57620000cc7f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de878381518110620000b857620000b8620005e7565b6020026020010151620002ce60201b60201c565b620000d78162000613565b905062000074565b5060005b81518110156200013a57620001277fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775838381518110620000b857620000b8620005e7565b620001328162000613565b9050620000e3565b505050505050806001600160401b03168251101580156200016457506000816001600160401b0316115b620001b65760405162461bcd60e51b815260206004820152601960248201527f4d756c74695369673a207369676e65727320746f6f206665770000000000000060448201526064015b60405180910390fd5b6000805b835181101562000282576000848281518110620001db57620001db620005e7565b60200260200101519050826001600160a01b0316816001600160a01b031611620002485760405162461bcd60e51b815260206004820152601c60248201527f4d756c74695369673a207369676e657273206e6f7420736f72746564000000006044820152606401620001ad565b6001600160a01b0381166000908152600360205260409020805460ff19166001179055915080620002798162000613565b915050620001ba565b50509051600480546001600160401b0393841668010000000000000000026001600160801b0319909116939092169290921717905550505063ffffffff90921660805250620006609050565b7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca821480156200031f57506000828152602081815260408083206001600160a01b038516845290915290205460ff16155b156200036c57600180546015906200034790600160a81b90046001600160401b03166200062f565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505b6200037882826200037c565b5050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff1662000378576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620003d83390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200044a57600080fd5b919050565b600082601f8301126200046157600080fd5b815160206001600160401b03808311156200048057620004806200041c565b8260051b604051601f19603f83011681018181108482111715620004a857620004a86200041c565b604052938452858101830193838101925087851115620004c757600080fd5b83870191505b84821015620004f157620004e18262000432565b83529183019190830190620004cd565b979650505050505050565b80516001600160401b03811681146200044a57600080fd5b60008060008060008060c087890312156200052e57600080fd5b865163ffffffff811681146200054357600080fd5b60208801519096506001600160401b03808211156200056157600080fd5b6200056f8a838b016200044f565b96506200057f60408a0162000432565b955060608901519150808211156200059657600080fd5b620005a48a838b016200044f565b9450620005b460808a01620004fc565b935060a0890151915080821115620005cb57600080fd5b50620005da89828a016200044f565b9150509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201620006285762000628620005fd565b5060010190565b60006001600160401b038281166002600160401b03198101620006565762000656620005fd565b6001019392505050565b6080516143156200068a600039600081816107d20152818161168f01526124e201526143156000f3fe6080604052600436106102695760003560e01c806391d1485411610153578063c5e193cd116100cb578063d547741f1161007f578063f010cb2311610064578063f010cb2314610883578063f3b4ebd0146108a3578063fd62e750146108c357600080fd5b8063d547741f14610843578063dafe0ccc1461086357600080fd5b8063c7b2370b116100b0578063c7b2370b146107a0578063cf34c768146107c0578063d2ae21041461080957600080fd5b8063c5e193cd14610752578063c7a823e01461077257600080fd5b8063aef18bf711610122578063b724b13311610107578063b724b133146106e0578063c358de0a14610700578063c416aa511461072057600080fd5b8063aef18bf714610690578063b143044b146106c057600080fd5b806391d148541461057257806395d376d7146105c35780639e944965146105d6578063a217fddf1461067b57600080fd5b806331cb6105116101e65780635c975abb116101b5578063736c0d5b1161019a578063736c0d5b146104d0578063741bef1a146105005780638585c9451461055257600080fd5b80635c975abb14610498578063724e78da146104b057600080fd5b806331cb61051461041857806336568abe1461043857806352d3b871146104585780635553fb8e1461047857600080fd5b80631703a0181161023d5780632de11376116102225780632de11376146103b85780632f2ff15d146103d857806330bb3aac146103f857600080fd5b80631703a01814610334578063248a9ca31461037a57600080fd5b8062bf2e801461026e57806301ffc9a7146102c25780631095b6d7146102f257806316c38b3c14610314575b600080fd5b34801561027a57600080fd5b506001546102aa907d010000000000000000000000000000000000000000000000000000000000900461ffff1681565b60405161ffff90911681526020015b60405180910390f35b3480156102ce57600080fd5b506102e26102dd36600461339f565b6108e4565b60405190151581526020016102b9565b3480156102fe57600080fd5b5061031261030d366004613403565b61097d565b005b34801561032057600080fd5b5061031261032f366004613454565b610b27565b34801561034057600080fd5b506004546103619068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016102b9565b34801561038657600080fd5b506103aa61039536600461346f565b60009081526020819052604090206001015490565b6040519081526020016102b9565b3480156103c457600080fd5b506102e26103d3366004613488565b610b4c565b3480156103e457600080fd5b506103126103f33660046134a5565b610c31565b34801561040457600080fd5b506103aa610413366004613543565b610da9565b34801561042457600080fd5b506103126104333660046135bb565b610f36565b34801561044457600080fd5b506103126104533660046134a5565b610f8f565b34801561046457600080fd5b506103126104733660046135f0565b610fd7565b34801561048457600080fd5b506103aa610493366004613677565b6111ab565b3480156104a457600080fd5b5060015460ff166102e2565b3480156104bc57600080fd5b506103126104cb366004613488565b61133a565b3480156104dc57600080fd5b506102e26104eb366004613488565b60036020526000908152604090205460ff1681565b34801561050c57600080fd5b5060025461052d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b9565b34801561055e57600080fd5b5061031261056d3660046136cd565b6113df565b34801561057e57600080fd5b506102e261058d3660046134a5565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6103aa6105d1366004613700565b61143a565b3480156105e257600080fd5b506106406105f1366004613769565b60056020526000908152604090205467ffffffffffffffff81169068010000000000000000810461ffff16906a010000000000000000000090046fffffffffffffffffffffffffffffffff1683565b6040805167ffffffffffffffff909416845261ffff90921660208401526fffffffffffffffffffffffffffffffff16908201526060016102b9565b34801561068757600080fd5b506103aa600081565b34801561069c57600080fd5b506102e26106ab36600461346f565b60066020526000908152604090205460ff1681565b3480156106cc57600080fd5b506103126106db366004613784565b61162c565b3480156106ec57600080fd5b506103126106fb3660046137e7565b61194a565b34801561070c57600080fd5b5061031261071b366004613857565b611bfd565b34801561072c57600080fd5b5060015461052d90610100900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561075e57600080fd5b506103aa61076d366004613677565b611cab565b34801561077e57600080fd5b5061079261078d366004613872565b611ea1565b6040516102b99291906138e0565b3480156107ac57600080fd5b506103126107bb366004613488565b6120bd565b3480156107cc57600080fd5b506107f47f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff90911681526020016102b9565b34801561081557600080fd5b50600154610361907501000000000000000000000000000000000000000000900467ffffffffffffffff1681565b34801561084f57600080fd5b5061031261085e3660046134a5565b612161565b34801561086f57600080fd5b5061031261087e366004613403565b61228c565b34801561088f57600080fd5b506103aa61089e36600461392d565b6123d8565b3480156108af57600080fd5b506103126108be366004613998565b612414565b3480156108cf57600080fd5b506004546103619067ffffffffffffffff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061097757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109a7816126b5565b73ffffffffffffffffffffffffffffffffffffffff841660009081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff16610a405760405162461bcd60e51b815260206004820152601b60248201527f576f726b65723a20496e76616c6964206d657373616765206c6962000000000060448201526064015b60405180910390fd5b6040517ffd9be52200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526024820184905285169063fd9be52290604401600060405180830381600087803b158015610ab057600080fd5b505af1158015610ac4573d6000803e3d6000fd5b50506040805173ffffffffffffffffffffffffffffffffffffffff8089168252871660208201529081018590527f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb9250606001905060405180910390a150505050565b6000610b32816126b5565b8115610b4457610b406126bf565b5050565b610b4061273e565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f93c430521711328044ae92d0f1f1286cf040bc4a382f1642bd89984e86630553602052604081205460ff1615610ba157506000919050565b6001547501000000000000000000000000000000000000000000900467ffffffffffffffff161580610c17575073ffffffffffffffffffffffffffffffffffffffff821660009081527f4ac82e3087b7dedf7f532cbc6915c722df8c1e31f1388c318a617b52760eaf8b602052604090205460ff165b15610c2457506001919050565b506000919050565b919050565b817f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca811480610c7f57507f4270fae16c6d150d00e80b689daca99e8073b1838ff2b6063a37be9d851283e481145b80610ca957507f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de81145b15610d0257303314610cfd5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b610d9a565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758103610d5257610cfd7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756126b5565b60405162461bcd60e51b815260206004820152601660248201527f56657269666965723a20696e76616c696420726f6c65000000000000000000006044820152606401610a37565b610da48383612795565b505050565b600083610db581610b4c565b610e015760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c08101825260025473ffffffffffffffffffffffffffffffffffffffff908116825263ffffffff8a16602080840182905267ffffffffffffffff808c16858701528a8416606086015260048054680100000000000000009004909116608086015260015461ffff7d01000000000000000000000000000000000000000000000000000000000082041660a0870152600093845260059092529185902094517f7bfa20a9000000000000000000000000000000000000000000000000000000008152939461010090910490921692637bfa20a992610ee99286928b918b9101613a1e565b602060405180830381865afa158015610f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2a9190613aeb565b98975050505050505050565b303314610f855760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b610b40828261285b565b60405162461bcd60e51b815260206004820152601c60248201527f576f726b65723a2063616e6e6f742072656e6f756e636520726f6c65000000006044820152606401610a37565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611001816126b5565b60005b8281101561116c573684848381811061101f5761101f613b04565b9050608002019050604051806060016040528082602001602081019061104591906136cd565b67ffffffffffffffff1681526020016110646060840160408501613857565b61ffff16815260200161107d6080840160608501613b53565b6fffffffffffffffffffffffffffffffff169052600560006110a26020850185613769565b63ffffffff1681526020808201929092526040908101600020835181549385015194909201516fffffffffffffffffffffffffffffffff166a0100000000000000000000027fffffffffffff00000000000000000000000000000000ffffffffffffffffffff61ffff90951668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000090941667ffffffffffffffff9093169290921792909217929092169190911790555061116581613b9d565b9050611004565b507f7dd21e42791b013d1929e86f0c59085e4fca24251f0f1aa81917b3b1611766e0838360405161119e929190613bd5565b60405180910390a1505050565b6000816111b781610b4c565b6112035760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c08101825260025473ffffffffffffffffffffffffffffffffffffffff908116825261ffff808a16602080850182905267ffffffffffffffff808b168688015289851660608701526004805468010000000000000000900490911660808701526001547d010000000000000000000000000000000000000000000000000000000000810490941660a08701526000928352600582528683208751928301885292825295517f7bfa20a9000000000000000000000000000000000000000000000000000000008152949561010090930490931693637bfa20a9936112ee9387939201613ce1565b602060405180830381865afa15801561130b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132f9190613aeb565b979650505050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611364816126b5565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527ff724a45d041687842411f2b977ef22ab8f43c8f1104f4592b42a00f9b34a643d906020015b60405180910390a15050565b30331461142e5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b61143781612a91565b50565b60007f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de611466816126b5565b61147660a0860160808701613488565b61147f81610b4c565b6114cb5760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c0810190915260025473ffffffffffffffffffffffffffffffffffffffff168152600090602080820190611506908a018a613769565b63ffffffff16815260200161152160808a0160608b016136cd565b67ffffffffffffffff16815260200161154060a08a0160808b01613488565b73ffffffffffffffffffffffffffffffffffffffff908116825260045468010000000000000000900467ffffffffffffffff166020808401919091526001547d010000000000000000000000000000000000000000000000000000000000810461ffff16604090940193909352929350610100909104169063df2b057e9083906005906000906115d2908d018d613769565b63ffffffff1663ffffffff16815260200190815260200160002089896040518563ffffffff1660e01b815260040161160d9493929190613a1e565b6020604051808303816000875af115801561130b573d6000803e3d6000fd5b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611656816126b5565b60005b82811015611944573684848381811061167457611674613b04565b90506020028101906116869190613db7565b905063ffffffff7f0000000000000000000000000000000000000000000000000000000000000000166116bc6020830183613769565b63ffffffff16146116cd5750611934565b428160600135116116de5750611934565b60006117176116f06020840184613769565b6117006040850160208601613488565b61170d6040860186613df5565b86606001356123d8565b9050600061172c8261078d6080860186613df5565b5090508061176f576040518481527fd6d90193101048cc1b6edcdc2348f5acf7a4a4a97d3e7b668b74cb7602ab3ebc9060200160405180910390a1505050611934565b600061178f6117816040860186613df5565b61178a91613e5a565b612b82565b905080156118285760008381526006602052604090205460ff16156117f0577f9bb9bddbdf537a2104255307230b323d7982f4512ee8e5bd15df62ddca50ab9784846040516117df929190613f06565b60405180910390a150505050611934565b600083815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008061183b6040870160208801613488565b73ffffffffffffffffffffffffffffffffffffffff1661185e6040880188613df5565b60405161186c929190613fcc565b6000604051808303816000865af19150503d80600081146118a9576040519150601f19603f3d011682016040523d82523d6000602084013e6118ae565b606091505b50915091508161192d5782156118f357600085815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7fdc8cdd96296241bbefda4a8e18ad2e0985a8da6495b34d409cfc4c886ee3b0cf8782604051611924929190613fdc565b60405180910390a15b5050505050505b61193d81613b9d565b9050611659565b50505050565b3033146119995760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b73ffffffffffffffffffffffffffffffffffffffff851660009081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff16611a2d5760405162461bcd60e51b815260206004820152601560248201527f56657269666965723a20696e76616c696420756c6e00000000000000000000006044820152606401610a37565b6040517f0223536e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861690630223536e90611a85908790879087908790600401613ff5565b600060405180830381600087803b158015611a9f57600080fd5b505af1158015611ab3573d6000803e3d6000fd5b5060019250611ac0915050565b6040517f7c0cf76300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690637c0cf76390611b169088908890889060040161402a565b602060405180830381865afa158015611b33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b57919061404e565b6003811115611b6857611b686138b1565b03611bf6576040517f5ed31c5900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861690635ed31c5990611bc39087908790879060040161402a565b600060405180830381600087803b158015611bdd57600080fd5b505af1158015611bf1573d6000803e3d6000fd5b505050505b5050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611c27816126b5565b600180547fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d01000000000000000000000000000000000000000000000000000000000061ffff8516908102919091179091556040519081527f7af0ac740036ffb1c97b03697859d729e80a44ae5030543d64971c313565ab4d906020016113d3565b60007f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de611cd7816126b5565b82611ce181610b4c565b611d2d5760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c08101825260025473ffffffffffffffffffffffffffffffffffffffff908116825261ffff808b16602080850182905267ffffffffffffffff808c16868801528a851660608701526004805468010000000000000000900490911660808701526001547d010000000000000000000000000000000000000000000000000000000000810490941660a08701526000928352600582528683208751928301885292825295517fdf2b057e00000000000000000000000000000000000000000000000000000000815294956101009093049093169363df2b057e93611e189387939201613ce1565b6020604051808303816000875af1158015611e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5b9190613aeb565b93507f87e46b0a6199bc734632187269a103c05714ee0adae5b28f30723955724f37ef84604051611e8e91815260200190565b60405180910390a1505050949350505050565b6004546000908190611eca9068010000000000000000900467ffffffffffffffff16604161406f565b8314611edc57506000905060016120b5565b6000611f35866040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b90506000805b60045468010000000000000000900467ffffffffffffffff168110156120a9573660008888611f6b85604161406f565b90611f77866001614086565b611f8290604161406f565b92611f8f93929190614099565b91509150600080611fd68785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c6b92505050565b90925090506000816004811115611fef57611fef6138b1565b14612008576000600198509850505050505050506120b5565b8573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161161204f576000600298509850505050505050506120b5565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205460ff16612090576000600398509850505050505050506120b5565b5093508291506120a1905081613b9d565b915050611f3b565b50600160009350935050505b935093915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756120e7816126b5565b600180547fffffffffffffffffffffff0000000000000000000000000000000000000000ff1661010073ffffffffffffffffffffffffffffffffffffffff8516908102919091179091556040519081527f1399be28223800f8669b3ba5f8721d9fc16fc4e8d0bbf98378791c8c5a3015e0906020016113d3565b817f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8114806121af57507f4270fae16c6d150d00e80b689daca99e8073b1838ff2b6063a37be9d851283e481145b806121d957507f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de81145b156122325730331461222d5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b612282565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758103610d525761222d7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756126b5565b610da48383612cb0565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756122b6816126b5565b73ffffffffffffffffffffffffffffffffffffffff841660009081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff1661234a5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a20496e76616c6964206d657373616765206c69620000006044820152606401610a37565b6040517f07b18bde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490528516906307b18bde90604401600060405180830381600087803b1580156123ba57600080fd5b505af11580156123ce573d6000803e3d6000fd5b5050505050505050565b600085858386866040516020016123f39594939291906140c3565b60405160208183030381529060405280519060200120905095945050505050565b428160600135116124675760405162461bcd60e51b815260206004820152601160248201527f56657269666965723a20657870697265640000000000000000000000000000006044820152606401610a37565b306124786040830160208401613488565b73ffffffffffffffffffffffffffffffffffffffff16146124db5760405162461bcd60e51b815260206004820152601860248201527f56657269666965723a20696e76616c69642074617267657400000000000000006044820152606401610a37565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000000001661250f6020830183613769565b63ffffffff16146125625760405162461bcd60e51b815260206004820152601560248201527f56657269666965723a20696e76616c69642076696400000000000000000000006044820152606401610a37565b60006125746116f06020840184613769565b905060006125898261078d6080860186613df5565b509050806125d95760405162461bcd60e51b815260206004820152601c60248201527f56657269666965723a20696e76616c6964207369676e617475726573000000006044820152606401610a37565b60008281526006602052604090205460ff16156126385760405162461bcd60e51b815260206004820152601b60248201527f56657269666965723a206861736820616c7265616479207573656400000000006044820152606401610a37565b6000828152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610da4907fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775906126a390860186613df5565b8101906126b09190613488565b612795565b6114378133612d75565b6126c7612e13565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b612746612e68565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612714565b7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca821480156127f2575060008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16155b15612851576001805460159061282a907501000000000000000000000000000000000000000000900467ffffffffffffffff16614135565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b610b408282612eba565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205481151560ff9091161515036128fe5760405162461bcd60e51b815260206004820152602660248201527f4d756c74695369673a207369676e657220616c726561647920696e207468617460448201527f20737461746500000000000000000000000000000000000000000000000000006064820152608401610a37565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821515179055806129705760045461296b9060019067ffffffffffffffff1661415c565b612988565b6004546129889067ffffffffffffffff166001614184565b600480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92831690811791829055680100000000000000009091049091161115612a445760405162461bcd60e51b8152602060048201526024808201527f4d756c74695369673a20636f6d6d69747465652073697a65203c20746872657360448201527f686f6c64000000000000000000000000000000000000000000000000000000006064820152608401610a37565b6040805173ffffffffffffffffffffffffffffffffffffffff8416815282151560208201527f863d338cad74814b108a06288ad5e0e80d56495e0332238b1d2cdcfa0ca8e5ce91016113d3565b60045467ffffffffffffffff90811690821611801590612abb575060008167ffffffffffffffff16115b612b075760405162461bcd60e51b815260206004820152601860248201527f4d756c74695369673a20696e76616c69642071756f72756d00000000000000006044820152606401610a37565b600480547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff8416908102919091179091556040519081527fb600f3cf7f38a4b49bb0c75f722ef69f7e3e39ef3bb4aa8207fd86e724a232499060200160405180910390a150565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0223536e0000000000000000000000000000000000000000000000000000000014801590612c1857507fffffffff0000000000000000000000000000000000000000000000000000000082167fb724b1330000000000000000000000000000000000000000000000000000000014155b801561097757507fffffffff0000000000000000000000000000000000000000000000000000000082167f704316e500000000000000000000000000000000000000000000000000000000141592915050565b6000808251604103612ca15760208301516040840151606085015160001a612c9587828585612faa565b94509450505050612ca9565b506000905060025b9250929050565b7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca82148015612d0c575060008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff165b15612d6b5760018054601590612d44907501000000000000000000000000000000000000000000900467ffffffffffffffff166141a5565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b610b408282613099565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b4057612db381613150565b612dbe83602061316f565b604051602001612dcf9291906141e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905262461bcd60e51b8252610a3791600401614268565b60015460ff1615612e665760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b565b60015460ff16612e665760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a37565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b405760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612f4c3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612fe15750600090506003613090565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613035573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661308957600060019250925050613090565b9150600090505b94509492505050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610b405760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b606061097773ffffffffffffffffffffffffffffffffffffffff831660145b6060600061317e83600261406f565b613189906002614086565b67ffffffffffffffff8111156131a1576131a161427b565b6040519080825280601f01601f1916602001820160405280156131cb576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061320257613202613b04565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061326557613265613b04565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006132a184600261406f565b6132ac906001614086565b90505b6001811115613349577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106132ed576132ed613b04565b1a60f81b82828151811061330357613303613b04565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93613342816142aa565b90506132af565b5083156133985760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a37565b9392505050565b6000602082840312156133b157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461339857600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461143757600080fd5b60008060006060848603121561341857600080fd5b8335613423816133e1565b92506020840135613433816133e1565b929592945050506040919091013590565b80358015158114610c2c57600080fd5b60006020828403121561346657600080fd5b61339882613444565b60006020828403121561348157600080fd5b5035919050565b60006020828403121561349a57600080fd5b8135613398816133e1565b600080604083850312156134b857600080fd5b8235915060208301356134ca816133e1565b809150509250929050565b803563ffffffff81168114610c2c57600080fd5b803567ffffffffffffffff81168114610c2c57600080fd5b60008083601f84011261351357600080fd5b50813567ffffffffffffffff81111561352b57600080fd5b602083019150836020828501011115612ca957600080fd5b60008060008060006080868803121561355b57600080fd5b613564866134d5565b9450613572602087016134e9565b93506040860135613582816133e1565b9250606086013567ffffffffffffffff81111561359e57600080fd5b6135aa88828901613501565b969995985093965092949392505050565b600080604083850312156135ce57600080fd5b82356135d9816133e1565b91506135e760208401613444565b90509250929050565b6000806020838503121561360357600080fd5b823567ffffffffffffffff8082111561361b57600080fd5b818501915085601f83011261362f57600080fd5b81358181111561363e57600080fd5b8660208260071b850101111561365357600080fd5b60209290920196919550909350505050565b803561ffff81168114610c2c57600080fd5b6000806000806080858703121561368d57600080fd5b61369685613665565b93506136a460208601613665565b92506136b2604086016134e9565b915060608501356136c2816133e1565b939692955090935050565b6000602082840312156136df57600080fd5b613398826134e9565b600060a082840312156136fa57600080fd5b50919050565b60008060006040848603121561371557600080fd5b833567ffffffffffffffff8082111561372d57600080fd5b613739878388016136e8565b9450602086013591508082111561374f57600080fd5b5061375c86828701613501565b9497909650939450505050565b60006020828403121561377b57600080fd5b613398826134d5565b6000806020838503121561379757600080fd5b823567ffffffffffffffff808211156137af57600080fd5b818501915085601f8301126137c357600080fd5b8135818111156137d257600080fd5b8660208260051b850101111561365357600080fd5b6000806000806000608086880312156137ff57600080fd5b853561380a816133e1565b9450602086013567ffffffffffffffff81111561382657600080fd5b61383288828901613501565b9095509350506040860135915061384b606087016134e9565b90509295509295909350565b60006020828403121561386957600080fd5b61339882613665565b60008060006040848603121561388757600080fd5b83359250602084013567ffffffffffffffff8111156138a557600080fd5b61375c86828701613501565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82151581526040810160048310613920577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8260208301529392505050565b60008060008060006080868803121561394557600080fd5b61394e866134d5565b9450602086013561395e816133e1565b9350604086013567ffffffffffffffff81111561397a57600080fd5b61398688828901613501565b96999598509660600135949350505050565b6000602082840312156139aa57600080fd5b813567ffffffffffffffff8111156139c157600080fd5b6139cd848285016136e8565b949350505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6000610140613a96838873ffffffffffffffffffffffffffffffffffffffff80825116835263ffffffff6020830151166020840152604082015167ffffffffffffffff808216604086015282606085015116606086015280608085015116608086015250505061ffff60a08201511660a08301525050565b613ad760c08401875467ffffffffffffffff81168252604081811c61ffff16602084015260509190911c6fffffffffffffffffffffffffffffffff16910152565b8061012084015261132f81840185876139d5565b600060208284031215613afd57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80356fffffffffffffffffffffffffffffffff81168114610c2c57600080fd5b600060208284031215613b6557600080fd5b61339882613b33565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613bce57613bce613b6e565b5060010190565b6020808252818101839052600090604080840186845b87811015613c665763ffffffff613c01836134d5565b16835267ffffffffffffffff613c188684016134e9565b168584015261ffff613c2b858401613665565b168484015260606fffffffffffffffffffffffffffffffff613c4e828501613b33565b16908401526080928301929190910190600101613beb565b5090979650505050505050565b60005b83811015613c8e578181015183820152602001613c76565b50506000910152565b60008151808452613caf816020860160208601613c73565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000610140613d59838773ffffffffffffffffffffffffffffffffffffffff80825116835263ffffffff6020830151166020840152604082015167ffffffffffffffff808216604086015282606085015116606086015280608085015116608086015250505061ffff60a08201511660a08301525050565b613d9a60c08401865467ffffffffffffffff81168252604081811c61ffff16602084015260509190911c6fffffffffffffffffffffffffffffffff16910152565b80610120840152613dad81840185613c97565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112613deb57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e2a57600080fd5b83018035915067ffffffffffffffff821115613e4557600080fd5b602001915036819003821315612ca957600080fd5b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015613e9a5780818660040360031b1b83161692505b505092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ed757600080fd5b830160208101925035905067ffffffffffffffff811115613ef757600080fd5b803603821315612ca957600080fd5b6040815263ffffffff613f18846134d5565b16604082015260006020840135613f2e816133e1565b73ffffffffffffffffffffffffffffffffffffffff166060830152613f566040850185613ea2565b60a06080850152613f6b60e0850182846139d5565b915050606085013560a0840152613f856080860186613ea2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160c0860152613fba8382846139d5565b93505050508260208301529392505050565b8183823760009101908152919050565b8281526040602082015260006139cd6040830184613c97565b6060815260006140096060830186886139d5565b905083602083015267ffffffffffffffff8316604083015295945050505050565b60408152600061403e6040830185876139d5565b9050826020830152949350505050565b60006020828403121561406057600080fd5b81516004811061339857600080fd5b808202811582820484141761097757610977613b6e565b8082018082111561097757610977613b6e565b600080858511156140a957600080fd5b838611156140b657600080fd5b5050820193919092039150565b7fffffffff000000000000000000000000000000000000000000000000000000008660e01b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1660048201528360188201528183603883013760009101603801908152949350505050565b600067ffffffffffffffff80831681810361415257614152613b6e565b6001019392505050565b67ffffffffffffffff82811682821603908082111561417d5761417d613b6e565b5092915050565b67ffffffffffffffff81811683821601908082111561417d5761417d613b6e565b600067ffffffffffffffff8216806141bf576141bf613b6e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161421f816017850160208801613c73565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161425c816028840160208801613c73565b01602801949350505050565b6020815260006133986020830184613c97565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000816142b9576142b9613b6e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea264697066735822122076e64814c856bd3a1ecb8bea8b296bbc2955b981255a6e68e6830e81af20ea8b64736f6c63430008130033000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000036480409859f812e8a78659002a461e46971a40500000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000010000000000000000000000004d73adb72bc3dd368966edd0f0b2148401a178e200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000d099360a069359fe7c9503ab44cbcb9eb2a746600000000000000000000000094bc8ba19b4cce7aac14e2679942fc567e027c67000000000000000000000000ddbdc840164da20bcf6aa85c3957396c14642ab100000000000000000000000000000000000000000000000000000000000000030000000000000000000000005ee2b0fd8d964cb50e787db4ff176d7bbb0fd1800000000000000000000000005b1dad86c9c4ae282bbabbe89c5f6231c065c23600000000000000000000000021c3de23d98caddc406e3d31b25e807addf33633

Deployed Bytecode

0x6080604052600436106102695760003560e01c806391d1485411610153578063c5e193cd116100cb578063d547741f1161007f578063f010cb2311610064578063f010cb2314610883578063f3b4ebd0146108a3578063fd62e750146108c357600080fd5b8063d547741f14610843578063dafe0ccc1461086357600080fd5b8063c7b2370b116100b0578063c7b2370b146107a0578063cf34c768146107c0578063d2ae21041461080957600080fd5b8063c5e193cd14610752578063c7a823e01461077257600080fd5b8063aef18bf711610122578063b724b13311610107578063b724b133146106e0578063c358de0a14610700578063c416aa511461072057600080fd5b8063aef18bf714610690578063b143044b146106c057600080fd5b806391d148541461057257806395d376d7146105c35780639e944965146105d6578063a217fddf1461067b57600080fd5b806331cb6105116101e65780635c975abb116101b5578063736c0d5b1161019a578063736c0d5b146104d0578063741bef1a146105005780638585c9451461055257600080fd5b80635c975abb14610498578063724e78da146104b057600080fd5b806331cb61051461041857806336568abe1461043857806352d3b871146104585780635553fb8e1461047857600080fd5b80631703a0181161023d5780632de11376116102225780632de11376146103b85780632f2ff15d146103d857806330bb3aac146103f857600080fd5b80631703a01814610334578063248a9ca31461037a57600080fd5b8062bf2e801461026e57806301ffc9a7146102c25780631095b6d7146102f257806316c38b3c14610314575b600080fd5b34801561027a57600080fd5b506001546102aa907d010000000000000000000000000000000000000000000000000000000000900461ffff1681565b60405161ffff90911681526020015b60405180910390f35b3480156102ce57600080fd5b506102e26102dd36600461339f565b6108e4565b60405190151581526020016102b9565b3480156102fe57600080fd5b5061031261030d366004613403565b61097d565b005b34801561032057600080fd5b5061031261032f366004613454565b610b27565b34801561034057600080fd5b506004546103619068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016102b9565b34801561038657600080fd5b506103aa61039536600461346f565b60009081526020819052604090206001015490565b6040519081526020016102b9565b3480156103c457600080fd5b506102e26103d3366004613488565b610b4c565b3480156103e457600080fd5b506103126103f33660046134a5565b610c31565b34801561040457600080fd5b506103aa610413366004613543565b610da9565b34801561042457600080fd5b506103126104333660046135bb565b610f36565b34801561044457600080fd5b506103126104533660046134a5565b610f8f565b34801561046457600080fd5b506103126104733660046135f0565b610fd7565b34801561048457600080fd5b506103aa610493366004613677565b6111ab565b3480156104a457600080fd5b5060015460ff166102e2565b3480156104bc57600080fd5b506103126104cb366004613488565b61133a565b3480156104dc57600080fd5b506102e26104eb366004613488565b60036020526000908152604090205460ff1681565b34801561050c57600080fd5b5060025461052d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102b9565b34801561055e57600080fd5b5061031261056d3660046136cd565b6113df565b34801561057e57600080fd5b506102e261058d3660046134a5565b60009182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6103aa6105d1366004613700565b61143a565b3480156105e257600080fd5b506106406105f1366004613769565b60056020526000908152604090205467ffffffffffffffff81169068010000000000000000810461ffff16906a010000000000000000000090046fffffffffffffffffffffffffffffffff1683565b6040805167ffffffffffffffff909416845261ffff90921660208401526fffffffffffffffffffffffffffffffff16908201526060016102b9565b34801561068757600080fd5b506103aa600081565b34801561069c57600080fd5b506102e26106ab36600461346f565b60066020526000908152604090205460ff1681565b3480156106cc57600080fd5b506103126106db366004613784565b61162c565b3480156106ec57600080fd5b506103126106fb3660046137e7565b61194a565b34801561070c57600080fd5b5061031261071b366004613857565b611bfd565b34801561072c57600080fd5b5060015461052d90610100900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561075e57600080fd5b506103aa61076d366004613677565b611cab565b34801561077e57600080fd5b5061079261078d366004613872565b611ea1565b6040516102b99291906138e0565b3480156107ac57600080fd5b506103126107bb366004613488565b6120bd565b3480156107cc57600080fd5b506107f47f000000000000000000000000000000000000000000000000000000000000007081565b60405163ffffffff90911681526020016102b9565b34801561081557600080fd5b50600154610361907501000000000000000000000000000000000000000000900467ffffffffffffffff1681565b34801561084f57600080fd5b5061031261085e3660046134a5565b612161565b34801561086f57600080fd5b5061031261087e366004613403565b61228c565b34801561088f57600080fd5b506103aa61089e36600461392d565b6123d8565b3480156108af57600080fd5b506103126108be366004613998565b612414565b3480156108cf57600080fd5b506004546103619067ffffffffffffffff1681565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061097757507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109a7816126b5565b73ffffffffffffffffffffffffffffffffffffffff841660009081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff16610a405760405162461bcd60e51b815260206004820152601b60248201527f576f726b65723a20496e76616c6964206d657373616765206c6962000000000060448201526064015b60405180910390fd5b6040517ffd9be52200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526024820184905285169063fd9be52290604401600060405180830381600087803b158015610ab057600080fd5b505af1158015610ac4573d6000803e3d6000fd5b50506040805173ffffffffffffffffffffffffffffffffffffffff8089168252871660208201529081018590527f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb9250606001905060405180910390a150505050565b6000610b32816126b5565b8115610b4457610b406126bf565b5050565b610b4061273e565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f93c430521711328044ae92d0f1f1286cf040bc4a382f1642bd89984e86630553602052604081205460ff1615610ba157506000919050565b6001547501000000000000000000000000000000000000000000900467ffffffffffffffff161580610c17575073ffffffffffffffffffffffffffffffffffffffff821660009081527f4ac82e3087b7dedf7f532cbc6915c722df8c1e31f1388c318a617b52760eaf8b602052604090205460ff165b15610c2457506001919050565b506000919050565b919050565b817f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca811480610c7f57507f4270fae16c6d150d00e80b689daca99e8073b1838ff2b6063a37be9d851283e481145b80610ca957507f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de81145b15610d0257303314610cfd5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b610d9a565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758103610d5257610cfd7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756126b5565b60405162461bcd60e51b815260206004820152601660248201527f56657269666965723a20696e76616c696420726f6c65000000000000000000006044820152606401610a37565b610da48383612795565b505050565b600083610db581610b4c565b610e015760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c08101825260025473ffffffffffffffffffffffffffffffffffffffff908116825263ffffffff8a16602080840182905267ffffffffffffffff808c16858701528a8416606086015260048054680100000000000000009004909116608086015260015461ffff7d01000000000000000000000000000000000000000000000000000000000082041660a0870152600093845260059092529185902094517f7bfa20a9000000000000000000000000000000000000000000000000000000008152939461010090910490921692637bfa20a992610ee99286928b918b9101613a1e565b602060405180830381865afa158015610f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2a9190613aeb565b98975050505050505050565b303314610f855760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b610b40828261285b565b60405162461bcd60e51b815260206004820152601c60248201527f576f726b65723a2063616e6e6f742072656e6f756e636520726f6c65000000006044820152606401610a37565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611001816126b5565b60005b8281101561116c573684848381811061101f5761101f613b04565b9050608002019050604051806060016040528082602001602081019061104591906136cd565b67ffffffffffffffff1681526020016110646060840160408501613857565b61ffff16815260200161107d6080840160608501613b53565b6fffffffffffffffffffffffffffffffff169052600560006110a26020850185613769565b63ffffffff1681526020808201929092526040908101600020835181549385015194909201516fffffffffffffffffffffffffffffffff166a0100000000000000000000027fffffffffffff00000000000000000000000000000000ffffffffffffffffffff61ffff90951668010000000000000000027fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000090941667ffffffffffffffff9093169290921792909217929092169190911790555061116581613b9d565b9050611004565b507f7dd21e42791b013d1929e86f0c59085e4fca24251f0f1aa81917b3b1611766e0838360405161119e929190613bd5565b60405180910390a1505050565b6000816111b781610b4c565b6112035760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c08101825260025473ffffffffffffffffffffffffffffffffffffffff908116825261ffff808a16602080850182905267ffffffffffffffff808b168688015289851660608701526004805468010000000000000000900490911660808701526001547d010000000000000000000000000000000000000000000000000000000000810490941660a08701526000928352600582528683208751928301885292825295517f7bfa20a9000000000000000000000000000000000000000000000000000000008152949561010090930490931693637bfa20a9936112ee9387939201613ce1565b602060405180830381865afa15801561130b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132f9190613aeb565b979650505050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611364816126b5565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091556040519081527ff724a45d041687842411f2b977ef22ab8f43c8f1104f4592b42a00f9b34a643d906020015b60405180910390a15050565b30331461142e5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b61143781612a91565b50565b60007f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de611466816126b5565b61147660a0860160808701613488565b61147f81610b4c565b6114cb5760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c0810190915260025473ffffffffffffffffffffffffffffffffffffffff168152600090602080820190611506908a018a613769565b63ffffffff16815260200161152160808a0160608b016136cd565b67ffffffffffffffff16815260200161154060a08a0160808b01613488565b73ffffffffffffffffffffffffffffffffffffffff908116825260045468010000000000000000900467ffffffffffffffff166020808401919091526001547d010000000000000000000000000000000000000000000000000000000000810461ffff16604090940193909352929350610100909104169063df2b057e9083906005906000906115d2908d018d613769565b63ffffffff1663ffffffff16815260200190815260200160002089896040518563ffffffff1660e01b815260040161160d9493929190613a1e565b6020604051808303816000875af115801561130b573d6000803e3d6000fd5b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611656816126b5565b60005b82811015611944573684848381811061167457611674613b04565b90506020028101906116869190613db7565b905063ffffffff7f0000000000000000000000000000000000000000000000000000000000000070166116bc6020830183613769565b63ffffffff16146116cd5750611934565b428160600135116116de5750611934565b60006117176116f06020840184613769565b6117006040850160208601613488565b61170d6040860186613df5565b86606001356123d8565b9050600061172c8261078d6080860186613df5565b5090508061176f576040518481527fd6d90193101048cc1b6edcdc2348f5acf7a4a4a97d3e7b668b74cb7602ab3ebc9060200160405180910390a1505050611934565b600061178f6117816040860186613df5565b61178a91613e5a565b612b82565b905080156118285760008381526006602052604090205460ff16156117f0577f9bb9bddbdf537a2104255307230b323d7982f4512ee8e5bd15df62ddca50ab9784846040516117df929190613f06565b60405180910390a150505050611934565b600083815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008061183b6040870160208801613488565b73ffffffffffffffffffffffffffffffffffffffff1661185e6040880188613df5565b60405161186c929190613fcc565b6000604051808303816000865af19150503d80600081146118a9576040519150601f19603f3d011682016040523d82523d6000602084013e6118ae565b606091505b50915091508161192d5782156118f357600085815260066020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b7fdc8cdd96296241bbefda4a8e18ad2e0985a8da6495b34d409cfc4c886ee3b0cf8782604051611924929190613fdc565b60405180910390a15b5050505050505b61193d81613b9d565b9050611659565b50505050565b3033146119995760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b73ffffffffffffffffffffffffffffffffffffffff851660009081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff16611a2d5760405162461bcd60e51b815260206004820152601560248201527f56657269666965723a20696e76616c696420756c6e00000000000000000000006044820152606401610a37565b6040517f0223536e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861690630223536e90611a85908790879087908790600401613ff5565b600060405180830381600087803b158015611a9f57600080fd5b505af1158015611ab3573d6000803e3d6000fd5b5060019250611ac0915050565b6040517f7c0cf76300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690637c0cf76390611b169088908890889060040161402a565b602060405180830381865afa158015611b33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b57919061404e565b6003811115611b6857611b686138b1565b03611bf6576040517f5ed31c5900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff861690635ed31c5990611bc39087908790879060040161402a565b600060405180830381600087803b158015611bdd57600080fd5b505af1158015611bf1573d6000803e3d6000fd5b505050505b5050505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611c27816126b5565b600180547fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d01000000000000000000000000000000000000000000000000000000000061ffff8516908102919091179091556040519081527f7af0ac740036ffb1c97b03697859d729e80a44ae5030543d64971c313565ab4d906020016113d3565b60007f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de611cd7816126b5565b82611ce181610b4c565b611d2d5760405162461bcd60e51b815260206004820152601360248201527f576f726b65723a206e6f7420616c6c6f776564000000000000000000000000006044820152606401610a37565b6040805160c08101825260025473ffffffffffffffffffffffffffffffffffffffff908116825261ffff808b16602080850182905267ffffffffffffffff808c16868801528a851660608701526004805468010000000000000000900490911660808701526001547d010000000000000000000000000000000000000000000000000000000000810490941660a08701526000928352600582528683208751928301885292825295517fdf2b057e00000000000000000000000000000000000000000000000000000000815294956101009093049093169363df2b057e93611e189387939201613ce1565b6020604051808303816000875af1158015611e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5b9190613aeb565b93507f87e46b0a6199bc734632187269a103c05714ee0adae5b28f30723955724f37ef84604051611e8e91815260200190565b60405180910390a1505050949350505050565b6004546000908190611eca9068010000000000000000900467ffffffffffffffff16604161406f565b8314611edc57506000905060016120b5565b6000611f35866040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b90506000805b60045468010000000000000000900467ffffffffffffffff168110156120a9573660008888611f6b85604161406f565b90611f77866001614086565b611f8290604161406f565b92611f8f93929190614099565b91509150600080611fd68785858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c6b92505050565b90925090506000816004811115611fef57611fef6138b1565b14612008576000600198509850505050505050506120b5565b8573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161161204f576000600298509850505050505050506120b5565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205460ff16612090576000600398509850505050505050506120b5565b5093508291506120a1905081613b9d565b915050611f3b565b50600160009350935050505b935093915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756120e7816126b5565b600180547fffffffffffffffffffffff0000000000000000000000000000000000000000ff1661010073ffffffffffffffffffffffffffffffffffffffff8516908102919091179091556040519081527f1399be28223800f8669b3ba5f8721d9fc16fc4e8d0bbf98378791c8c5a3015e0906020016113d3565b817f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8114806121af57507f4270fae16c6d150d00e80b689daca99e8073b1838ff2b6063a37be9d851283e481145b806121d957507f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de81145b156122325730331461222d5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a2063616c6c6572206d7573742062652073656c660000006044820152606401610a37565b612282565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758103610d525761222d7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756126b5565b610da48383612cb0565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756122b6816126b5565b73ffffffffffffffffffffffffffffffffffffffff841660009081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff1661234a5760405162461bcd60e51b815260206004820152601d60248201527f56657269666965723a20496e76616c6964206d657373616765206c69620000006044820152606401610a37565b6040517f07b18bde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490528516906307b18bde90604401600060405180830381600087803b1580156123ba57600080fd5b505af11580156123ce573d6000803e3d6000fd5b5050505050505050565b600085858386866040516020016123f39594939291906140c3565b60405160208183030381529060405280519060200120905095945050505050565b428160600135116124675760405162461bcd60e51b815260206004820152601160248201527f56657269666965723a20657870697265640000000000000000000000000000006044820152606401610a37565b306124786040830160208401613488565b73ffffffffffffffffffffffffffffffffffffffff16146124db5760405162461bcd60e51b815260206004820152601860248201527f56657269666965723a20696e76616c69642074617267657400000000000000006044820152606401610a37565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000000701661250f6020830183613769565b63ffffffff16146125625760405162461bcd60e51b815260206004820152601560248201527f56657269666965723a20696e76616c69642076696400000000000000000000006044820152606401610a37565b60006125746116f06020840184613769565b905060006125898261078d6080860186613df5565b509050806125d95760405162461bcd60e51b815260206004820152601c60248201527f56657269666965723a20696e76616c6964207369676e617475726573000000006044820152606401610a37565b60008281526006602052604090205460ff16156126385760405162461bcd60e51b815260206004820152601b60248201527f56657269666965723a206861736820616c7265616479207573656400000000006044820152606401610a37565b6000828152600660205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610da4907fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775906126a390860186613df5565b8101906126b09190613488565b612795565b6114378133612d75565b6126c7612e13565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b612746612e68565b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612714565b7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca821480156127f2575060008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16155b15612851576001805460159061282a907501000000000000000000000000000000000000000000900467ffffffffffffffff16614135565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b610b408282612eba565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205481151560ff9091161515036128fe5760405162461bcd60e51b815260206004820152602660248201527f4d756c74695369673a207369676e657220616c726561647920696e207468617460448201527f20737461746500000000000000000000000000000000000000000000000000006064820152608401610a37565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016821515179055806129705760045461296b9060019067ffffffffffffffff1661415c565b612988565b6004546129889067ffffffffffffffff166001614184565b600480547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff92831690811791829055680100000000000000009091049091161115612a445760405162461bcd60e51b8152602060048201526024808201527f4d756c74695369673a20636f6d6d69747465652073697a65203c20746872657360448201527f686f6c64000000000000000000000000000000000000000000000000000000006064820152608401610a37565b6040805173ffffffffffffffffffffffffffffffffffffffff8416815282151560208201527f863d338cad74814b108a06288ad5e0e80d56495e0332238b1d2cdcfa0ca8e5ce91016113d3565b60045467ffffffffffffffff90811690821611801590612abb575060008167ffffffffffffffff16115b612b075760405162461bcd60e51b815260206004820152601860248201527f4d756c74695369673a20696e76616c69642071756f72756d00000000000000006044820152606401610a37565b600480547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000067ffffffffffffffff8416908102919091179091556040519081527fb600f3cf7f38a4b49bb0c75f722ef69f7e3e39ef3bb4aa8207fd86e724a232499060200160405180910390a150565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0223536e0000000000000000000000000000000000000000000000000000000014801590612c1857507fffffffff0000000000000000000000000000000000000000000000000000000082167fb724b1330000000000000000000000000000000000000000000000000000000014155b801561097757507fffffffff0000000000000000000000000000000000000000000000000000000082167f704316e500000000000000000000000000000000000000000000000000000000141592915050565b6000808251604103612ca15760208301516040840151606085015160001a612c9587828585612faa565b94509450505050612ca9565b506000905060025b9250929050565b7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca82148015612d0c575060008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff165b15612d6b5760018054601590612d44907501000000000000000000000000000000000000000000900467ffffffffffffffff166141a5565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b610b408282613099565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b4057612db381613150565b612dbe83602061316f565b604051602001612dcf9291906141e7565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905262461bcd60e51b8252610a3791600401614268565b60015460ff1615612e665760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610a37565b565b60015460ff16612e665760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610a37565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610b405760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055612f4c3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115612fe15750600090506003613090565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613035573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661308957600060019250925050613090565b9150600090505b94509492505050565b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610b405760008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b606061097773ffffffffffffffffffffffffffffffffffffffff831660145b6060600061317e83600261406f565b613189906002614086565b67ffffffffffffffff8111156131a1576131a161427b565b6040519080825280601f01601f1916602001820160405280156131cb576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061320257613202613b04565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f78000000000000000000000000000000000000000000000000000000000000008160018151811061326557613265613b04565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006132a184600261406f565b6132ac906001614086565b90505b6001811115613349577f303132333435363738396162636465660000000000000000000000000000000085600f16601081106132ed576132ed613b04565b1a60f81b82828151811061330357613303613b04565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c93613342816142aa565b90506132af565b5083156133985760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610a37565b9392505050565b6000602082840312156133b157600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461339857600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461143757600080fd5b60008060006060848603121561341857600080fd5b8335613423816133e1565b92506020840135613433816133e1565b929592945050506040919091013590565b80358015158114610c2c57600080fd5b60006020828403121561346657600080fd5b61339882613444565b60006020828403121561348157600080fd5b5035919050565b60006020828403121561349a57600080fd5b8135613398816133e1565b600080604083850312156134b857600080fd5b8235915060208301356134ca816133e1565b809150509250929050565b803563ffffffff81168114610c2c57600080fd5b803567ffffffffffffffff81168114610c2c57600080fd5b60008083601f84011261351357600080fd5b50813567ffffffffffffffff81111561352b57600080fd5b602083019150836020828501011115612ca957600080fd5b60008060008060006080868803121561355b57600080fd5b613564866134d5565b9450613572602087016134e9565b93506040860135613582816133e1565b9250606086013567ffffffffffffffff81111561359e57600080fd5b6135aa88828901613501565b969995985093965092949392505050565b600080604083850312156135ce57600080fd5b82356135d9816133e1565b91506135e760208401613444565b90509250929050565b6000806020838503121561360357600080fd5b823567ffffffffffffffff8082111561361b57600080fd5b818501915085601f83011261362f57600080fd5b81358181111561363e57600080fd5b8660208260071b850101111561365357600080fd5b60209290920196919550909350505050565b803561ffff81168114610c2c57600080fd5b6000806000806080858703121561368d57600080fd5b61369685613665565b93506136a460208601613665565b92506136b2604086016134e9565b915060608501356136c2816133e1565b939692955090935050565b6000602082840312156136df57600080fd5b613398826134e9565b600060a082840312156136fa57600080fd5b50919050565b60008060006040848603121561371557600080fd5b833567ffffffffffffffff8082111561372d57600080fd5b613739878388016136e8565b9450602086013591508082111561374f57600080fd5b5061375c86828701613501565b9497909650939450505050565b60006020828403121561377b57600080fd5b613398826134d5565b6000806020838503121561379757600080fd5b823567ffffffffffffffff808211156137af57600080fd5b818501915085601f8301126137c357600080fd5b8135818111156137d257600080fd5b8660208260051b850101111561365357600080fd5b6000806000806000608086880312156137ff57600080fd5b853561380a816133e1565b9450602086013567ffffffffffffffff81111561382657600080fd5b61383288828901613501565b9095509350506040860135915061384b606087016134e9565b90509295509295909350565b60006020828403121561386957600080fd5b61339882613665565b60008060006040848603121561388757600080fd5b83359250602084013567ffffffffffffffff8111156138a557600080fd5b61375c86828701613501565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82151581526040810160048310613920577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8260208301529392505050565b60008060008060006080868803121561394557600080fd5b61394e866134d5565b9450602086013561395e816133e1565b9350604086013567ffffffffffffffff81111561397a57600080fd5b61398688828901613501565b96999598509660600135949350505050565b6000602082840312156139aa57600080fd5b813567ffffffffffffffff8111156139c157600080fd5b6139cd848285016136e8565b949350505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b6000610140613a96838873ffffffffffffffffffffffffffffffffffffffff80825116835263ffffffff6020830151166020840152604082015167ffffffffffffffff808216604086015282606085015116606086015280608085015116608086015250505061ffff60a08201511660a08301525050565b613ad760c08401875467ffffffffffffffff81168252604081811c61ffff16602084015260509190911c6fffffffffffffffffffffffffffffffff16910152565b8061012084015261132f81840185876139d5565b600060208284031215613afd57600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80356fffffffffffffffffffffffffffffffff81168114610c2c57600080fd5b600060208284031215613b6557600080fd5b61339882613b33565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613bce57613bce613b6e565b5060010190565b6020808252818101839052600090604080840186845b87811015613c665763ffffffff613c01836134d5565b16835267ffffffffffffffff613c188684016134e9565b168584015261ffff613c2b858401613665565b168484015260606fffffffffffffffffffffffffffffffff613c4e828501613b33565b16908401526080928301929190910190600101613beb565b5090979650505050505050565b60005b83811015613c8e578181015183820152602001613c76565b50506000910152565b60008151808452613caf816020860160208601613c73565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6000610140613d59838773ffffffffffffffffffffffffffffffffffffffff80825116835263ffffffff6020830151166020840152604082015167ffffffffffffffff808216604086015282606085015116606086015280608085015116608086015250505061ffff60a08201511660a08301525050565b613d9a60c08401865467ffffffffffffffff81168252604081811c61ffff16602084015260509190911c6fffffffffffffffffffffffffffffffff16910152565b80610120840152613dad81840185613c97565b9695505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112613deb57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e2a57600080fd5b83018035915067ffffffffffffffff821115613e4557600080fd5b602001915036819003821315612ca957600080fd5b7fffffffff000000000000000000000000000000000000000000000000000000008135818116916004851015613e9a5780818660040360031b1b83161692505b505092915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613ed757600080fd5b830160208101925035905067ffffffffffffffff811115613ef757600080fd5b803603821315612ca957600080fd5b6040815263ffffffff613f18846134d5565b16604082015260006020840135613f2e816133e1565b73ffffffffffffffffffffffffffffffffffffffff166060830152613f566040850185613ea2565b60a06080850152613f6b60e0850182846139d5565b915050606085013560a0840152613f856080860186613ea2565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08584030160c0860152613fba8382846139d5565b93505050508260208301529392505050565b8183823760009101908152919050565b8281526040602082015260006139cd6040830184613c97565b6060815260006140096060830186886139d5565b905083602083015267ffffffffffffffff8316604083015295945050505050565b60408152600061403e6040830185876139d5565b9050826020830152949350505050565b60006020828403121561406057600080fd5b81516004811061339857600080fd5b808202811582820484141761097757610977613b6e565b8082018082111561097757610977613b6e565b600080858511156140a957600080fd5b838611156140b657600080fd5b5050820193919092039150565b7fffffffff000000000000000000000000000000000000000000000000000000008660e01b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1660048201528360188201528183603883013760009101603801908152949350505050565b600067ffffffffffffffff80831681810361415257614152613b6e565b6001019392505050565b67ffffffffffffffff82811682821603908082111561417d5761417d613b6e565b5092915050565b67ffffffffffffffff81811683821601908082111561417d5761417d613b6e565b600067ffffffffffffffff8216806141bf576141bf613b6e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161421f816017850160208801613c73565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000601791840191820152835161425c816028840160208801613c73565b01602801949350505050565b6020815260006133986020830184613c97565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000816142b9576142b9613b6e565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea264697066735822122076e64814c856bd3a1ecb8bea8b296bbc2955b981255a6e68e6830e81af20ea8b64736f6c63430008130033

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

000000000000000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000036480409859f812e8a78659002a461e46971a40500000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000010000000000000000000000004d73adb72bc3dd368966edd0f0b2148401a178e200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000d099360a069359fe7c9503ab44cbcb9eb2a746600000000000000000000000094bc8ba19b4cce7aac14e2679942fc567e027c67000000000000000000000000ddbdc840164da20bcf6aa85c3957396c14642ab100000000000000000000000000000000000000000000000000000000000000030000000000000000000000005ee2b0fd8d964cb50e787db4ff176d7bbb0fd1800000000000000000000000005b1dad86c9c4ae282bbabbe89c5f6231c065c23600000000000000000000000021c3de23d98caddc406e3d31b25e807addf33633

-----Decoded View---------------
Arg [0] : _vid (uint32): 112
Arg [1] : _messageLibs (address[]): 0x4D73AdB72bC3DD368966edD0f0b2148401A178E2
Arg [2] : _priceFeed (address): 0x36480409859f812e8a78659002A461E46971a405
Arg [3] : _signers (address[]): 0x0D099360A069359fE7c9503ab44cbCb9eB2A7466,0x94bC8Ba19b4CcE7AAc14E2679942fc567e027C67,0xDdBDC840164da20bCf6AA85C3957396C14642AB1
Arg [4] : _quorum (uint64): 2
Arg [5] : _admins (address[]): 0x5EE2B0fd8d964cB50e787DB4fF176D7bbb0fD180,0x5b1DaD86c9c4aE282BBAbbE89C5f6231C065c236,0x21C3de23d98Caddc406E3d31b25e807aDDF33633

-----Encoded View---------------
16 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000070
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 00000000000000000000000036480409859f812e8a78659002a461e46971a405
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 0000000000000000000000004d73adb72bc3dd368966edd0f0b2148401a178e2
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [9] : 0000000000000000000000000d099360a069359fe7c9503ab44cbcb9eb2a7466
Arg [10] : 00000000000000000000000094bc8ba19b4cce7aac14e2679942fc567e027c67
Arg [11] : 000000000000000000000000ddbdc840164da20bcf6aa85c3957396c14642ab1
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [13] : 0000000000000000000000005ee2b0fd8d964cb50e787db4ff176d7bbb0fd180
Arg [14] : 0000000000000000000000005b1dad86c9c4ae282bbabbe89c5f6231c065c236
Arg [15] : 00000000000000000000000021c3de23d98caddc406e3d31b25e807addf33633


Block Transaction Gas Used Reward
view all blocks produced

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

Validator Index Block Amount
View All Withdrawals

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

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