ETH Price: $2,091.28 (+2.52%)

Contract

0x9D9C82012E749451E551AFDB34a93bA1FC3CC2Ef
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw Fee235753302025-10-14 10:24:59168 days ago1760437499IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000082281.85918247
Execute302234900992025-10-02 12:28:23180 days ago1759408103IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000216710.43609558
Commit Verificat...234900942025-10-02 12:27:23180 days ago1759408043IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000046030.44534627
Execute302234900132025-10-02 12:10:59180 days ago1759407059IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.00006340.52767373
Commit Verificat...234900092025-10-02 12:10:11180 days ago1759407011IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000054320.52553586
Execute302234754692025-09-30 11:20:23182 days ago1759231223IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000147771.22976705
Commit Verificat...234754682025-09-30 11:20:11182 days ago1759231211IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000125261.21189561
Withdraw Fee234102182025-09-21 8:25:47191 days ago1758443147IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.00005171.16790183
Execute302233952692025-09-19 6:15:11193 days ago1758262511IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000092060.19165144
Commit Verificat...233952672025-09-19 6:14:47193 days ago1758262487IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000020360.19704315
Execute302233902912025-09-18 13:34:23194 days ago1758202463IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.001588573.30188042
Commit Verificat...233902882025-09-18 13:33:47194 days ago1758202427IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.00033813.27178603
Execute302233902842025-09-18 13:32:59194 days ago1758202379IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.001576473.27974801
Commit Verificat...233902812025-09-18 13:32:23194 days ago1758202343IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000319123.0873399
Execute302233832632025-09-17 14:01:23195 days ago1758117683IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000084670.7047262
Commit Verificat...233832622025-09-17 14:01:11195 days ago1758117671IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000070090.67809596
Execute302233832612025-09-17 14:00:59195 days ago1758117659IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000079350.66038552
Commit Verificat...233832572025-09-17 14:00:11195 days ago1758117611IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000066210.64063221
Execute302233832562025-09-17 13:59:59195 days ago1758117599IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000078140.65029594
Commit Verificat...233832552025-09-17 13:59:47195 days ago1758117587IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000065670.63536232
Execute302233832492025-09-17 13:58:35195 days ago1758117515IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000077230.64269781
Commit Verificat...233832482025-09-17 13:58:23195 days ago1758117503IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000066210.64065984
Execute302233820072025-09-17 9:48:47195 days ago1758102527IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000161580.32516795
Commit Verificat...233820032025-09-17 9:47:59195 days ago1758102479IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000031660.30636194
Execute302233812722025-09-17 7:21:23195 days ago1758093683IN
0x9D9C8201...1FC3CC2Ef
0 ETH0.000037050.30838951
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Executor

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 400 runs

Other Settings:
prague EvmVersion
// SPDX-License-Identifier: LZBL-1.2
// copied and modified from https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/messagelib/contracts/Executor.sol
pragma solidity ^0.8.24;
import {IExecutor} from "@layerzerolabs/lz-evm-messagelib-v2/contracts/interfaces/IExecutor.sol";
import {IExecutorFeeLib} from "@layerzerolabs/lz-evm-messagelib-v2/contracts/interfaces/IExecutorFeeLib.sol";
import {IReceiveUlnE2} from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/interfaces/IReceiveUlnE2.sol";
import {Origin, ILayerZeroEndpointV2} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import {PacketV1Codec} from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {ILayerZeroEndpointV2Extended} from "./interfaces/ILayerZeroEndpointV2Extended.sol";
import {IReceiveUlnView, VerificationState, ExecutionState} from "./interfaces/ILayerZeroReceiveUlnView.sol";
import {Worker} from "./Worker.sol";

/// @title Executor Contract.
/// @notice Executes LayerZero V2 operations and handles the job fee logic for messaging libraries.
/// @dev Extends `Worker`, `ReentrancyGuard`, and implements `IExecutor`.
contract Executor is Worker, ReentrancyGuard, IExecutor {
    using PacketV1Codec for bytes;

    /// @dev Represents an empty payload hash.
    bytes32 public constant EMPTY_PAYLOAD_HASH = bytes32(0);

    /// @dev Represents a nil (max value) payload hash.
    bytes32 public constant NIL_PAYLOAD_HASH = bytes32(type(uint256).max);

    /// @dev Configuration per destination endpoint ID.
    mapping(uint32 dstEid => DstConfig) public dstConfig;

    /// @dev LayerZero V2 endpoint address.
    address public immutable ENDPOINT;

    /// @dev Local endpoint ID for LayerZero V2.
    uint32 public immutable LOCAL_EID_V2;

    /// @dev LayerZero V2 ReceiveUln302 contract address.
    address public immutable RECEIVE_ULN302;

    /// @dev Error thrown when `commitVerification` is called with an invalid state (i.e. Packet not verifiable).
    error Executor_InvalidVerificationState();

    /**
     * @dev Initializes the Executor contract with endpoint, ULN302, admin, and libraries.
     * @param _endpoint Address of LayerZeroV2 endpoint contract.
     * @param _receiveUln302 LayerZeroV2 RecieveUln302 contract address to commit verifications.
     * @param _messageLibs Addresses of messaging fee libraries allowed for job assignment.
     * @param _priceFeed Address of price feed contract used for fee calculations.
     * @param _roleAdmin Address assigned `DEFAULT_ADMIN_ROLE`.
     * @param _admins Additional addresses to be granted `ADMIN_ROLE`.
     */
    constructor(
        address _endpoint,
        address _receiveUln302,
        address[] memory _messageLibs,
        address _priceFeed,
        address _roleAdmin,
        address[] memory _admins
    )
        Worker(_messageLibs, _priceFeed, 12000, _roleAdmin, _admins)
        notZeroAddress(_endpoint)
        notZeroAddress(_receiveUln302)
    {
        ENDPOINT = _endpoint;
        LOCAL_EID_V2 = ILayerZeroEndpointV2Extended(_endpoint).eid();
        RECEIVE_ULN302 = _receiveUln302;
    }

    /**
     * @dev Sets configuration parameters for multiple destination EIDs.
     * This function allows `ADMIN_ROLE` to set various parameters for each destination EID.
     * It updates the `dstConfig` mapping with new values for each destination EID.
     * @param _params Array of the `DstConfigParam` structs containing destination settings.
     * Emits a `DstConfigSet` event with the updated parameters.
     */
    function setDstConfig(DstConfigParam[] calldata _params) external onlyRole(_ADMIN_ROLE) {
        uint256 paramsLength = _params.length;
        for (uint256 i = 0; i < paramsLength; ++i) {
            // Write each destination config into the mapping, overwriting any previous value.
            DstConfigParam memory param = _params[i];
            dstConfig[param.dstEid] = DstConfig(
                param.lzReceiveBaseGas,
                param.multiplierBps,
                param.floorMarginUSD,
                param.nativeCap,
                param.lzComposeBaseGas
            );
        }
        emit DstConfigSet(_params);
    }

    /**
     * @dev Sends native tokens to specified addresses on the target chain.
     * It can only be called by an address with `ADMIN_ROLE` and is protected against reentrancy attacks.
     * @param _origin Origin information for the message context.
     * @param _dstEid Destination endpoint EID where native tokens should be dropped.
     * @param _oapp Address of the target OApp contract on the destination chain.
     * @param _nativeDropParams Array of `NativeDropParams` specifying receivers and amounts.
     * @param _nativeDropGasLimit Gas limit for each native transfer call.
     */
    function nativeDrop(
        Origin calldata _origin,
        uint32 _dstEid,
        address _oapp,
        NativeDropParams[] calldata _nativeDropParams,
        uint256 _nativeDropGasLimit
    ) external payable onlyRole(_ADMIN_ROLE) nonReentrant {
        // Internal call ensures an event is emitted and the total amount spent is tracked.
        _nativeDrop(_origin, _dstEid, _oapp, _nativeDropParams, _nativeDropGasLimit);
    }

    /**
     * @dev Commits a packet verification to the `ReceiveUln302` contract.
     * It checks the verification state of the packet header and payload hash.
     * If the packet is in a verifiable state, it commits the verification.
     * If the packet is in a verifying state, it reverts with a `LzExecutor_Verifying` error.
     * @param _packetHeader Encoded packet header bytes.
     * @param _payloadHash Keccak256 hash of the packet payload.
     */
    function commitVerification(
        bytes calldata _packetHeader,
        bytes32 _payloadHash
    ) external nonReentrant {
        VerificationState verificationState = verifiable(_packetHeader, _payloadHash);
        if (verificationState == VerificationState.Verifiable) {
            // Verification passed, commit to the verifier contract.
            IReceiveUlnE2(RECEIVE_ULN302).commitVerification(_packetHeader, _payloadHash);
        } else {
            // Revert if a Packet is still verifying or not verifiable.
            revert Executor_InvalidVerificationState();
        }
    }

    /**
     * @notice Executes LayerZero V2 receive logic (`lzReceive`).
     * @dev This function is used to execute messages received from LayerZero V2.
     * It wraps the call in a try/catch block to handle any errors that may occur.
     * @param _executionParams Struct containing `origin`, `receiver`, `guid`, `message`, `extraData`, and `gasLimit`.
     */
    function execute302(ExecutionParams calldata _executionParams) external payable nonReentrant {
        try
            ILayerZeroEndpointV2Extended(ENDPOINT).lzReceive{
                value: msg.value,
                gas: _executionParams.gasLimit
            }(
                _executionParams.origin,
                _executionParams.receiver,
                _executionParams.guid,
                _executionParams.message,
                _executionParams.extraData
            )
        // solhint-disable-next-line no-empty-blocks
        {
            // Do nothing.
        } catch (bytes memory reason) {
            // On error, call the alert method on the endpoint for logging.
            ILayerZeroEndpointV2Extended(ENDPOINT).lzReceiveAlert(
                _executionParams.origin,
                _executionParams.receiver,
                _executionParams.guid,
                _executionParams.gasLimit,
                msg.value,
                _executionParams.message,
                _executionParams.extraData,
                reason
            );
        }
    }

    /**
     * @notice Composes LayerZero V2 packets (lzCompose).
     * @dev This function is used to compose messages for LayerZero V2.
     * It wraps the call in a try/catch block to handle any errors that may occur.
     * @param _from Address from which the message originates.
     * @param _to Address to which the message is destined.
     * @param _guid Unique GUID for this message.
     * @param _index Sequence index for multi-packet messages.
     * @param _message Payload to send.
     * @param _extraData Additional data for the endpoint.
     * @param _gasLimit Gas limit provided for lzCompose.
     */
    function compose302(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index,
        bytes calldata _message,
        bytes calldata _extraData,
        uint256 _gasLimit
    ) external payable nonReentrant {
        try
            ILayerZeroEndpointV2Extended(ENDPOINT).lzCompose{value: msg.value, gas: _gasLimit}(
                _from,
                _to,
                _guid,
                _index,
                _message,
                _extraData
            )
        // solhint-disable-next-line no-empty-blocks
        {
            // Do nothing.
        } catch (bytes memory reason) {
            ILayerZeroEndpointV2Extended(ENDPOINT).lzComposeAlert(
                _from,
                _to,
                _guid,
                _index,
                _gasLimit,
                msg.value,
                _message,
                _extraData,
                reason
            );
        }
    }

    /**
     * @dev Executes a native drop then LayerZero V2 receive logic in a single transaction.
     * This function allows for a native drop to be performed before executing the LayerZero V2 receive logic.
     * It combines the native drop and lzReceive into a single transaction to save on gas
     * and ensure atomicity of the operations.
     * This function can only be called by an address with ADMIN_ROLE and is protected against reentrancy attacks.
     * @param _nativeDropParams Array of `NativeDropParams` for native drop.
     * @param _nativeDropGasLimit Gas limit for each native transfer.
     * @param _executionParams Struct containing parameters for `lzReceive`.
     */
    function nativeDropAndExecute302(
        NativeDropParams[] calldata _nativeDropParams,
        uint256 _nativeDropGasLimit,
        ExecutionParams calldata _executionParams
    ) external payable onlyRole(_ADMIN_ROLE) nonReentrant {
        // Spend as much of `msg.value` as needed for drops; leftover is used for receive.
        uint256 spent = _nativeDrop(
            _executionParams.origin,
            LOCAL_EID_V2,
            _executionParams.receiver,
            _nativeDropParams,
            _nativeDropGasLimit
        );

        // Only remaining value is used for the receive call.
        uint256 value = msg.value - spent;
        try
            ILayerZeroEndpointV2Extended(ENDPOINT).lzReceive{
                value: value,
                gas: _executionParams.gasLimit
            }(
                _executionParams.origin,
                _executionParams.receiver,
                _executionParams.guid,
                _executionParams.message,
                _executionParams.extraData
            )
        // solhint-disable-next-line no-empty-blocks
        {
            // Do nothing.
        } catch (bytes memory reason) {
            // If the receive fails, report for monitoring.
            ILayerZeroEndpointV2Extended(ENDPOINT).lzReceiveAlert(
                _executionParams.origin,
                _executionParams.receiver,
                _executionParams.guid,
                _executionParams.gasLimit,
                value,
                _executionParams.message,
                _executionParams.extraData,
                reason
            );
        }
    }

    // --- Message Lib ---

    /**
     * @dev Assigns a job to the Executor and calculates the fee. Used by message libraries.
     * @param _dstEid Destination EID.
     * @param _sender Address sending the job.
     * @param _calldataSize Size of calldata in bytes.
     * @param _options Additional options as bytes.
     * @return fee Fee calculated for the job.
     */
    function assignJob(
        uint32 _dstEid,
        address _sender,
        uint256 _calldataSize,
        bytes calldata _options
    ) external onlyRole(_MESSAGE_LIB_ROLE) onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
        // Construct fee parameters for the fee library call.
        IExecutorFeeLib.FeeParams memory params = IExecutorFeeLib.FeeParams(
            priceFeed,
            _dstEid,
            _sender,
            _calldataSize,
            defaultMultiplierBps
        );
        // Call external fee library (pluggable) for fee computation.
        fee = IExecutorFeeLib(workerFeeLib).getFeeOnSend(params, dstConfig[_dstEid], _options);
    }

    /**
     * @dev Assigns a job for CmdLib (`destination = localEidV2`).
     * @param _sender Address sending the job.
     * @param _options Additional options as bytes.
     * @return fee Fee calculated for the job.
     */
    function assignJob(
        address _sender,
        bytes calldata _options
    ) external onlyRole(_MESSAGE_LIB_ROLE) onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
        // Construct fee parameters for the fee library call.
        IExecutorFeeLib.FeeParamsForRead memory params = IExecutorFeeLib.FeeParamsForRead(
            priceFeed,
            _sender,
            defaultMultiplierBps
        );
        // Call external fee library (pluggable) for fee computation.
        fee = IExecutorFeeLib(workerFeeLib).getFeeOnSend(params, dstConfig[LOCAL_EID_V2], _options);
    }

    /**
     * @dev Returns the current execution state for a packet.
     * @param _packetHeader Encoded packet header.
     * @param _payloadHash Hash of the packet payload.
     * @return ExecutionState Current execution state of the packet.
     */
    function executable(
        bytes calldata _packetHeader,
        bytes32 _payloadHash
    ) public view returns (ExecutionState) {
        // Decode the receiver and origin details from the header.
        address _receiver = _packetHeader.receiverB20();
        Origin memory _origin = Origin(
            _packetHeader.srcEid(),
            _packetHeader.sender(),
            _packetHeader.nonce()
        );

        // Query the payload hash stored in the endpoint for the packet.
        bytes32 payloadHash = ILayerZeroEndpointV2(ENDPOINT).inboundPayloadHash(
            _receiver,
            _origin.srcEid,
            _origin.sender,
            _origin.nonce
        );

        // 1. Already executed if the payload hash has been cleared and the nonce is less than or equal to `lazyInboundNonce`.
        if (
            payloadHash == EMPTY_PAYLOAD_HASH &&
            _origin.nonce <=
            ILayerZeroEndpointV2(ENDPOINT).lazyInboundNonce(
                _receiver,
                _origin.srcEid,
                _origin.sender
            )
        ) {
            return ExecutionState.Executed;
        }

        // 2. Executable: if nonce has not been executed and has not been nilified and nonce is less than or equal to `inboundNonce`.
        if (
            payloadHash != NIL_PAYLOAD_HASH &&
            payloadHash == _payloadHash &&
            _origin.nonce <=
            ILayerZeroEndpointV2(ENDPOINT).inboundNonce(_receiver, _origin.srcEid, _origin.sender)
        ) {
            return ExecutionState.Executable;
        }

        // 3. Pending but verified: only start active executable polling if payload hash is not empty nor `nil`.
        if (payloadHash != EMPTY_PAYLOAD_HASH && payloadHash != NIL_PAYLOAD_HASH) {
            return ExecutionState.VerifiedButNotExecutable;
        }

        // 4. Not executable: `catch-all`.
        return ExecutionState.NotExecutable;
    }

    /**
     * @dev Checks if a packet is in a verifiable state.
     * @param _packetHeader Encoded packet header bytes.
     * @param _payloadHash Keccak256 hash of packet payload.
     * @return state Current `VerificationState` of the packet.
     */
    function verifiable(
        bytes calldata _packetHeader,
        bytes32 _payloadHash
    ) public view returns (VerificationState) {
        // Assert the header is valid for the local endpoint ID.
        IReceiveUlnView(RECEIVE_ULN302).assertHeader(_packetHeader, LOCAL_EID_V2);

        // Decode the receiver and origin details from the header.
        address receiver = _packetHeader.receiverB20();

        Origin memory origin = Origin(
            _packetHeader.srcEid(),
            _packetHeader.sender(),
            _packetHeader.nonce()
        );

        // 1. Endpoint must support initialization (config present, etc).
        if (!_initializable(origin, receiver)) {
            return VerificationState.NotInitializable;
        }

        // 2. Endpoint verifiable (e.g. not already verified).
        if (!_endpointVerifiable(origin, receiver, _payloadHash)) {
            return VerificationState.Verified;
        }

        // 3. ULN verifiable (DVN or ULN, packet is verifiable).
        if (
            IReceiveUlnView(RECEIVE_ULN302).verifiable(
                IReceiveUlnView(RECEIVE_ULN302).getUlnConfig(receiver, origin.srcEid),
                keccak256(_packetHeader),
                _payloadHash
            )
        ) {
            return VerificationState.Verifiable;
        }

        // 4. Still verifying.
        return VerificationState.Verifying;
    }

    // --- Only ACL ---

    /**
     * @dev Returns the fee for a given destination and calldata size (for `msg.sender`).
     * @param _dstEid Destination EID.
     * @param _sender Address of message sender.
     * @param _calldataSize Calldata size.
     * @param _options Options encoded as bytes.
     * @return fee Quoted fee for the job.
     */
    function getFee(
        uint32 _dstEid,
        address _sender,
        uint256 _calldataSize,
        bytes calldata _options
    ) external view onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
        // Construct fee parameters for the fee library call.
        IExecutorFeeLib.FeeParams memory params = IExecutorFeeLib.FeeParams(
            priceFeed,
            _dstEid,
            _sender,
            _calldataSize,
            defaultMultiplierBps
        );
        // Call external fee library (pluggable) for fee computation.
        fee = IExecutorFeeLib(workerFeeLib).getFee(params, dstConfig[_dstEid], _options);
    }

    /**
     * @dev Returns the fee for a read job (for `CmdLib`, `msg.sender`).
     * @param _sender Address of message sender.
     * @param _options Options encoded as bytes.
     * @return fee Quoted fee for the job.
     */
    function getFee(
        address _sender,
        bytes calldata _options
    ) external view onlyAcl(_sender) whenNotPaused returns (uint256 fee) {
        // Construct fee parameters for the fee library call.
        IExecutorFeeLib.FeeParamsForRead memory params = IExecutorFeeLib.FeeParamsForRead(
            priceFeed,
            _sender,
            defaultMultiplierBps
        );
        // Call external fee library (pluggable) for fee computation.
        fee = IExecutorFeeLib(workerFeeLib).getFee(params, dstConfig[LOCAL_EID_V2], _options);
    }

    /// @dev Internal function to distribute native tokens to multiple recipients.
    /// @param _origin Origin information for the message context.
    /// @param _dstEid Destination endpoint ID.
    /// @param _oapp Target contract on remote chain.
    /// @param _nativeDropParams Array of receivers and amounts.
    /// @param _nativeDropGasLimit Gas limit for each transfer call.
    /// @return spent Total amount of native tokens sent.
    function _nativeDrop(
        Origin calldata _origin,
        uint32 _dstEid,
        address _oapp,
        NativeDropParams[] calldata _nativeDropParams,
        uint256 _nativeDropGasLimit
    ) internal returns (uint256 spent) {
        uint256 paramsLength = _nativeDropParams.length;
        bool[] memory success = new bool[](paramsLength);
        for (uint256 i = 0; i < paramsLength; ++i) {
            NativeDropParams memory param = _nativeDropParams[i];
            // slither-disable-next-line arbitrary-send-eth,low-level-calls,return-bomb
            (bool sent, ) = param.receiver.call{value: param.amount, gas: _nativeDropGasLimit}("");

            success[i] = sent;
            spent += param.amount;
        }
        emit NativeDropApplied(_origin, _dstEid, _oapp, _nativeDropParams, success);
    }

    /// @dev Checks whether the endpoint can be verified and the payload hash is not already stored.
    /// @param _origin Origin information for the message context.
    /// @param _receiver Address of the endpoint’s receiver contract.
    /// @param _payloadHash Keccak256 hash of the message payload.
    /// @return boolean `True` if the endpoint is verifiable and hasn’t seen this payload before.
    function _endpointVerifiable(
        Origin memory _origin,
        address _receiver,
        bytes32 _payloadHash
    ) internal view returns (bool) {
        // check endpoint verifiable
        if (!_verifiable(_origin, _receiver, RECEIVE_ULN302, _payloadHash)) return false;

        // if `endpoint.verifiable`, also check if the payload hash matches
        // the endpoint that allows re-verification. Check if this payload has already been verified.
        if (
            ILayerZeroEndpointV2(ENDPOINT).inboundPayloadHash(
                _receiver,
                _origin.srcEid,
                _origin.sender,
                _origin.nonce
            ) == _payloadHash
        ) return false;

        return true;
    }

    /**
     * @dev Internal helper to verify library and endpoint readiness.
     * Checks if the receive library is valid for the receiver,
     * if the endpoint is verifiable for the origin and receiver,
     * and if the payload hash is non‐zero.
     * @param _origin Origin context for verification.
     * @param _receiver Receiver address on this chain.
     * @param _receiveLib Address of the ULN receive library to check.
     * @param _payloadHash Payload hash that must be non‐zero.
     * @return True if the receive library is registered, the endpoint is verifiable, and `payloadHash ≠ 0`.
     */
    function _verifiable(
        Origin memory _origin,
        address _receiver,
        address _receiveLib,
        bytes32 _payloadHash
    ) internal view returns (bool) {
        // Library must be a valid receive library for this endpoint.
        if (
            !ILayerZeroEndpointV2(ENDPOINT).isValidReceiveLibrary(
                _receiver,
                _origin.srcEid,
                _receiveLib
            )
        ) return false;

        // Endpoint must report itself as verifiable for this origin.
        if (!ILayerZeroEndpointV2(ENDPOINT).verifiable(_origin, _receiver)) return false;

        // Reject zero‐value hashes (not a real message).
        if (_payloadHash == EMPTY_PAYLOAD_HASH) return false;

        return true;
    }

    /**
     * @dev Checks if the endpoint supports initialization for a given origin and receiver.
     * @param _origin Origin context to query.
     * @param _receiver Address of the receiver contract to check.
     * @return boolean `True` if the endpoint supports initialization for this origin and receiver.
     */
    function _initializable(Origin memory _origin, address _receiver) internal view returns (bool) {
        try ILayerZeroEndpointV2(ENDPOINT).initializable(_origin, _receiver) returns (
            bool initializable
        ) {
            return initializable;
        } catch {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

import { IWorker } from "./IWorker.sol";
import { ILayerZeroExecutor } from "./ILayerZeroExecutor.sol";
import { ILayerZeroReadExecutor } from "./ILayerZeroReadExecutor.sol";

interface IExecutor is IWorker, ILayerZeroExecutor, ILayerZeroReadExecutor {
    struct DstConfigParam {
        uint32 dstEid;
        uint64 lzReceiveBaseGas;
        uint64 lzComposeBaseGas;
        uint16 multiplierBps;
        uint128 floorMarginUSD;
        uint128 nativeCap;
    }

    struct DstConfig {
        uint64 lzReceiveBaseGas;
        uint16 multiplierBps;
        uint128 floorMarginUSD; // uses priceFeed PRICE_RATIO_DENOMINATOR
        uint128 nativeCap;
        uint64 lzComposeBaseGas;
    }

    struct ExecutionParams {
        address receiver;
        Origin origin;
        bytes32 guid;
        bytes message;
        bytes extraData;
        uint256 gasLimit;
    }

    struct NativeDropParams {
        address receiver;
        uint256 amount;
    }

    event DstConfigSet(DstConfigParam[] params);
    event NativeDropApplied(Origin origin, uint32 dstEid, address oapp, NativeDropParams[] params, bool[] success);

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

interface IExecutorFeeLib {
    struct FeeParams {
        address priceFeed;
        uint32 dstEid;
        address sender;
        uint256 calldataSize;
        uint16 defaultMultiplierBps;
    }

    struct FeeParamsForRead {
        address priceFeed;
        address sender;
        uint16 defaultMultiplierBps;
    }

    error Executor_NoOptions();
    error Executor_NativeAmountExceedsCap(uint256 amount, uint256 cap);
    error Executor_UnsupportedOptionType(uint8 optionType);
    error Executor_InvalidExecutorOptions(uint256 cursor);
    error Executor_ZeroLzReceiveGasProvided();
    error Executor_ZeroLzComposeGasProvided();
    error Executor_ZeroCalldataSizeProvided();
    error Executor_EidNotSupported(uint32 eid);

    function getFeeOnSend(
        FeeParams calldata _params,
        IExecutor.DstConfig calldata _dstConfig,
        bytes calldata _options
    ) external returns (uint256 fee);

    function getFee(
        FeeParams calldata _params,
        IExecutor.DstConfig calldata _dstConfig,
        bytes calldata _options
    ) external view returns (uint256 fee);

    function getFeeOnSend(
        FeeParamsForRead calldata _params,
        IExecutor.DstConfig calldata _dstConfig,
        bytes calldata _options
    ) external returns (uint256 fee);

    function getFee(
        FeeParamsForRead calldata _params,
        IExecutor.DstConfig calldata _dstConfig,
        bytes calldata _options
    ) external view returns (uint256 fee);

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

// SPDX-License-Identifier: MIT

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,
        uint256 _calldataSize,
        bytes calldata _options
    ) external returns (uint256 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,
        uint256 _calldataSize,
        bytes calldata _options
    ) external view returns (uint256 price);
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface ILayerZeroReadExecutor {
    // @notice query price and assign jobs at the same time
    // @param _sender - the source sending contract address. executors may apply price discrimination to senders
    // @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
    function assignJob(address _sender, bytes calldata _options) external returns (uint256 fee);

    // @notice query the executor price for executing the payload on this chain
    // @param _sender - the source sending contract address. executors may apply price discrimination to senders
    // @param _options - optional parameters for extra service plugins, e.g. sending dust tokens
    function getFee(address _sender, bytes calldata _options) external view returns (uint256 fee);
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

interface IWorker {
    event SetWorkerLib(address workerLib);
    event SetPriceFeed(address priceFeed);
    event SetDefaultMultiplierBps(uint16 multiplierBps);
    event SetSupportedOptionTypes(uint32 dstEid, uint8[] optionTypes);
    event Withdraw(address lib, address to, uint256 amount);

    error Worker_NotAllowed();
    error Worker_OnlyMessageLib();
    error Worker_RoleRenouncingDisabled();

    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, uint256 _amount) external;

    function setSupportedOptionTypes(uint32 _eid, uint8[] calldata _optionTypes) external;

    function getSupportedOptionTypes(uint32 _eid) external view returns (uint8[] memory);
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

/// @dev should be implemented by the ReceiveUln302 contract and future ReceiveUln contracts on EndpointV2
interface IReceiveUlnE2 {
    /// @notice for each dvn to verify the payload
    /// @dev this function signature 0x0223536e
    function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external;

    /// @notice verify the payload at endpoint, will check if all DVNs verified
    function commitVerification(bytes calldata _packetHeader, bytes32 _payloadHash) external;
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

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

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

struct MessagingFee {
    uint256 nativeFee;
    uint256 lzTokenFee;
}

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

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

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

    event PacketDelivered(Origin origin, address receiver);

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

    event LzTokenSet(address token);

    event DelegateSet(address sender, address delegate);

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

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

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

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

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

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

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

    function setLzToken(address _lzToken) external;

    function lzToken() external view returns (address);

    function nativeToken() external view returns (address);

    function setDelegate(address _delegate) external;
}

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

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

enum MessageLibType {
    Send,
    Receive,
    SendAndReceive
}

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

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

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

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

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

    function registerLibrary(address _lib) external;

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

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

    function setDefaultSendLibrary(uint32 _eid, address _newLib) external;

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

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

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

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

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

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

    function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool);

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

    function eid() external view returns (uint32);

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

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

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

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

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

// SPDX-License-Identifier: MIT

pragma solidity >=0.8.0;

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

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

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

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

    function setTreasury(address _treasury) external;

    function withdrawFee(address _to, uint256 _amount) external;

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

// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.20;

library AddressCast {
    error AddressCast_InvalidSizeForAddress();
    error AddressCast_InvalidAddress();

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

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

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

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

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

// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.20;

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

library Transfer {
    using SafeERC20 for IERC20;

    address internal constant ADDRESS_ZERO = address(0);

    error Transfer_NativeFailed(address _to, uint256 _value);
    error Transfer_ToAddressIsZero();

    function native(address _to, uint256 _value) internal {
        if (_to == ADDRESS_ZERO) revert Transfer_ToAddressIsZero();
        (bool success, ) = _to.call{ value: _value }("");
        if (!success) revert Transfer_NativeFailed(_to, _value);
    }

    function token(address _token, address _to, uint256 _value) internal {
        if (_to == ADDRESS_ZERO) revert Transfer_ToAddressIsZero();
        IERC20(_token).safeTransfer(_to, _value);
    }

    function nativeOrToken(address _token, address _to, uint256 _value) internal {
        if (_token == ADDRESS_ZERO) {
            native(_to, _value);
        } else {
            token(_token, _to, _value);
        }
    }
}

// SPDX-License-Identifier: LZBL-1.2

pragma solidity ^0.8.20;

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

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

    uint8 internal constant PACKET_VERSION = 1;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {IERC165, ERC165} from "../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 account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /// @inheritdoc IERC165
    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 returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @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 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 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 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 `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @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 Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)

pragma solidity >=0.8.4;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @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 to signal this.
     */
    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. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    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 `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 21 of 34 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

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

File 22 of 34 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

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

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

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

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

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

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

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 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);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * 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[ERC 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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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 {
    bool private _paused;

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

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @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 {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

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

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

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

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

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

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 30 of 34 : ValueValidator.sol
// SPDX-FileCopyrightText: 2025 Molecula <info@molecula.fi>
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

import {ConstantsCoreV2} from "./../coreV2/Constants.sol";

/// @title ValueValidator.
/// @notice Contract for validating common value-based conditions.
/// @dev Provides modifiers to check for zero values, zero addresses, and `msg.value` conditions.
contract ValueValidator {
    /// @dev Error: `msg.sender` is not authorized for this function.
    error ENotAuthorized();

    /// @dev Error thrown when a value is zero but must be non-zero.
    error EZeroValue();

    /// @dev Error thrown when an address is zero but must be non-zero.
    error EZeroAddress();

    /// @dev Error thrown when `msg.value` is not zero but must be zero.
    error EMsgValueIsNotZero();

    /// @dev Error: Provided array is empty.
    error EEmptyArray();

    /// @dev Error: Percentage is invalid.
    error EInvalidPercentage();

    /**
     * @dev Ensures the function is called by the expected sender.
     * @param expectedSender Address that is allowed to call the function.
     * @custom:revert ENotAuthorized Check if the caller is not the expected sender.
     */
    modifier only(address expectedSender) {
        if (msg.sender != expectedSender) {
            revert ENotAuthorized();
        }
        _;
    }

    /// @dev Modifier that checks if a value is not zero.
    /// @param value Value to check.
    modifier notZero(uint256 value) {
        // slither-disable-next-line incorrect-equality
        if (value == 0) {
            revert EZeroValue();
        }
        _;
    }

    /// @dev Modifier that checks if an address is not zero.
    /// @param addr Address to check.
    modifier notZeroAddress(address addr) {
        if (addr == address(0)) {
            revert EZeroAddress();
        }
        _;
    }

    /// @dev Modifier that ensures `msg.value` is zero.
    modifier zeroMsgValue() {
        if (msg.value != 0) {
            revert EMsgValueIsNotZero();
        }
        _;
    }

    /// @dev Modifier that checks if the array is empty.
    /// @param arrayLength Array length to check.
    modifier notEmpty(uint256 arrayLength) {
        if (arrayLength == 0) {
            revert EEmptyArray();
        }
        _;
    }

    /// @dev Modifier that validates if the basis points value is within the valid range (0-10000).
    /// @param bps Basis points value to validate.
    /// @custom:revert EInvalidPercentage Check if bps exceeds the maximum allowed value (10000).
    modifier checkBPS(uint16 bps) {
        if (bps > ConstantsCoreV2.PERCENTAGE_FACTOR) {
            revert EInvalidPercentage();
        }
        _;
    }
}

File 31 of 34 : Constants.sol
// SPDX-FileCopyrightText: 2025 Molecula <info@molecula.fi>
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.24;

/// @title ConstantsCoreV2.
/// @notice Library containing core constants used across the protocol.
/// @dev Contains immutable values that are frequently used in other contracts.
library ConstantsCoreV2 {
    /// @notice Special address used to represent the native token (e.g., ETH) according to EIP-7528:
    ///         https://eips.ethereum.org/EIPS/eip-7528
    /// @dev This pseudo-address is commonly used to differentiate between ERC20 tokens and the native tokens.
    address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @dev Basis points factor, where 100% = 10,000.
    /// Used as a denominator in percentage calculations.
    uint16 public constant PERCENTAGE_FACTOR = 10_000;
}

// SPDX-License-Identifier: LZBL-1.2
// copied from https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/messagelib/contracts/Executor.sol
pragma solidity ^0.8.24;

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

/**
 * @dev Extended interface for LayerZero Endpoint v2 for message processing, composing, and alerting.
 */
interface ILayerZeroEndpointV2Extended {
    /**
     * @dev Returns the endpoint ID (EID) for this contract.
     * @return Endpoint EID (unique uint32 identifier)
     */
    function eid() external view returns (uint32);

    /**
     * @notice Receives and processes a cross-chain message.
     * @dev Called by Executor or LayerZero infrastructure to deliver a message.
     * @param _origin       Struct describing the source chain and sender.
     * @param _receiver     Destination receiver contract address.
     * @param _guid         Unique message GUID (32 bytes).
     * @param _message      Serialized message payload.
     * @param _extraData    Extra data (optional, may be empty).
     */
    function lzReceive(
        Origin calldata _origin,
        address _receiver,
        bytes32 _guid,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;

    /**
     * @notice Alerts about a failed message delivery or execution attempt.
     * @dev Used for off-chain monitoring and reprocessing flows.
     * @param _origin       Struct describing the source chain and sender.
     * @param _receiver     Destination receiver contract address.
     * @param _guid         Unique message GUID (32 bytes).
     * @param _gas          Gas provided for the failed attempt.
     * @param _value        Native token value sent.
     * @param _message      Serialized message payload.
     * @param _extraData    Extra data passed during the call.
     * @param _reason       ABI-encoded revert reason or error data.
     */
    function lzReceiveAlert(
        Origin calldata _origin,
        address _receiver,
        bytes32 _guid,
        uint256 _gas,
        uint256 _value,
        bytes calldata _message,
        bytes calldata _extraData,
        bytes calldata _reason
    ) external;

    /**
     * @notice Composes (initiates) a new cross-chain message from one contract to another.
     * @dev Used for multi-hop or chained message execution.
     * @param _from         Originating contract address.
     * @param _to           Destination contract address.
     * @param _guid         Unique message GUID.
     * @param _index        Message sequence index for ordering.
     * @param _message      Serialized payload.
     * @param _extraData    Extra data (optional, may be empty).
     */
    function lzCompose(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index,
        bytes calldata _message,
        bytes calldata _extraData
    ) external payable;

    /**
     * @notice Alerts about a failed compose attempt.
     * @dev Used for off-chain monitoring and diagnostics.
     * @param _from         Originating contract address.
     * @param _to           Destination contract address.
     * @param _guid         Unique message GUID.
     * @param _index        Message sequence index.
     * @param _gas          Gas provided for the failed attempt.
     * @param _value        Native token value sent.
     * @param _message      Serialized payload.
     * @param _extraData    Extra data passed during the call.
     * @param _reason       ABI-encoded revert reason or error data.
     */
    function lzComposeAlert(
        address _from,
        address _to,
        bytes32 _guid,
        uint16 _index,
        uint256 _gas,
        uint256 _value,
        bytes calldata _message,
        bytes calldata _extraData,
        bytes calldata _reason
    ) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @title LayerZero ULN Verification and Execution State Enums & View Interface.
/// @dev These enums and interface are used for verifying and tracking LayerZero Ultra Light Node packet states.

/**
 * @dev Represents the verification status of a LayerZero packet.
 * - Verifying:     Packet is still undergoing DVN verification.
 * - Verifiable:    Packet is ready to be committed after successful DVN verification.
 * - Verified:      Packet has been verified.
 * - NotInitializable:  Packet cannot be initialized for verification due to config/state.
 */
enum VerificationState {
    Verifying,
    Verifiable,
    Verified,
    NotInitializable
}

/**
 * @dev Represents the execution status of a LayerZero packet.
 * - NotExecutable:               Packet cannot be executed (waiting for verification).
 * - VerifiedButNotExecutable:    Packet has been verified but is not yet executable (active polling).
 * - Executable:                  Packet is executable (can be processed by the executor).
 * - Executed:                    Packet has already been executed.
 */
enum ExecutionState {
    NotExecutable,
    VerifiedButNotExecutable,
    Executable,
    Executed
}

/**
 * @dev Interface for reading Ultra Light Node (ULN) verification config and status.
 */
interface IReceiveUlnView {
    /**
     * @dev ULN DVN configuration for a given remote chain and OApp.
     * @param confirmations         Number of block confirmations required for DVN.
     * @param requiredDVNCount      Number of required DVNs (0 = default, special NIL_DVN_COUNT disables).
     * @param optionalDVNCount      Number of optional DVNs (0 = default, special NIL_DVN_COUNT disables).
     * @param optionalDVNThreshold  Minimum number of optional DVN confirmations required.
     * @param requiredDVNs          List of required DVN addresses (sorted, unique, may overlap with optional).
     * @param optionalDVNs          List of optional DVN addresses (sorted, unique, may overlap with required).
     */
    struct UlnConfig {
        uint64 confirmations;
        uint8 requiredDVNCount;
        uint8 optionalDVNCount;
        uint8 optionalDVNThreshold;
        address[] requiredDVNs;
        address[] optionalDVNs;
    }

    /**
     * @dev Checks if a packet is verifiable given its ULN config, header hash, and payload hash.
     * @param _config      ULN configuration to check against.
     * @param _headerHash  keccak256 hash of the packet header.
     * @param _payloadHash keccak256 hash of the packet payload.
     * @return True if the packet is currently verifiable.
     */
    function verifiable(
        UlnConfig memory _config,
        bytes32 _headerHash,
        bytes32 _payloadHash
    ) external view returns (bool);

    /**
     * @dev Returns the current ULN configuration for a given OApp and remote EID.
     * @param _oapp Address of the OApp (on this chain).
     * @param _remoteEid Remote LayerZero endpoint ID.
     * @return rtnConfig Current ULN config for this OApp and remote endpoint.
     */
    function getUlnConfig(
        address _oapp,
        uint32 _remoteEid
    ) external view returns (UlnConfig memory rtnConfig);

    /**
     * @dev Asserts that the provided packet header is valid for the local endpoint ID.
     * @param _packetHeader Encoded packet header bytes.
     * @param _localEid Local LayerZero endpoint ID.
     */
    function assertHeader(bytes calldata _packetHeader, uint32 _localEid) external pure;
}

// SPDX-License-Identifier: LZBL-1.2
// copied from https://github.com/LayerZero-Labs/LayerZero-v2/blob/main/packages/layerzero-v2/evm/messagelib/contracts/Worker.sol
pragma solidity ^0.8.24;

import {IWorker} from "@layerzerolabs/lz-evm-messagelib-v2/contracts/interfaces/IWorker.sol";
import {ISendLib} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol";
import {Transfer} from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/Transfer.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {ValueValidator} from "../common/ValueValidator.sol";

abstract contract Worker is AccessControl, Pausable, IWorker, ValueValidator {
    /// @dev Role for contracts allowed to assign jobs (messaging libraries).
    bytes32 internal constant _MESSAGE_LIB_ROLE = keccak256("MESSAGE_LIB_ROLE");
    /// @dev Role representing addresses in the allowlist.
    bytes32 internal constant _ALLOWLIST = keccak256("ALLOWLIST");
    /// @dev Role representing addresses in the denylist.
    bytes32 internal constant _DENYLIST = keccak256("DENYLIST");
    /// @dev Admin role for configuration changes.
    bytes32 internal constant _ADMIN_ROLE = keccak256("ADMIN_ROLE");

    /// @dev Address of the ExecutorFeeLib contract used for fee computations.
    address public workerFeeLib;
    /// @dev Number of addresses currently in the allowlist.
    uint64 public allowlistSize;
    /// @dev Default multiplier (in basis points) applied to computed fees.
    uint16 public defaultMultiplierBps;
    /// @dev Address of the external price feed used by ExecutorFeeLib.
    address public priceFeed;
    /// @dev Mapping of remote LZ EIDs to supported option type codes.
    mapping(uint32 eid => uint8[] optionTypes) internal _supportedOptionTypes;

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

    /**
     * @dev Initialize Worker with initial libraries, admin, price feed, and roles.
     * @param _messageLibs Array of message lib addresses that are granted the MESSAGE_LIB_ROLE.
     * @param _priceFeed Price feed address (for fee quoting).
     * @param _defaultMultiplierBps Default fee multiplier (bps).
     * @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)) {
            // _roleAdmin can grant and revoke all roles
            _grantRole(DEFAULT_ADMIN_ROLE, _roleAdmin);
        }

        // solhint-disable-next-line gas-length-in-loops
        for (uint256 i = 0; i < _messageLibs.length; ++i) {
            // Grant _MESSAGE_LIB_ROLE to all provided message libraries
            _grantRole(_MESSAGE_LIB_ROLE, _messageLibs[i]);
        }

        // solhint-disable-next-line gas-length-in-loops
        for (uint256 i = 0; i < _admins.length; ++i) {
            // Grant _ADMIN_ROLE to all provided admin addresses
            _grantRole(_ADMIN_ROLE, _admins[i]);
        }
    }

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

    /**
     * @dev Modifier that restricts access to only those passing the ACL check.
     *      Can be used to guard fee queries, job assignments, etc.
     * @param _sender Address to check ACL against.
     */
    modifier onlyAcl(address _sender) {
        if (!hasAcl(_sender)) {
            revert Worker_NotAllowed();
        }
        _;
    }

    /**
     * @dev Access control list logic.
     *      - If sender is in denylist: always denied
     *      - If allowlist is empty or sender is in allowlist: allowed
     *      - Else: denied
     * @param _sender Address to check for ACL.
     * @return True if allowed, false otherwise.
     */
    function hasAcl(address _sender) public view returns (bool) {
        if (hasRole(_DENYLIST, _sender)) {
            return false;
        } else if (allowlistSize == 0 || hasRole(_ALLOWLIST, _sender)) {
            // If allowlist is empty (open mode) or sender is in allowlist
            return true;
        } else {
            return false;
        }
    }

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

    /**
     * @dev Pauses or unpauses contract (if used with whenNotPaused).
     *      Only callable by DEFAULT_ADMIN_ROLE.
     * @param _paused True to pause, false to unpause.
     */
    function setPaused(bool _paused) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_paused) {
            _pause();
        } else {
            _unpause();
        }
    }

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

    /**
     * @dev Updates the price feed contract used for fee calculation.
     *      Only callable by ADMIN_ROLE.
     * @param _priceFeed New price feed address.
     */
    function setPriceFeed(
        address _priceFeed
    ) external onlyRole(_ADMIN_ROLE) notZeroAddress(_priceFeed) {
        priceFeed = _priceFeed;
        emit SetPriceFeed(_priceFeed);
    }

    /**
     * @dev Updates ExecutorFeeLib address used for all fee calculations.
     *      Only callable by ADMIN_ROLE.
     * @param _workerFeeLib Address of new ExecutorFeeLib contract.
     */
    function setWorkerFeeLib(
        address _workerFeeLib
    ) external onlyRole(_ADMIN_ROLE) notZeroAddress(_workerFeeLib) {
        workerFeeLib = _workerFeeLib;
        emit SetWorkerLib(_workerFeeLib);
    }

    /**
     * @dev Updates the default fee multiplier (basis points).
     *      Only callable by ADMIN_ROLE.
     * @param _multiplierBps New default multiplier (bps).
     */
    function setDefaultMultiplierBps(uint16 _multiplierBps) external onlyRole(_ADMIN_ROLE) {
        defaultMultiplierBps = _multiplierBps;
        emit SetDefaultMultiplierBps(_multiplierBps);
    }

    /**
     * @dev Withdraws protocol fees from supported message ULN libraries.
     *      Only callable by ADMIN_ROLE. Library must have MESSAGE_LIB_ROLE.
     * @param _lib Message library address to withdraw from.
     * @param _to Recipient address.
     * @param _amount Amount to withdraw.
     */
    function withdrawFee(
        address _lib,
        address _to,
        uint256 _amount
    ) external onlyRole(_ADMIN_ROLE) {
        if (!hasRole(_MESSAGE_LIB_ROLE, _lib)) revert Worker_OnlyMessageLib();
        // Call withdrawFee on the underlying library
        ISendLib(_lib).withdrawFee(_to, _amount);
        emit Withdraw(_lib, _to, _amount);
    }

    /**
     * @dev Withdraws ERC20 tokens or native currency.
     * @param _token Token address (use address(0) for native).
     * @param _to Recipient address.
     * @param _amount Amount to withdraw.
     */
    function withdrawToken(
        address _token,
        address _to,
        uint256 _amount
    ) external onlyRole(_ADMIN_ROLE) {
        // transfers native if _token is address(0x0)
        Transfer.nativeOrToken(_token, _to, _amount);
    }

    /**
     * @dev Set supported option type codes for a given remote endpoint.
     *      Used for feature upgrades, testing, or protocol extension.
     *      Only callable by ADMIN_ROLE.
     * @param _eid Endpoint ID.
     * @param _optionTypes List of supported option codes.
     */
    function setSupportedOptionTypes(
        uint32 _eid,
        uint8[] calldata _optionTypes
    ) external onlyRole(_ADMIN_ROLE) {
        _supportedOptionTypes[_eid] = _optionTypes;
    }

    // ========================= View Functions =========================

    /**
     * @dev Returns the list of supported option types for a given remote endpoint.
     * @param _eid Endpoint ID.
     * @return Array of option type codes.
     */
    function getSupportedOptionTypes(uint32 _eid) external view returns (uint8[] memory) {
        return _supportedOptionTypes[_eid];
    }

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

    /**
     * @dev Overrides AccessControl's _grantRole to increment allowlistSize as needed.
     * @param _role Role to grant.
     * @param _account Address to grant role to.
     * @return True if role was granted, false otherwise.
     */
    function _grantRole(bytes32 _role, address _account) internal override returns (bool) {
        if (_role == _ALLOWLIST && !hasRole(_role, _account)) {
            ++allowlistSize;
        }
        return super._grantRole(_role, _account);
    }

    /**
     * @dev Overrides AccessControl's _revokeRole to decrement allowlistSize as needed.
     * @param _role Role to revoke.
     * @param _account Address to revoke role from.
     * @return True if role was revoked, false otherwise.
     */
    function _revokeRole(bytes32 _role, address _account) internal override returns (bool) {
        if (_role == _ALLOWLIST && hasRole(_role, _account)) {
            --allowlistSize;
        }
        return super._revokeRole(_role, _account);
    }

    /**
     * @dev Overrides AccessControl to disable renouncing of roles.
     * Disable renouncing roles to prevent accidental loss of permissions.
     */
    function renounceRole(bytes32 /*role*/, address /*account*/) public pure override {
        revert Worker_RoleRenouncingDisabled();
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"address","name":"_receiveUln302","type":"address"},{"internalType":"address[]","name":"_messageLibs","type":"address[]"},{"internalType":"address","name":"_priceFeed","type":"address"},{"internalType":"address","name":"_roleAdmin","type":"address"},{"internalType":"address[]","name":"_admins","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"EEmptyArray","type":"error"},{"inputs":[],"name":"EInvalidPercentage","type":"error"},{"inputs":[],"name":"EMsgValueIsNotZero","type":"error"},{"inputs":[],"name":"ENotAuthorized","type":"error"},{"inputs":[],"name":"EZeroAddress","type":"error"},{"inputs":[],"name":"EZeroValue","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"Executor_InvalidVerificationState","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer_NativeFailed","type":"error"},{"inputs":[],"name":"Transfer_ToAddressIsZero","type":"error"},{"inputs":[],"name":"Worker_NotAllowed","type":"error"},{"inputs":[],"name":"Worker_OnlyMessageLib","type":"error"},{"inputs":[],"name":"Worker_RoleRenouncingDisabled","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"uint64","name":"lzReceiveBaseGas","type":"uint64"},{"internalType":"uint64","name":"lzComposeBaseGas","type":"uint64"},{"internalType":"uint16","name":"multiplierBps","type":"uint16"},{"internalType":"uint128","name":"floorMarginUSD","type":"uint128"},{"internalType":"uint128","name":"nativeCap","type":"uint128"}],"indexed":false,"internalType":"struct IExecutor.DstConfigParam[]","name":"params","type":"tuple[]"}],"name":"DstConfigSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"indexed":false,"internalType":"struct Origin","name":"origin","type":"tuple"},{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":false,"internalType":"address","name":"oapp","type":"address"},{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct IExecutor.NativeDropParams[]","name":"params","type":"tuple[]"},{"indexed":false,"internalType":"bool[]","name":"success","type":"bool[]"}],"name":"NativeDropApplied","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":[{"indexed":false,"internalType":"address","name":"priceFeed","type":"address"}],"name":"SetPriceFeed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":false,"internalType":"uint8[]","name":"optionTypes","type":"uint8[]"}],"name":"SetSupportedOptionTypes","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":"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":"EMPTY_PAYLOAD_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENDPOINT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCAL_EID_V2","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NIL_PAYLOAD_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECEIVE_ULN302","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowlistSize","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint256","name":"_calldataSize","type":"uint256"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"assignJob","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"assignJob","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_packetHeader","type":"bytes"},{"internalType":"bytes32","name":"_payloadHash","type":"bytes32"}],"name":"commitVerification","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"uint16","name":"_index","type":"uint16"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"bytes","name":"_extraData","type":"bytes"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"compose302","outputs":[],"stateMutability":"payable","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":"lzReceiveBaseGas","type":"uint64"},{"internalType":"uint16","name":"multiplierBps","type":"uint16"},{"internalType":"uint128","name":"floorMarginUSD","type":"uint128"},{"internalType":"uint128","name":"nativeCap","type":"uint128"},{"internalType":"uint64","name":"lzComposeBaseGas","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_packetHeader","type":"bytes"},{"internalType":"bytes32","name":"_payloadHash","type":"bytes32"}],"name":"executable","outputs":[{"internalType":"enum ExecutionState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"},{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"internalType":"struct IExecutor.ExecutionParams","name":"_executionParams","type":"tuple"}],"name":"execute302","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"uint256","name":"_calldataSize","type":"uint256"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"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":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"}],"name":"getSupportedOptionTypes","outputs":[{"internalType":"uint8[]","name":"","type":"uint8[]"}],"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":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"address","name":"_oapp","type":"address"},{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IExecutor.NativeDropParams[]","name":"_nativeDropParams","type":"tuple[]"},{"internalType":"uint256","name":"_nativeDropGasLimit","type":"uint256"}],"name":"nativeDrop","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IExecutor.NativeDropParams[]","name":"_nativeDropParams","type":"tuple[]"},{"internalType":"uint256","name":"_nativeDropGasLimit","type":"uint256"},{"components":[{"internalType":"address","name":"receiver","type":"address"},{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"},{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"internalType":"struct IExecutor.ExecutionParams","name":"_executionParams","type":"tuple"}],"name":"nativeDropAndExecute302","outputs":[],"stateMutability":"payable","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":[{"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":"lzReceiveBaseGas","type":"uint64"},{"internalType":"uint64","name":"lzComposeBaseGas","type":"uint64"},{"internalType":"uint16","name":"multiplierBps","type":"uint16"},{"internalType":"uint128","name":"floorMarginUSD","type":"uint128"},{"internalType":"uint128","name":"nativeCap","type":"uint128"}],"internalType":"struct IExecutor.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":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint8[]","name":"_optionTypes","type":"uint8[]"}],"name":"setSupportedOptionTypes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_workerFeeLib","type":"address"}],"name":"setWorkerFeeLib","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_packetHeader","type":"bytes"},{"internalType":"bytes32","name":"_payloadHash","type":"bytes32"}],"name":"verifiable","outputs":[{"internalType":"enum VerificationState","name":"","type":"uint8"}],"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":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"workerFeeLib","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60e060405234801561000f575f5ffd5b5060405161425438038061425483398101604081905261002e9161043d565b6001805461ffff60e81b191661017760ed1b179055600280546001600160a01b0319166001600160a01b038581169190911790915584908490612ee09085908590821615610082576100805f83610217565b505b5f5b85518110156100df576100d67f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de8783815181106100c3576100c36104e1565b602002602001015161021760201b60201c565b50600101610084565b505f5b815181101561012a576101217fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217758383815181106100c3576100c36104e1565b506001016100e2565b5050600160045550889250506001600160a01b038216905061015f5760405163f44a4d1760e01b815260040160405180910390fd5b856001600160a01b0381166101875760405163f44a4d1760e01b815260040160405180910390fd5b6001600160a01b03881660808190526040805163416ecebf60e01b8152905163416ecebf916004808201926020929091908290030181865afa1580156101cf573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101f391906104f5565b63ffffffff1660a0525050506001600160a01b0390931660c0525061055692505050565b5f7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8314801561026757505f838152602081815260408083206001600160a01b038616845290915290205460ff16155b156102b1576001805460159061028c90600160a81b90046001600160401b031661051f565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505b6102bb83836102c4565b90505b92915050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16610364575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561031c3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016102be565b505f6102be565b80516001600160a01b0381168114610381575f5ffd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126103a9575f5ffd5b81516001600160401b038111156103c2576103c2610386565b604051600582901b90603f8201601f191681016001600160401b03811182821017156103f0576103f0610386565b60405291825260208185018101929081018684111561040d575f5ffd5b6020860192505b83831015610433576104258361036b565b815260209283019201610414565b5095945050505050565b5f5f5f5f5f5f60c08789031215610452575f5ffd5b61045b8761036b565b95506104696020880161036b565b60408801519095506001600160401b03811115610484575f5ffd5b61049089828a0161039a565b94505061049f6060880161036b565b92506104ad6080880161036b565b60a08801519092506001600160401b038111156104c8575f5ffd5b6104d489828a0161039a565b9150509295509295509295565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215610505575f5ffd5b815163ffffffff81168114610518575f5ffd5b9392505050565b5f6001600160401b0382166002600160401b0319810161054d57634e487b7160e01b5f52601160045260245ffd5b60010192915050565b60805160a05160c051613c416106135f395f818161035e015281816108c001528181610b3201528181610c6c015261211c01525f81816107e501528181610b63015281816117a701528181611a2b0152611c5301525f81816104bb015281816113820152818161146c0152818161155401528181611636015281816116f1015281816117f1015281816118d201528181611d4201528181611e230152818161209d0152818161219c01528181612691015261274e0152613c415ff3fe608060405260043610610227575f3560e01c8063717e8a4211610129578063c358de0a116100a8578063cd88b9031161006d578063cd88b90314610745578063cfc3257014610764578063d2ae210414610777578063d547741f146107b5578063da2eb165146107d4575f5ffd5b8063c358de0a146106c4578063c416aa51146106e3578063c7b2370b14610707578063c8f8dcd114610726578063cb5026b914610692575f5ffd5b80638624ba07116100ee5780638624ba071461058b57806391d148541461059e5780639e944965146105e0578063a217fddf14610692578063c015bb7d146106a5575f5ffd5b8063717e8a42146104fc578063724e78da1461051b5780637401fccc1461053a578063741bef1a146105595780637cd4473414610578575f5ffd5b806327d12cd9116101b55780633d85ac331161017a5780633d85ac3314610461578063475b6d9e146104805780635c975abb146104935780636fad06f5146104aa578063709eb664146104dd575f5ffd5b806327d12cd9146103c45780632baf0be7146103f05780632de11376146104045780632f2ff15d1461042357806336568abe14610442575f5ffd5b80631095b6d7116101fb5780631095b6d7146102d357806316c38b3c146102f2578063248a9ca314610311578063252f5e3e1461034d57806326e67a3714610398575f5ffd5b8062bf2e801461022b57806301e336671461026457806301ffc9a7146102855780630894edf1146102b4575b5f5ffd5b348015610236575f5ffd5b5060015461024c90600160e81b900461ffff1681565b60405161ffff90911681526020015b60405180910390f35b34801561026f575f5ffd5b5061028361027e366004612a9e565b61081c565b005b348015610290575f5ffd5b506102a461029f366004612adc565b610844565b604051901515815260200161025b565b3480156102bf575f5ffd5b506102836102ce366004612b47565b61087a565b3480156102de575f5ffd5b506102836102ed366004612a9e565b610954565b3480156102fd575f5ffd5b5061028361030c366004612b9b565b610a72565b34801561031c575f5ffd5b5061033f61032b366004612bb6565b5f9081526020819052604090206001015490565b60405190815260200161025b565b348015610358575f5ffd5b506103807f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161025b565b3480156103a3575f5ffd5b506103b76103b2366004612be0565b610a96565b60405161025b9190612bf9565b3480156103cf575f5ffd5b506103e36103de366004612b47565b610b19565b60405161025b9190612c6e565b3480156103fb575f5ffd5b5061033f5f1981565b34801561040f575f5ffd5b506102a461041e366004612c81565b610d76565b34801561042e575f5ffd5b5061028361043d366004612c9c565b610e2a565b34801561044d575f5ffd5b5061028361045c366004612c9c565b610e4e565b34801561046c575f5ffd5b5061028361047b366004612cca565b610e67565b61028361048e366004612d79565b610ff1565b34801561049e575f5ffd5b5060015460ff166102a4565b3480156104b5575f5ffd5b506103807f000000000000000000000000000000000000000000000000000000000000000081565b3480156104e8575f5ffd5b5061033f6104f7366004612dfa565b611032565b348015610507575f5ffd5b5061033f610516366004612dfa565b611135565b348015610526575f5ffd5b50610283610535366004612c81565b611264565b348015610545575f5ffd5b506103e3610554366004612b47565b611307565b348015610564575f5ffd5b50600254610380906001600160a01b031681565b610283610586366004612e76565b611617565b610283610599366004612f3f565b61177e565b3480156105a9575f5ffd5b506102a46105b8366004612c9c565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156105eb575f5ffd5b5061064f6105fa366004612be0565b60056020525f9081526040902080546001909101546001600160401b038083169261ffff68010000000000000000820416926001600160801b03600160501b90920482169291811691600160801b9091041685565b604080516001600160401b03968716815261ffff90951660208601526001600160801b03938416908501529116606083015291909116608082015260a00161025b565b34801561069d575f5ffd5b5061033f5f81565b3480156106b0575f5ffd5b5061033f6106bf366004612fb0565b611992565b3480156106cf575f5ffd5b506102836106de366004613000565b611ad4565b3480156106ee575f5ffd5b506001546103809061010090046001600160a01b031681565b348015610712575f5ffd5b50610283610721366004612c81565b611b42565b348015610731575f5ffd5b5061033f610740366004612fb0565b611be4565b348015610750575f5ffd5b5061028361075f366004613019565b611cfa565b610283610772366004613098565b611d30565b348015610782575f5ffd5b5060015461079d90600160a81b90046001600160401b031681565b6040516001600160401b03909116815260200161025b565b3480156107c0575f5ffd5b506102836107cf366004612c9c565b611edd565b3480156107df575f5ffd5b506108077f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff909116815260200161025b565b5f516020613bec5f395f51905f5261083381611f01565b61083e848484611f0b565b50505050565b5f6001600160e01b03198216637965db0b60e01b148061087457506301ffc9a760e01b6001600160e01b03198316145b92915050565b610882611f2e565b5f61088e848484610b19565b905060018160038111156108a4576108a4612c3e565b0361092b57604051630894edf160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630894edf1906108f9908790879087906004016130f1565b5f604051808303815f87803b158015610910575f5ffd5b505af1158015610922573d5f5f3e3d5ffd5b50505050610944565b604051633152adcf60e11b815260040160405180910390fd5b5061094f6001600455565b505050565b5f516020613bec5f395f51905f5261096b81611f01565b6001600160a01b0384165f9081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff166109c257604051635ee08b9760e01b815260040160405180910390fd5b604051637ecdf29160e11b81526001600160a01b0384811660048301526024820184905285169063fd9be522906044015f604051808303815f87803b158015610a09575f5ffd5b505af1158015610a1b573d5f5f3e3d5ffd5b5050604080516001600160a01b038089168252871660208201529081018590527f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb925060600190505b60405180910390a150505050565b5f610a7c81611f01565b8115610a8e57610a8a611f58565b5050565b610a8a611fac565b63ffffffff81165f90815260036020908152604091829020805483518184028101840190945280845260609392830182828015610b0d57602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411610ade5790505b50505050509050919050565b60405163c40ff83560e01b81525f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063c40ff83590610b8b90879087907f000000000000000000000000000000000000000000000000000000000000000090600401613114565b5f6040518083038186803b158015610ba1575f5ffd5b505afa158015610bb3573d5f5f3e3d5ffd5b505050505f610bc28585611fe5565b90505f6040518060600160405280610bda8888611ff6565b63ffffffff168152602001610bef8888612018565b8152602001610bfe8888612030565b6001600160401b031690529050610c158183612052565b610c2457600392505050610d6f565b610c2f818386612114565b610c3e57600292505050610d6f565b80516040516343ea4fa960e01b81526001600160a01b03848116600483015263ffffffff90921660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063e084d9529082906343ea4fa9906044015f60405180830381865afa158015610cba573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ce19190810190613256565b8888604051610cf192919061332e565b6040519081900381206001600160e01b031960e085901b168252610d1a92918990600401613380565b602060405180830381865afa158015610d35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d599190613408565b15610d6957600192505050610d6f565b5f925050505b9392505050565b6001600160a01b0381165f9081527f93c430521711328044ae92d0f1f1286cf040bc4a382f1642bd89984e86630553602052604081205460ff1615610dbc57505f919050565b600154600160a81b90046001600160401b03161580610e1157506001600160a01b0382165f9081527f4ac82e3087b7dedf7f532cbc6915c722df8c1e31f1388c318a617b52760eaf8b602052604090205460ff165b15610e1e57506001919050565b505f919050565b919050565b5f82815260208190526040902060010154610e4481611f01565b61083e838361221b565b60405163dec9f03160e01b815260040160405180910390fd5b5f516020613bec5f395f51905f52610e7e81611f01565b815f5b81811015610fbf575f858583818110610e9c57610e9c613423565b905060c00201803603810190610eb2919061344d565b6040805160a080820183526020808501516001600160401b03908116845260608087015161ffff9081168487019081526080808a01516001600160801b03908116898b01908152978b01518116948901948552898b01518616918901918252995163ffffffff165f90815260059096529790942095518654945195518916600160501b027fffffffffffff00000000000000000000000000000000ffffffffffffffffffff96909216680100000000000000000269ffffffffffffffffffff199095169084161793909317939093169190911783559051600192830180549451909216600160801b026001600160c01b031990941694169390931791909117909155919091019050610e81565b507fb99f6de5e22c60c178b03bfacf2daeb4b6089f5b37e0fe2c48a5d5141191fc538484604051610a649291906134d2565b5f516020613bec5f395f51905f5261100881611f01565b611010611f2e565b61101e8787878787876122bf565b506110296001600455565b50505050505050565b5f8461103d81610d76565b61105a57604051634ab5ebcd60e01b815260040160405180910390fd5b611062612423565b6040805160a0810182526002546001600160a01b03908116825263ffffffff8a1660208084018290528a831684860152606084018a905260015461ffff600160e81b82041660808601525f92835260059091529084902093516321a7700b60e11b815292936101009091049091169163434ee016916110ea918591908a908a9060040161359a565b602060405180830381865afa158015611105573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611129919061365c565b98975050505050505050565b5f7f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de61116081611f01565b8561116a81610d76565b61118757604051634ab5ebcd60e01b815260040160405180910390fd5b61118f612423565b6040805160a0810182526002546001600160a01b03908116825263ffffffff8b1660208084018290528b831684860152606084018b905260015461ffff600160e81b82041660808601525f9283526005909152908490209351632b377bb160e11b815292936101009091049091169163566ef76291611217918591908b908b9060040161359a565b6020604051808303815f875af1158015611233573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611257919061365c565b9998505050505050505050565b5f516020613bec5f395f51905f5261127b81611f01565b816001600160a01b0381166112a35760405163f44a4d1760e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385169081179091556040519081527ff724a45d041687842411f2b977ef22ab8f43c8f1104f4592b42a00f9b34a643d906020015b60405180910390a1505050565b5f5f6113138585611fe5565b90505f604051806060016040528061132b8888611ff6565b63ffffffff1681526020016113408888612018565b815260200161134f8888612030565b6001600160401b0316905280516020820151604080840151905163c9fc7bcd60e01b81529394505f936001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363c9fc7bcd936113e79389936004016001600160a01b0394909416845263ffffffff92909216602084015260408301526001600160401b0316606082015260800190565b602060405180830381865afa158015611402573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611426919061365c565b9050801580156114f15750815160208301516040516305b17bb760e41b81526001600160a01b03868116600483015263ffffffff909316602482015260448101919091527f000000000000000000000000000000000000000000000000000000000000000090911690635b17bb7090606401602060405180830381865afa1580156114b3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114d79190613673565b6001600160401b031682604001516001600160401b031611155b156115025760039350505050610d6f565b5f19811480159061151257508481145b80156115d957508151602083015160405163283750ff60e21b81526001600160a01b03868116600483015263ffffffff909316602482015260448101919091527f00000000000000000000000000000000000000000000000000000000000000009091169063a0dd43fc90606401602060405180830381865afa15801561159b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115bf9190613673565b6001600160401b031682604001516001600160401b031611155b156115ea5760029350505050610d6f565b80158015906115fa57505f198114155b1561160b5760019350505050610d6f565b505f9695505050505050565b61161f611f2e565b6040516391d20fa160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906391d20fa1908390349061167d908e908e908e908e908e908e908e908e9060040161368e565b5f604051808303818589803b158015611694575f5ffd5b5088f194505050505080156116a7575060015b611769573d8080156116d4576040519150601f19603f3d011682016040523d82523d5f602084013e6116d9565b606091505b506040516334bff35b60e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063697fe6b69061173a908d908d908d908d90899034908f908f908f908f908e9060040161371f565b5f604051808303815f87803b158015611751575f5ffd5b505af1158015611763573d5f5f3e3d5ffd5b50505050505b6117736001600455565b505050505050505050565b5f516020613bec5f395f51905f5261179581611f01565b61179d611f2e565b5f6117d8602084017f00000000000000000000000000000000000000000000000000000000000000006117d08287612c81565b8989896122bf565b90505f6117e582346137bc565b90506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630c0c389e60e0860135836020880161182a818a612c81565b60808a013561183c60a08c018c6137cf565b61184960c08e018e6137cf565b6040518a63ffffffff1660e01b815260040161186b979695949392919061384e565b5f604051808303818589803b158015611882575f5ffd5b5088f19450505050508015611895575060015b61197f573d8080156118c2576040519150601f19603f3d011682016040523d82523d5f602084013e6118c7565b606091505b506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016636bf73fa3602087016119058189612c81565b608089013560e08a01358761191d60a08d018d6137cf565b61192a60c08f018f6137cf565b8b6040518b63ffffffff1660e01b81526004016119509a999897969594939291906138a4565b5f604051808303815f87803b158015611967575f5ffd5b505af1158015611979573d5f5f3e3d5ffd5b50505050505b505061198b6001600455565b5050505050565b5f7f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de6119bd81611f01565b846119c781610d76565b6119e457604051634ab5ebcd60e01b815260040160405180910390fd5b6119ec612423565b604080516060810182526002546001600160a01b03908116825288811660208084019190915260015461ffff600160e81b8204168486015263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000165f90815260059092529084902093516319400de160e21b8152929361010090910490911691636500378491611a89918591908b908b90600401613921565b6020604051808303815f875af1158015611aa5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac9919061365c565b979650505050505050565b5f516020613bec5f395f51905f52611aeb81611f01565b6001805461ffff60e81b1916600160e81b61ffff8516908102919091179091556040519081527f7af0ac740036ffb1c97b03697859d729e80a44ae5030543d64971c313565ab4d9060200160405180910390a15050565b5f516020613bec5f395f51905f52611b5981611f01565b816001600160a01b038116611b815760405163f44a4d1760e01b815260040160405180910390fd5b6001805474ffffffffffffffffffffffffffffffffffffffff0019166101006001600160a01b038616908102919091179091556040519081527f1399be28223800f8669b3ba5f8721d9fc16fc4e8d0bbf98378791c8c5a3015e0906020016112fa565b5f83611bef81610d76565b611c0c57604051634ab5ebcd60e01b815260040160405180910390fd5b611c14612423565b604080516060810182526002546001600160a01b03908116825287811660208084019190915260015461ffff600160e81b8204168486015263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000165f90815260059092529084902093516319be3d4f60e11b815292936101009091049091169163337c7a9e91611cb1918591908a908a90600401613921565b602060405180830381865afa158015611ccc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cf0919061365c565b9695505050505050565b5f516020613bec5f395f51905f52611d1181611f01565b63ffffffff84165f90815260036020526040902061198b9084846129d2565b611d38611f2e565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016630c0c389e60e08301353460208501611d7b8187612c81565b6080870135611d8d60a08901896137cf565b611d9a60c08b018b6137cf565b6040518a63ffffffff1660e01b8152600401611dbc979695949392919061384e565b5f604051808303818589803b158015611dd3575f5ffd5b5088f19450505050508015611de6575060015b611ed0573d808015611e13576040519150601f19603f3d011682016040523d82523d5f602084013e611e18565b606091505b506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016636bf73fa360208401611e568186612c81565b608086013560e087013534611e6e60a08a018a6137cf565b611e7b60c08c018c6137cf565b8b6040518b63ffffffff1660e01b8152600401611ea19a999897969594939291906138a4565b5f604051808303815f87803b158015611eb8575f5ffd5b505af1158015611eca573d5f5f3e3d5ffd5b50505050505b611eda6001600455565b50565b5f82815260208190526040902060010154611ef781611f01565b61083e8383612449565b611eda81336124ec565b6001600160a01b038316611f235761094f8282612543565b61094f8383836125ec565b600260045403611f5157604051633ee5aeb560e01b815260040160405180910390fd5b6002600455565b611f60612423565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a1565b611fb4612627565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33611f8f565b5f610d6f611ff3848461264a565b90565b5f612005600d600984866139c9565b61200e916139f0565b60e01c9392505050565b5f612027602d600d84866139c9565b610d6f91613a28565b5f61203f6009600184866139c9565b61204891613a45565b60c01c9392505050565b6040805163861e1ca560e01b8152835163ffffffff16600482015260208401516024820152908301516001600160401b031660448201526001600160a01b0382811660648301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063861e1ca590608401602060405180830381865afa925050508015612102575060408051601f3d908101601f191682019092526120ff91810190613408565b60015b61210d57505f610874565b9050610874565b5f61214184847f000000000000000000000000000000000000000000000000000000000000000085612659565b61214c57505f610d6f565b83516020850151604080870151905163c9fc7bcd60e01b81526001600160a01b03878116600483015263ffffffff909416602482015260448101929092526001600160401b0316606482015283917f0000000000000000000000000000000000000000000000000000000000000000169063c9fc7bcd90608401602060405180830381865afa1580156121e1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612205919061365c565b0361221157505f610d6f565b5060019392505050565b5f7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8314801561226b57505f838152602081815260408083206001600160a01b038616845290915290205460ff16155b156122b5576001805460159061229090600160a81b90046001600160401b0316613a7b565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505b610d6f83836127da565b5f8281816001600160401b038111156122da576122da61313d565b604051908082528060200260200182016040528015612303578160200160208202803683370190505b5090505f5b828110156123d5575f87878381811061232357612323613423565b9050604002018036038101906123399190613aa5565b90505f815f01516001600160a01b0316826020015188906040515f60405180830381858888f193505050503d805f811461238e576040519150601f19603f3d011682016040523d82523d5f602084013e612393565b606091505b50509050808484815181106123aa576123aa613423565b9115156020928302919091018201528201516123c69087613afc565b95505050806001019050612308565b507f1f48172553121d8bf273ce457a5a3dd180d464e0add3e0143045b7fa039c346889898989898660405161240f96959493929190613b41565b60405180910390a150509695505050505050565b60015460ff16156124475760405163d93c066560e01b815260040160405180910390fd5b565b5f7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8314801561249857505f838152602081815260408083206001600160a01b038616845290915290205460ff165b156124e257600180546015906124bd90600160a81b90046001600160401b0316613bca565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505b610d6f8383612881565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16610a8a5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b6001600160a01b03821661256a576040516306b7a93160e41b815260040160405180910390fd5b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146125b3576040519150601f19603f3d011682016040523d82523d5f602084013e6125b8565b606091505b505090508061094f57604051631196f20d60e21b81526001600160a01b03841660048201526024810183905260440161253a565b6001600160a01b038216612613576040516306b7a93160e41b815260040160405180910390fd5b61094f6001600160a01b0384168383612902565b60015460ff1661244757604051638dfc202b60e01b815260040160405180910390fd5b5f6120276051603184866139c9565b8351604051639d7f977560e01b81526001600160a01b03858116600483015263ffffffff909216602482015283821660448201525f917f00000000000000000000000000000000000000000000000000000000000000001690639d7f977590606401602060405180830381865afa1580156126d6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126fa9190613408565b61270557505f6127d2565b6040805163c9a54a9960e01b8152865163ffffffff16600482015260208701516024820152908601516001600160401b031660448201526001600160a01b0385811660648301527f0000000000000000000000000000000000000000000000000000000000000000169063c9a54a9990608401602060405180830381865afa158015612793573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127b79190613408565b6127c257505f6127d2565b816127ce57505f6127d2565b5060015b949350505050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1661287a575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556128323390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610874565b505f610874565b5f828152602081815260408083206001600160a01b038516845290915281205460ff161561287a575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610874565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b178152825161094f93879390925f9283929183919082885af180612985576040513d5f823e3d81fd5b50505f513d9150811561299c5780600114156129a9565b6001600160a01b0384163b155b1561083e57604051635274afe760e01b81526001600160a01b038516600482015260240161253a565b828054828255905f5260205f2090601f01602090048101928215612a66579160200282015f5b83821115612a3857833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f010492830192600103026129f8565b8015612a645782816101000a81549060ff02191690556001016020815f01049283019260010302612a38565b505b50612a72929150612a76565b5090565b5b80821115612a72575f8155600101612a77565b6001600160a01b0381168114611eda575f5ffd5b5f5f5f60608486031215612ab0575f5ffd5b8335612abb81612a8a565b92506020840135612acb81612a8a565b929592945050506040919091013590565b5f60208284031215612aec575f5ffd5b81356001600160e01b031981168114610d6f575f5ffd5b5f5f83601f840112612b13575f5ffd5b5081356001600160401b03811115612b29575f5ffd5b602083019150836020828501011115612b40575f5ffd5b9250929050565b5f5f5f60408486031215612b59575f5ffd5b83356001600160401b03811115612b6e575f5ffd5b612b7a86828701612b03565b909790965060209590950135949350505050565b8015158114611eda575f5ffd5b5f60208284031215612bab575f5ffd5b8135610d6f81612b8e565b5f60208284031215612bc6575f5ffd5b5035919050565b803563ffffffff81168114610e25575f5ffd5b5f60208284031215612bf0575f5ffd5b610d6f82612bcd565b602080825282518282018190525f918401906040840190835b81811015612c3357835160ff16835260209384019390920191600101612c12565b509095945050505050565b634e487b7160e01b5f52602160045260245ffd5b60048110611eda57634e487b7160e01b5f52602160045260245ffd5b60208101612c7b83612c52565b91905290565b5f60208284031215612c91575f5ffd5b8135610d6f81612a8a565b5f5f60408385031215612cad575f5ffd5b823591506020830135612cbf81612a8a565b809150509250929050565b5f5f60208385031215612cdb575f5ffd5b82356001600160401b03811115612cf0575f5ffd5b8301601f81018513612d00575f5ffd5b80356001600160401b03811115612d15575f5ffd5b85602060c083028401011115612d29575f5ffd5b6020919091019590945092505050565b5f5f83601f840112612d49575f5ffd5b5081356001600160401b03811115612d5f575f5ffd5b6020830191508360208260061b8501011115612b40575f5ffd5b5f5f5f5f5f5f86880360e0811215612d8f575f5ffd5b6060811215612d9c575f5ffd5b50869550612dac60608801612bcd565b94506080870135612dbc81612a8a565b935060a08701356001600160401b03811115612dd6575f5ffd5b612de289828a01612d39565b979a969950949794969560c090950135949350505050565b5f5f5f5f5f60808688031215612e0e575f5ffd5b612e1786612bcd565b94506020860135612e2781612a8a565b93506040860135925060608601356001600160401b03811115612e48575f5ffd5b612e5488828901612b03565b969995985093965092949392505050565b803561ffff81168114610e25575f5ffd5b5f5f5f5f5f5f5f5f5f60e08a8c031215612e8e575f5ffd5b8935612e9981612a8a565b985060208a0135612ea981612a8a565b975060408a01359650612ebe60608b01612e65565b955060808a01356001600160401b03811115612ed8575f5ffd5b612ee48c828d01612b03565b90965094505060a08a01356001600160401b03811115612f02575f5ffd5b612f0e8c828d01612b03565b9a9d999c50979a9699959894979660c00135949350505050565b5f6101008284031215612f39575f5ffd5b50919050565b5f5f5f5f60608587031215612f52575f5ffd5b84356001600160401b03811115612f67575f5ffd5b612f7387828801612d39565b9095509350506020850135915060408501356001600160401b03811115612f98575f5ffd5b612fa487828801612f28565b91505092959194509250565b5f5f5f60408486031215612fc2575f5ffd5b8335612fcd81612a8a565b925060208401356001600160401b03811115612fe7575f5ffd5b612ff386828701612b03565b9497909650939450505050565b5f60208284031215613010575f5ffd5b610d6f82612e65565b5f5f5f6040848603121561302b575f5ffd5b61303484612bcd565b925060208401356001600160401b0381111561304e575f5ffd5b8401601f8101861361305e575f5ffd5b80356001600160401b03811115613073575f5ffd5b8660208260051b8401011115613087575f5ffd5b939660209190910195509293505050565b5f602082840312156130a8575f5ffd5b81356001600160401b038111156130bd575f5ffd5b6127d284828501612f28565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f6131046040830185876130c9565b9050826020830152949350505050565b604081525f6131276040830185876130c9565b905063ffffffff83166020830152949350505050565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b03811182821017156131735761317361313d565b60405290565b604051601f8201601f191681016001600160401b03811182821017156131a1576131a161313d565b604052919050565b6001600160401b0381168114611eda575f5ffd5b8051610e25816131a9565b805160ff81168114610e25575f5ffd5b5f82601f8301126131e7575f5ffd5b81516001600160401b038111156132005761320061313d565b8060051b61321060208201613179565b9182526020818501810192908101908684111561322b575f5ffd5b6020860192505b83831015611cf057825161324581612a8a565b825260209283019290910190613232565b5f60208284031215613266575f5ffd5b81516001600160401b0381111561327b575f5ffd5b820160c0818503121561328c575f5ffd5b613294613151565b61329d826131bd565b81526132ab602083016131c8565b60208201526132bc604083016131c8565b60408201526132cd606083016131c8565b606082015260808201516001600160401b038111156132ea575f5ffd5b6132f6868285016131d8565b60808301525060a08201516001600160401b03811115613314575f5ffd5b613320868285016131d8565b60a083015250949350505050565b818382375f9101908152919050565b5f8151808452602084019350602083015f5b828110156133765781516001600160a01b031686526020958601959091019060010161334f565b5093949350505050565b606081526001600160401b03845116606082015260ff602085015116608082015260ff60408501511660a082015260ff60608501511660c08201525f608085015160c060e08401526133d661012084018261333d565b905060a0860151605f19848303016101008501526133f4828261333d565b602085019690965250505060400152919050565b5f60208284031215613418575f5ffd5b8151610d6f81612b8e565b634e487b7160e01b5f52603260045260245ffd5b80356001600160801b0381168114610e25575f5ffd5b5f60c082840312801561345e575f5ffd5b50613467613151565b61347083612bcd565b81526020830135613480816131a9565b60208201526040830135613493816131a9565b60408201526134a460608401612e65565b60608201526134b560808401613437565b60808201526134c660a08401613437565b60a08201529392505050565b602080825281018290525f8360408301825b858110156135905763ffffffff6134fa84612bcd565b168252602083013561350b816131a9565b6001600160401b031660208301526040830135613527816131a9565b6001600160401b0316604083015261ffff61354460608501612e65565b1660608301526001600160801b0361355e60808501613437565b16608083015261357060a08401613437565b6001600160801b031660a083015260c092830192909101906001016134e4565b5095945050505050565b6001600160a01b03855116815263ffffffff60208601511660208201526001600160a01b0360408601511660408201526060850151606082015261ffff608086015116608082015261364360a082018580546001600160401b038116835261ffff8160401c1660208401526001600160801b038160501c1660408401525060018101546001600160801b03811660608401526001600160401b038160801c166080840152505050565b6101606101408201525f611cf0610160830184866130c9565b5f6020828403121561366c575f5ffd5b5051919050565b5f60208284031215613683575f5ffd5b8151610d6f816131a9565b6001600160a01b03891681526001600160a01b038816602082015286604082015261ffff8616606082015260c060808201525f6136cf60c0830186886130c9565b82810360a08401526136e28185876130c9565b9b9a5050505050505050505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038c1681526001600160a01b038b16602082015289604082015261ffff891660608201528760808201528660a082015261012060c08201525f61376e610120830187896130c9565b82810360e08401526137818186886130c9565b905082810361010084015261379681856136f1565b9e9d5050505050505050505050505050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610874576108746137a8565b5f5f8335601e198436030181126137e4575f5ffd5b8301803591506001600160401b038211156137fd575f5ffd5b602001915036819003821315612b40575f5ffd5b63ffffffff61381f82612bcd565b16825260208181013590830152604081013561383a816131a9565b6001600160401b0381166040840152505050565b6138588189613811565b6001600160a01b038716606082015285608082015260e060a08201525f61388360e0830186886130c9565b82810360c08401526138968185876130c9565b9a9950505050505050505050565b6138ae818c613811565b6001600160a01b038a1660608201528860808201528760a08201528660c082015261014060e08201525f6138e7610140830187896130c9565b8281036101008401526138fb8186886130c9565b905082810361012084015261391081856136f1565b9d9c50505050505050505050505050565b6001600160a01b0385511681526001600160a01b03602086015116602082015261ffff60408601511660408201526139b0606082018580546001600160401b038116835261ffff8160401c1660208401526001600160801b038160501c1660408401525060018101546001600160801b03811660608401526001600160401b038160801c166080840152505050565b6101206101008201525f611cf0610120830184866130c9565b5f5f858511156139d7575f5ffd5b838611156139e3575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015613a21576001600160e01b0319600485900360031b81901b82161691505b5092915050565b80356020831015610874575f19602084900360031b1b1692915050565b80356001600160c01b03198116906008841015613a21576001600160c01b031960089490940360031b84901b1690921692915050565b5f6001600160401b0382166001600160401b038103613a9c57613a9c6137a8565b60010192915050565b5f6040828403128015613ab6575f5ffd5b50604080519081016001600160401b0381118282101715613ad957613ad961313d565b6040528235613ae781612a8a565b81526020928301359281019290925250919050565b80820180821115610874576108746137a8565b5f8151808452602084019350602083015f5b828110156133765781511515865260209586019590910190600101613b21565b5f60e08201613b50838a613811565b63ffffffff881660608401526001600160a01b038716608084015260e060a08401528490528461010083015f5b86811015613bb7578235613b9081612a8a565b6001600160a01b031682526020838101359083015260409283019290910190600101613b7d565b5083810360c08501526138968186613b0f565b5f6001600160401b03821680613be257613be26137a8565b5f19019291505056fea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220978432c8ea204632d1c1a08323f4a92762b72a1424e76fa94185a4ceda465cd464736f6c634300081e00330000000000000000000000001a44076050125825900e736c501f859c50fe728c000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c200000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000c03f31fd86a9077785b7bcf6598ce3598fa91113000000000000000000000000f6ea1b046522fe5a58124555b1acbc77fabdd7e500000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2ea70c9e858123480642cf96acbcce1372dce10000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f6ea1b046522fe5a58124555b1acbc77fabdd7e5

Deployed Bytecode

0x608060405260043610610227575f3560e01c8063717e8a4211610129578063c358de0a116100a8578063cd88b9031161006d578063cd88b90314610745578063cfc3257014610764578063d2ae210414610777578063d547741f146107b5578063da2eb165146107d4575f5ffd5b8063c358de0a146106c4578063c416aa51146106e3578063c7b2370b14610707578063c8f8dcd114610726578063cb5026b914610692575f5ffd5b80638624ba07116100ee5780638624ba071461058b57806391d148541461059e5780639e944965146105e0578063a217fddf14610692578063c015bb7d146106a5575f5ffd5b8063717e8a42146104fc578063724e78da1461051b5780637401fccc1461053a578063741bef1a146105595780637cd4473414610578575f5ffd5b806327d12cd9116101b55780633d85ac331161017a5780633d85ac3314610461578063475b6d9e146104805780635c975abb146104935780636fad06f5146104aa578063709eb664146104dd575f5ffd5b806327d12cd9146103c45780632baf0be7146103f05780632de11376146104045780632f2ff15d1461042357806336568abe14610442575f5ffd5b80631095b6d7116101fb5780631095b6d7146102d357806316c38b3c146102f2578063248a9ca314610311578063252f5e3e1461034d57806326e67a3714610398575f5ffd5b8062bf2e801461022b57806301e336671461026457806301ffc9a7146102855780630894edf1146102b4575b5f5ffd5b348015610236575f5ffd5b5060015461024c90600160e81b900461ffff1681565b60405161ffff90911681526020015b60405180910390f35b34801561026f575f5ffd5b5061028361027e366004612a9e565b61081c565b005b348015610290575f5ffd5b506102a461029f366004612adc565b610844565b604051901515815260200161025b565b3480156102bf575f5ffd5b506102836102ce366004612b47565b61087a565b3480156102de575f5ffd5b506102836102ed366004612a9e565b610954565b3480156102fd575f5ffd5b5061028361030c366004612b9b565b610a72565b34801561031c575f5ffd5b5061033f61032b366004612bb6565b5f9081526020819052604090206001015490565b60405190815260200161025b565b348015610358575f5ffd5b506103807f000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c281565b6040516001600160a01b03909116815260200161025b565b3480156103a3575f5ffd5b506103b76103b2366004612be0565b610a96565b60405161025b9190612bf9565b3480156103cf575f5ffd5b506103e36103de366004612b47565b610b19565b60405161025b9190612c6e565b3480156103fb575f5ffd5b5061033f5f1981565b34801561040f575f5ffd5b506102a461041e366004612c81565b610d76565b34801561042e575f5ffd5b5061028361043d366004612c9c565b610e2a565b34801561044d575f5ffd5b5061028361045c366004612c9c565b610e4e565b34801561046c575f5ffd5b5061028361047b366004612cca565b610e67565b61028361048e366004612d79565b610ff1565b34801561049e575f5ffd5b5060015460ff166102a4565b3480156104b5575f5ffd5b506103807f0000000000000000000000001a44076050125825900e736c501f859c50fe728c81565b3480156104e8575f5ffd5b5061033f6104f7366004612dfa565b611032565b348015610507575f5ffd5b5061033f610516366004612dfa565b611135565b348015610526575f5ffd5b50610283610535366004612c81565b611264565b348015610545575f5ffd5b506103e3610554366004612b47565b611307565b348015610564575f5ffd5b50600254610380906001600160a01b031681565b610283610586366004612e76565b611617565b610283610599366004612f3f565b61177e565b3480156105a9575f5ffd5b506102a46105b8366004612c9c565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b3480156105eb575f5ffd5b5061064f6105fa366004612be0565b60056020525f9081526040902080546001909101546001600160401b038083169261ffff68010000000000000000820416926001600160801b03600160501b90920482169291811691600160801b9091041685565b604080516001600160401b03968716815261ffff90951660208601526001600160801b03938416908501529116606083015291909116608082015260a00161025b565b34801561069d575f5ffd5b5061033f5f81565b3480156106b0575f5ffd5b5061033f6106bf366004612fb0565b611992565b3480156106cf575f5ffd5b506102836106de366004613000565b611ad4565b3480156106ee575f5ffd5b506001546103809061010090046001600160a01b031681565b348015610712575f5ffd5b50610283610721366004612c81565b611b42565b348015610731575f5ffd5b5061033f610740366004612fb0565b611be4565b348015610750575f5ffd5b5061028361075f366004613019565b611cfa565b610283610772366004613098565b611d30565b348015610782575f5ffd5b5060015461079d90600160a81b90046001600160401b031681565b6040516001600160401b03909116815260200161025b565b3480156107c0575f5ffd5b506102836107cf366004612c9c565b611edd565b3480156107df575f5ffd5b506108077f000000000000000000000000000000000000000000000000000000000000759581565b60405163ffffffff909116815260200161025b565b5f516020613bec5f395f51905f5261083381611f01565b61083e848484611f0b565b50505050565b5f6001600160e01b03198216637965db0b60e01b148061087457506301ffc9a760e01b6001600160e01b03198316145b92915050565b610882611f2e565b5f61088e848484610b19565b905060018160038111156108a4576108a4612c3e565b0361092b57604051630894edf160e01b81526001600160a01b037f000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c21690630894edf1906108f9908790879087906004016130f1565b5f604051808303815f87803b158015610910575f5ffd5b505af1158015610922573d5f5f3e3d5ffd5b50505050610944565b604051633152adcf60e11b815260040160405180910390fd5b5061094f6001600455565b505050565b5f516020613bec5f395f51905f5261096b81611f01565b6001600160a01b0384165f9081527f9b50f4667d2d24216ccbf0dce3a90c0f620fa4d895e7b069d80ff6247fd25620602052604090205460ff166109c257604051635ee08b9760e01b815260040160405180910390fd5b604051637ecdf29160e11b81526001600160a01b0384811660048301526024820184905285169063fd9be522906044015f604051808303815f87803b158015610a09575f5ffd5b505af1158015610a1b573d5f5f3e3d5ffd5b5050604080516001600160a01b038089168252871660208201529081018590527f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb925060600190505b60405180910390a150505050565b5f610a7c81611f01565b8115610a8e57610a8a611f58565b5050565b610a8a611fac565b63ffffffff81165f90815260036020908152604091829020805483518184028101840190945280845260609392830182828015610b0d57602002820191905f5260205f20905f905b825461010083900a900460ff16815260206001928301818104948501949093039092029101808411610ade5790505b50505050509050919050565b60405163c40ff83560e01b81525f906001600160a01b037f000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c2169063c40ff83590610b8b90879087907f000000000000000000000000000000000000000000000000000000000000759590600401613114565b5f6040518083038186803b158015610ba1575f5ffd5b505afa158015610bb3573d5f5f3e3d5ffd5b505050505f610bc28585611fe5565b90505f6040518060600160405280610bda8888611ff6565b63ffffffff168152602001610bef8888612018565b8152602001610bfe8888612030565b6001600160401b031690529050610c158183612052565b610c2457600392505050610d6f565b610c2f818386612114565b610c3e57600292505050610d6f565b80516040516343ea4fa960e01b81526001600160a01b03848116600483015263ffffffff90921660248201527f000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c29091169063e084d9529082906343ea4fa9906044015f60405180830381865afa158015610cba573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610ce19190810190613256565b8888604051610cf192919061332e565b6040519081900381206001600160e01b031960e085901b168252610d1a92918990600401613380565b602060405180830381865afa158015610d35573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d599190613408565b15610d6957600192505050610d6f565b5f925050505b9392505050565b6001600160a01b0381165f9081527f93c430521711328044ae92d0f1f1286cf040bc4a382f1642bd89984e86630553602052604081205460ff1615610dbc57505f919050565b600154600160a81b90046001600160401b03161580610e1157506001600160a01b0382165f9081527f4ac82e3087b7dedf7f532cbc6915c722df8c1e31f1388c318a617b52760eaf8b602052604090205460ff165b15610e1e57506001919050565b505f919050565b919050565b5f82815260208190526040902060010154610e4481611f01565b61083e838361221b565b60405163dec9f03160e01b815260040160405180910390fd5b5f516020613bec5f395f51905f52610e7e81611f01565b815f5b81811015610fbf575f858583818110610e9c57610e9c613423565b905060c00201803603810190610eb2919061344d565b6040805160a080820183526020808501516001600160401b03908116845260608087015161ffff9081168487019081526080808a01516001600160801b03908116898b01908152978b01518116948901948552898b01518616918901918252995163ffffffff165f90815260059096529790942095518654945195518916600160501b027fffffffffffff00000000000000000000000000000000ffffffffffffffffffff96909216680100000000000000000269ffffffffffffffffffff199095169084161793909317939093169190911783559051600192830180549451909216600160801b026001600160c01b031990941694169390931791909117909155919091019050610e81565b507fb99f6de5e22c60c178b03bfacf2daeb4b6089f5b37e0fe2c48a5d5141191fc538484604051610a649291906134d2565b5f516020613bec5f395f51905f5261100881611f01565b611010611f2e565b61101e8787878787876122bf565b506110296001600455565b50505050505050565b5f8461103d81610d76565b61105a57604051634ab5ebcd60e01b815260040160405180910390fd5b611062612423565b6040805160a0810182526002546001600160a01b03908116825263ffffffff8a1660208084018290528a831684860152606084018a905260015461ffff600160e81b82041660808601525f92835260059091529084902093516321a7700b60e11b815292936101009091049091169163434ee016916110ea918591908a908a9060040161359a565b602060405180830381865afa158015611105573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611129919061365c565b98975050505050505050565b5f7f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de61116081611f01565b8561116a81610d76565b61118757604051634ab5ebcd60e01b815260040160405180910390fd5b61118f612423565b6040805160a0810182526002546001600160a01b03908116825263ffffffff8b1660208084018290528b831684860152606084018b905260015461ffff600160e81b82041660808601525f9283526005909152908490209351632b377bb160e11b815292936101009091049091169163566ef76291611217918591908b908b9060040161359a565b6020604051808303815f875af1158015611233573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611257919061365c565b9998505050505050505050565b5f516020613bec5f395f51905f5261127b81611f01565b816001600160a01b0381166112a35760405163f44a4d1760e01b815260040160405180910390fd5b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385169081179091556040519081527ff724a45d041687842411f2b977ef22ab8f43c8f1104f4592b42a00f9b34a643d906020015b60405180910390a1505050565b5f5f6113138585611fe5565b90505f604051806060016040528061132b8888611ff6565b63ffffffff1681526020016113408888612018565b815260200161134f8888612030565b6001600160401b0316905280516020820151604080840151905163c9fc7bcd60e01b81529394505f936001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c169363c9fc7bcd936113e79389936004016001600160a01b0394909416845263ffffffff92909216602084015260408301526001600160401b0316606082015260800190565b602060405180830381865afa158015611402573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611426919061365c565b9050801580156114f15750815160208301516040516305b17bb760e41b81526001600160a01b03868116600483015263ffffffff909316602482015260448101919091527f0000000000000000000000001a44076050125825900e736c501f859c50fe728c90911690635b17bb7090606401602060405180830381865afa1580156114b3573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114d79190613673565b6001600160401b031682604001516001600160401b031611155b156115025760039350505050610d6f565b5f19811480159061151257508481145b80156115d957508151602083015160405163283750ff60e21b81526001600160a01b03868116600483015263ffffffff909316602482015260448101919091527f0000000000000000000000001a44076050125825900e736c501f859c50fe728c9091169063a0dd43fc90606401602060405180830381865afa15801561159b573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115bf9190613673565b6001600160401b031682604001516001600160401b031611155b156115ea5760029350505050610d6f565b80158015906115fa57505f198114155b1561160b5760019350505050610d6f565b505f9695505050505050565b61161f611f2e565b6040516391d20fa160e01b81526001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c16906391d20fa1908390349061167d908e908e908e908e908e908e908e908e9060040161368e565b5f604051808303818589803b158015611694575f5ffd5b5088f194505050505080156116a7575060015b611769573d8080156116d4576040519150601f19603f3d011682016040523d82523d5f602084013e6116d9565b606091505b506040516334bff35b60e11b81526001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c169063697fe6b69061173a908d908d908d908d90899034908f908f908f908f908e9060040161371f565b5f604051808303815f87803b158015611751575f5ffd5b505af1158015611763573d5f5f3e3d5ffd5b50505050505b6117736001600455565b505050505050505050565b5f516020613bec5f395f51905f5261179581611f01565b61179d611f2e565b5f6117d8602084017f00000000000000000000000000000000000000000000000000000000000075956117d08287612c81565b8989896122bf565b90505f6117e582346137bc565b90506001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c16630c0c389e60e0860135836020880161182a818a612c81565b60808a013561183c60a08c018c6137cf565b61184960c08e018e6137cf565b6040518a63ffffffff1660e01b815260040161186b979695949392919061384e565b5f604051808303818589803b158015611882575f5ffd5b5088f19450505050508015611895575060015b61197f573d8080156118c2576040519150601f19603f3d011682016040523d82523d5f602084013e6118c7565b606091505b506001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c16636bf73fa3602087016119058189612c81565b608089013560e08a01358761191d60a08d018d6137cf565b61192a60c08f018f6137cf565b8b6040518b63ffffffff1660e01b81526004016119509a999897969594939291906138a4565b5f604051808303815f87803b158015611967575f5ffd5b505af1158015611979573d5f5f3e3d5ffd5b50505050505b505061198b6001600455565b5050505050565b5f7f724aface199fe5bed93ae8508474576a9adf3dc443b2c451842a2242919f19de6119bd81611f01565b846119c781610d76565b6119e457604051634ab5ebcd60e01b815260040160405180910390fd5b6119ec612423565b604080516060810182526002546001600160a01b03908116825288811660208084019190915260015461ffff600160e81b8204168486015263ffffffff7f0000000000000000000000000000000000000000000000000000000000007595165f90815260059092529084902093516319400de160e21b8152929361010090910490911691636500378491611a89918591908b908b90600401613921565b6020604051808303815f875af1158015611aa5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ac9919061365c565b979650505050505050565b5f516020613bec5f395f51905f52611aeb81611f01565b6001805461ffff60e81b1916600160e81b61ffff8516908102919091179091556040519081527f7af0ac740036ffb1c97b03697859d729e80a44ae5030543d64971c313565ab4d9060200160405180910390a15050565b5f516020613bec5f395f51905f52611b5981611f01565b816001600160a01b038116611b815760405163f44a4d1760e01b815260040160405180910390fd5b6001805474ffffffffffffffffffffffffffffffffffffffff0019166101006001600160a01b038616908102919091179091556040519081527f1399be28223800f8669b3ba5f8721d9fc16fc4e8d0bbf98378791c8c5a3015e0906020016112fa565b5f83611bef81610d76565b611c0c57604051634ab5ebcd60e01b815260040160405180910390fd5b611c14612423565b604080516060810182526002546001600160a01b03908116825287811660208084019190915260015461ffff600160e81b8204168486015263ffffffff7f0000000000000000000000000000000000000000000000000000000000007595165f90815260059092529084902093516319be3d4f60e11b815292936101009091049091169163337c7a9e91611cb1918591908a908a90600401613921565b602060405180830381865afa158015611ccc573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611cf0919061365c565b9695505050505050565b5f516020613bec5f395f51905f52611d1181611f01565b63ffffffff84165f90815260036020526040902061198b9084846129d2565b611d38611f2e565b6001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c16630c0c389e60e08301353460208501611d7b8187612c81565b6080870135611d8d60a08901896137cf565b611d9a60c08b018b6137cf565b6040518a63ffffffff1660e01b8152600401611dbc979695949392919061384e565b5f604051808303818589803b158015611dd3575f5ffd5b5088f19450505050508015611de6575060015b611ed0573d808015611e13576040519150601f19603f3d011682016040523d82523d5f602084013e611e18565b606091505b506001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c16636bf73fa360208401611e568186612c81565b608086013560e087013534611e6e60a08a018a6137cf565b611e7b60c08c018c6137cf565b8b6040518b63ffffffff1660e01b8152600401611ea19a999897969594939291906138a4565b5f604051808303815f87803b158015611eb8575f5ffd5b505af1158015611eca573d5f5f3e3d5ffd5b50505050505b611eda6001600455565b50565b5f82815260208190526040902060010154611ef781611f01565b61083e8383612449565b611eda81336124ec565b6001600160a01b038316611f235761094f8282612543565b61094f8383836125ec565b600260045403611f5157604051633ee5aeb560e01b815260040160405180910390fd5b6002600455565b611f60612423565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258335b6040516001600160a01b03909116815260200160405180910390a1565b611fb4612627565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33611f8f565b5f610d6f611ff3848461264a565b90565b5f612005600d600984866139c9565b61200e916139f0565b60e01c9392505050565b5f612027602d600d84866139c9565b610d6f91613a28565b5f61203f6009600184866139c9565b61204891613a45565b60c01c9392505050565b6040805163861e1ca560e01b8152835163ffffffff16600482015260208401516024820152908301516001600160401b031660448201526001600160a01b0382811660648301525f917f0000000000000000000000001a44076050125825900e736c501f859c50fe728c9091169063861e1ca590608401602060405180830381865afa925050508015612102575060408051601f3d908101601f191682019092526120ff91810190613408565b60015b61210d57505f610874565b9050610874565b5f61214184847f000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c285612659565b61214c57505f610d6f565b83516020850151604080870151905163c9fc7bcd60e01b81526001600160a01b03878116600483015263ffffffff909416602482015260448101929092526001600160401b0316606482015283917f0000000000000000000000001a44076050125825900e736c501f859c50fe728c169063c9fc7bcd90608401602060405180830381865afa1580156121e1573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612205919061365c565b0361221157505f610d6f565b5060019392505050565b5f7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8314801561226b57505f838152602081815260408083206001600160a01b038616845290915290205460ff16155b156122b5576001805460159061229090600160a81b90046001600160401b0316613a7b565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505b610d6f83836127da565b5f8281816001600160401b038111156122da576122da61313d565b604051908082528060200260200182016040528015612303578160200160208202803683370190505b5090505f5b828110156123d5575f87878381811061232357612323613423565b9050604002018036038101906123399190613aa5565b90505f815f01516001600160a01b0316826020015188906040515f60405180830381858888f193505050503d805f811461238e576040519150601f19603f3d011682016040523d82523d5f602084013e612393565b606091505b50509050808484815181106123aa576123aa613423565b9115156020928302919091018201528201516123c69087613afc565b95505050806001019050612308565b507f1f48172553121d8bf273ce457a5a3dd180d464e0add3e0143045b7fa039c346889898989898660405161240f96959493929190613b41565b60405180910390a150509695505050505050565b60015460ff16156124475760405163d93c066560e01b815260040160405180910390fd5b565b5f7f74845de37cfabd357633214b47fa91ccd19b05b7c5a08ac22c187f811fb62bca8314801561249857505f838152602081815260408083206001600160a01b038616845290915290205460ff165b156124e257600180546015906124bd90600160a81b90046001600160401b0316613bca565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505b610d6f8383612881565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16610a8a5760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b6001600160a01b03821661256a576040516306b7a93160e41b815260040160405180910390fd5b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f81146125b3576040519150601f19603f3d011682016040523d82523d5f602084013e6125b8565b606091505b505090508061094f57604051631196f20d60e21b81526001600160a01b03841660048201526024810183905260440161253a565b6001600160a01b038216612613576040516306b7a93160e41b815260040160405180910390fd5b61094f6001600160a01b0384168383612902565b60015460ff1661244757604051638dfc202b60e01b815260040160405180910390fd5b5f6120276051603184866139c9565b8351604051639d7f977560e01b81526001600160a01b03858116600483015263ffffffff909216602482015283821660448201525f917f0000000000000000000000001a44076050125825900e736c501f859c50fe728c1690639d7f977590606401602060405180830381865afa1580156126d6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126fa9190613408565b61270557505f6127d2565b6040805163c9a54a9960e01b8152865163ffffffff16600482015260208701516024820152908601516001600160401b031660448201526001600160a01b0385811660648301527f0000000000000000000000001a44076050125825900e736c501f859c50fe728c169063c9a54a9990608401602060405180830381865afa158015612793573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127b79190613408565b6127c257505f6127d2565b816127ce57505f6127d2565b5060015b949350505050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1661287a575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556128323390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610874565b505f610874565b5f828152602081815260408083206001600160a01b038516845290915281205460ff161561287a575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610874565b604080516001600160a01b03841660248201526044808201849052825180830390910181526064909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b178152825161094f93879390925f9283929183919082885af180612985576040513d5f823e3d81fd5b50505f513d9150811561299c5780600114156129a9565b6001600160a01b0384163b155b1561083e57604051635274afe760e01b81526001600160a01b038516600482015260240161253a565b828054828255905f5260205f2090601f01602090048101928215612a66579160200282015f5b83821115612a3857833560ff1683826101000a81548160ff021916908360ff16021790555092602001926001016020815f010492830192600103026129f8565b8015612a645782816101000a81549060ff02191690556001016020815f01049283019260010302612a38565b505b50612a72929150612a76565b5090565b5b80821115612a72575f8155600101612a77565b6001600160a01b0381168114611eda575f5ffd5b5f5f5f60608486031215612ab0575f5ffd5b8335612abb81612a8a565b92506020840135612acb81612a8a565b929592945050506040919091013590565b5f60208284031215612aec575f5ffd5b81356001600160e01b031981168114610d6f575f5ffd5b5f5f83601f840112612b13575f5ffd5b5081356001600160401b03811115612b29575f5ffd5b602083019150836020828501011115612b40575f5ffd5b9250929050565b5f5f5f60408486031215612b59575f5ffd5b83356001600160401b03811115612b6e575f5ffd5b612b7a86828701612b03565b909790965060209590950135949350505050565b8015158114611eda575f5ffd5b5f60208284031215612bab575f5ffd5b8135610d6f81612b8e565b5f60208284031215612bc6575f5ffd5b5035919050565b803563ffffffff81168114610e25575f5ffd5b5f60208284031215612bf0575f5ffd5b610d6f82612bcd565b602080825282518282018190525f918401906040840190835b81811015612c3357835160ff16835260209384019390920191600101612c12565b509095945050505050565b634e487b7160e01b5f52602160045260245ffd5b60048110611eda57634e487b7160e01b5f52602160045260245ffd5b60208101612c7b83612c52565b91905290565b5f60208284031215612c91575f5ffd5b8135610d6f81612a8a565b5f5f60408385031215612cad575f5ffd5b823591506020830135612cbf81612a8a565b809150509250929050565b5f5f60208385031215612cdb575f5ffd5b82356001600160401b03811115612cf0575f5ffd5b8301601f81018513612d00575f5ffd5b80356001600160401b03811115612d15575f5ffd5b85602060c083028401011115612d29575f5ffd5b6020919091019590945092505050565b5f5f83601f840112612d49575f5ffd5b5081356001600160401b03811115612d5f575f5ffd5b6020830191508360208260061b8501011115612b40575f5ffd5b5f5f5f5f5f5f86880360e0811215612d8f575f5ffd5b6060811215612d9c575f5ffd5b50869550612dac60608801612bcd565b94506080870135612dbc81612a8a565b935060a08701356001600160401b03811115612dd6575f5ffd5b612de289828a01612d39565b979a969950949794969560c090950135949350505050565b5f5f5f5f5f60808688031215612e0e575f5ffd5b612e1786612bcd565b94506020860135612e2781612a8a565b93506040860135925060608601356001600160401b03811115612e48575f5ffd5b612e5488828901612b03565b969995985093965092949392505050565b803561ffff81168114610e25575f5ffd5b5f5f5f5f5f5f5f5f5f60e08a8c031215612e8e575f5ffd5b8935612e9981612a8a565b985060208a0135612ea981612a8a565b975060408a01359650612ebe60608b01612e65565b955060808a01356001600160401b03811115612ed8575f5ffd5b612ee48c828d01612b03565b90965094505060a08a01356001600160401b03811115612f02575f5ffd5b612f0e8c828d01612b03565b9a9d999c50979a9699959894979660c00135949350505050565b5f6101008284031215612f39575f5ffd5b50919050565b5f5f5f5f60608587031215612f52575f5ffd5b84356001600160401b03811115612f67575f5ffd5b612f7387828801612d39565b9095509350506020850135915060408501356001600160401b03811115612f98575f5ffd5b612fa487828801612f28565b91505092959194509250565b5f5f5f60408486031215612fc2575f5ffd5b8335612fcd81612a8a565b925060208401356001600160401b03811115612fe7575f5ffd5b612ff386828701612b03565b9497909650939450505050565b5f60208284031215613010575f5ffd5b610d6f82612e65565b5f5f5f6040848603121561302b575f5ffd5b61303484612bcd565b925060208401356001600160401b0381111561304e575f5ffd5b8401601f8101861361305e575f5ffd5b80356001600160401b03811115613073575f5ffd5b8660208260051b8401011115613087575f5ffd5b939660209190910195509293505050565b5f602082840312156130a8575f5ffd5b81356001600160401b038111156130bd575f5ffd5b6127d284828501612f28565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b604081525f6131046040830185876130c9565b9050826020830152949350505050565b604081525f6131276040830185876130c9565b905063ffffffff83166020830152949350505050565b634e487b7160e01b5f52604160045260245ffd5b60405160c081016001600160401b03811182821017156131735761317361313d565b60405290565b604051601f8201601f191681016001600160401b03811182821017156131a1576131a161313d565b604052919050565b6001600160401b0381168114611eda575f5ffd5b8051610e25816131a9565b805160ff81168114610e25575f5ffd5b5f82601f8301126131e7575f5ffd5b81516001600160401b038111156132005761320061313d565b8060051b61321060208201613179565b9182526020818501810192908101908684111561322b575f5ffd5b6020860192505b83831015611cf057825161324581612a8a565b825260209283019290910190613232565b5f60208284031215613266575f5ffd5b81516001600160401b0381111561327b575f5ffd5b820160c0818503121561328c575f5ffd5b613294613151565b61329d826131bd565b81526132ab602083016131c8565b60208201526132bc604083016131c8565b60408201526132cd606083016131c8565b606082015260808201516001600160401b038111156132ea575f5ffd5b6132f6868285016131d8565b60808301525060a08201516001600160401b03811115613314575f5ffd5b613320868285016131d8565b60a083015250949350505050565b818382375f9101908152919050565b5f8151808452602084019350602083015f5b828110156133765781516001600160a01b031686526020958601959091019060010161334f565b5093949350505050565b606081526001600160401b03845116606082015260ff602085015116608082015260ff60408501511660a082015260ff60608501511660c08201525f608085015160c060e08401526133d661012084018261333d565b905060a0860151605f19848303016101008501526133f4828261333d565b602085019690965250505060400152919050565b5f60208284031215613418575f5ffd5b8151610d6f81612b8e565b634e487b7160e01b5f52603260045260245ffd5b80356001600160801b0381168114610e25575f5ffd5b5f60c082840312801561345e575f5ffd5b50613467613151565b61347083612bcd565b81526020830135613480816131a9565b60208201526040830135613493816131a9565b60408201526134a460608401612e65565b60608201526134b560808401613437565b60808201526134c660a08401613437565b60a08201529392505050565b602080825281018290525f8360408301825b858110156135905763ffffffff6134fa84612bcd565b168252602083013561350b816131a9565b6001600160401b031660208301526040830135613527816131a9565b6001600160401b0316604083015261ffff61354460608501612e65565b1660608301526001600160801b0361355e60808501613437565b16608083015261357060a08401613437565b6001600160801b031660a083015260c092830192909101906001016134e4565b5095945050505050565b6001600160a01b03855116815263ffffffff60208601511660208201526001600160a01b0360408601511660408201526060850151606082015261ffff608086015116608082015261364360a082018580546001600160401b038116835261ffff8160401c1660208401526001600160801b038160501c1660408401525060018101546001600160801b03811660608401526001600160401b038160801c166080840152505050565b6101606101408201525f611cf0610160830184866130c9565b5f6020828403121561366c575f5ffd5b5051919050565b5f60208284031215613683575f5ffd5b8151610d6f816131a9565b6001600160a01b03891681526001600160a01b038816602082015286604082015261ffff8616606082015260c060808201525f6136cf60c0830186886130c9565b82810360a08401526136e28185876130c9565b9b9a5050505050505050505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b038c1681526001600160a01b038b16602082015289604082015261ffff891660608201528760808201528660a082015261012060c08201525f61376e610120830187896130c9565b82810360e08401526137818186886130c9565b905082810361010084015261379681856136f1565b9e9d5050505050505050505050505050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610874576108746137a8565b5f5f8335601e198436030181126137e4575f5ffd5b8301803591506001600160401b038211156137fd575f5ffd5b602001915036819003821315612b40575f5ffd5b63ffffffff61381f82612bcd565b16825260208181013590830152604081013561383a816131a9565b6001600160401b0381166040840152505050565b6138588189613811565b6001600160a01b038716606082015285608082015260e060a08201525f61388360e0830186886130c9565b82810360c08401526138968185876130c9565b9a9950505050505050505050565b6138ae818c613811565b6001600160a01b038a1660608201528860808201528760a08201528660c082015261014060e08201525f6138e7610140830187896130c9565b8281036101008401526138fb8186886130c9565b905082810361012084015261391081856136f1565b9d9c50505050505050505050505050565b6001600160a01b0385511681526001600160a01b03602086015116602082015261ffff60408601511660408201526139b0606082018580546001600160401b038116835261ffff8160401c1660208401526001600160801b038160501c1660408401525060018101546001600160801b03811660608401526001600160401b038160801c166080840152505050565b6101206101008201525f611cf0610120830184866130c9565b5f5f858511156139d7575f5ffd5b838611156139e3575f5ffd5b5050820193919092039150565b80356001600160e01b03198116906004841015613a21576001600160e01b0319600485900360031b81901b82161691505b5092915050565b80356020831015610874575f19602084900360031b1b1692915050565b80356001600160c01b03198116906008841015613a21576001600160c01b031960089490940360031b84901b1690921692915050565b5f6001600160401b0382166001600160401b038103613a9c57613a9c6137a8565b60010192915050565b5f6040828403128015613ab6575f5ffd5b50604080519081016001600160401b0381118282101715613ad957613ad961313d565b6040528235613ae781612a8a565b81526020928301359281019290925250919050565b80820180821115610874576108746137a8565b5f8151808452602084019350602083015f5b828110156133765781511515865260209586019590910190600101613b21565b5f60e08201613b50838a613811565b63ffffffff881660608401526001600160a01b038716608084015260e060a08401528490528461010083015f5b86811015613bb7578235613b9081612a8a565b6001600160a01b031682526020838101359083015260409283019290910190600101613b7d565b5083810360c08501526138968186613b0f565b5f6001600160401b03821680613be257613be26137a8565b5f19019291505056fea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220978432c8ea204632d1c1a08323f4a92762b72a1424e76fa94185a4ceda465cd464736f6c634300081e0033

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

0000000000000000000000001a44076050125825900e736c501f859c50fe728c000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c200000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000c03f31fd86a9077785b7bcf6598ce3598fa91113000000000000000000000000f6ea1b046522fe5a58124555b1acbc77fabdd7e500000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000bb2ea70c9e858123480642cf96acbcce1372dce10000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f6ea1b046522fe5a58124555b1acbc77fabdd7e5

-----Decoded View---------------
Arg [0] : _endpoint (address): 0x1a44076050125825900e736c501f859c50fE728c
Arg [1] : _receiveUln302 (address): 0xc02Ab410f0734EFa3F14628780e6e695156024C2
Arg [2] : _messageLibs (address[]): 0xbB2Ea70C9E858123480642Cf96acbcCE1372dCe1
Arg [3] : _priceFeed (address): 0xC03f31fD86a9077785b7bCf6598Ce3598Fa91113
Arg [4] : _roleAdmin (address): 0xf6Ea1B046522fe5a58124555b1Acbc77FabdD7E5
Arg [5] : _admins (address[]): 0xf6Ea1B046522fe5a58124555b1Acbc77FabdD7E5

-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000001a44076050125825900e736c501f859c50fe728c
Arg [1] : 000000000000000000000000c02ab410f0734efa3f14628780e6e695156024c2
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [3] : 000000000000000000000000c03f31fd86a9077785b7bcf6598ce3598fa91113
Arg [4] : 000000000000000000000000f6ea1b046522fe5a58124555b1acbc77fabdd7e5
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 000000000000000000000000bb2ea70c9e858123480642cf96acbcce1372dce1
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 000000000000000000000000f6ea1b046522fe5a58124555b1acbc77fabdd7e5


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.