ETH Price: $3,380.30 (-0.21%)
Gas: 3 Gwei

Contract

0x272dfD47b3A4bc77DD8a667A327f1aCA15305FcC
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Renounce Manager...176350772023-07-06 13:23:23359 days ago1688649803IN
Interport: LayerZero Gateway v2
0 ETH0.0011173227.0113905
Transfer Ownersh...176350752023-07-06 13:22:59359 days ago1688649779IN
Interport: LayerZero Gateway v2
0 ETH0.0008424229.32530097
Set Manager176350712023-07-06 13:22:11359 days ago1688649731IN
Interport: LayerZero Gateway v2
0 ETH0.0026568827.07020915
Set Peers176349452023-07-06 12:56:35360 days ago1688648195IN
Interport: LayerZero Gateway v2
0 ETH0.0157607727.13332885
Renounce Manager...176340912023-07-06 10:02:59360 days ago1688637779IN
Interport: LayerZero Gateway v2
0 ETH0.0010774526.04739618
Set Client176340902023-07-06 10:02:47360 days ago1688637767IN
Interport: LayerZero Gateway v2
0 ETH0.00135527.07403666
0x60806040176340892023-07-06 10:02:35360 days ago1688637755IN
 Create: LayerZeroGatewayV2
0 ETH0.0747705524.91406648

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
202042742024-06-30 11:42:351 hr ago1719747755
Interport: LayerZero Gateway v2
0.00026346 ETH
202042742024-06-30 11:42:351 hr ago1719747755
Interport: LayerZero Gateway v2
0.00118329 ETH
202042742024-06-30 11:42:351 hr ago1719747755
Interport: LayerZero Gateway v2
0.00144675 ETH
201997562024-06-29 20:33:4716 hrs ago1719693227
Interport: LayerZero Gateway v2
0.00029449 ETH
201997562024-06-29 20:33:4716 hrs ago1719693227
Interport: LayerZero Gateway v2
0.00029449 ETH
201981142024-06-29 15:04:1121 hrs ago1719673451
Interport: LayerZero Gateway v2
0.00046364 ETH
201981142024-06-29 15:04:1121 hrs ago1719673451
Interport: LayerZero Gateway v2
0.00014783 ETH
201981142024-06-29 15:04:1121 hrs ago1719673451
Interport: LayerZero Gateway v2
0.00061148 ETH
201936902024-06-29 0:13:1136 hrs ago1719619991
Interport: LayerZero Gateway v2
0.00025638 ETH
201936902024-06-29 0:13:1136 hrs ago1719619991
Interport: LayerZero Gateway v2
0.0002965 ETH
201936902024-06-29 0:13:1136 hrs ago1719619991
Interport: LayerZero Gateway v2
0.00055288 ETH
201922332024-06-28 19:19:5941 hrs ago1719602399
Interport: LayerZero Gateway v2
0.00029547 ETH
201922332024-06-28 19:19:5941 hrs ago1719602399
Interport: LayerZero Gateway v2
0.00014796 ETH
201922332024-06-28 19:19:5941 hrs ago1719602399
Interport: LayerZero Gateway v2
0.00044343 ETH
201918782024-06-28 18:08:4742 hrs ago1719598127
Interport: LayerZero Gateway v2
0.00026634 ETH
201918782024-06-28 18:08:4742 hrs ago1719598127
Interport: LayerZero Gateway v2
0.00029602 ETH
201918782024-06-28 18:08:4742 hrs ago1719598127
Interport: LayerZero Gateway v2
0.00056237 ETH
201916502024-06-28 17:22:5943 hrs ago1719595379
Interport: LayerZero Gateway v2
0.0005664 ETH
201916502024-06-28 17:22:5943 hrs ago1719595379
Interport: LayerZero Gateway v2
0.00014762 ETH
201916502024-06-28 17:22:5943 hrs ago1719595379
Interport: LayerZero Gateway v2
0.00071402 ETH
201809362024-06-27 5:28:353 days ago1719466115
Interport: LayerZero Gateway v2
0.0002859 ETH
201809362024-06-27 5:28:353 days ago1719466115
Interport: LayerZero Gateway v2
0.00118297 ETH
201809362024-06-27 5:28:353 days ago1719466115
Interport: LayerZero Gateway v2
0.00146888 ETH
201771332024-06-26 16:43:473 days ago1719420227
Interport: LayerZero Gateway v2
0.00051768 ETH
201771332024-06-26 16:43:473 days ago1719420227
Interport: LayerZero Gateway v2
0.0004462 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LayerZeroGatewayV2

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 22 : LayerZeroGatewayV2.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import { IGateway } from '../interfaces/IGateway.sol';
import { IGatewayClient } from '../interfaces/IGatewayClient.sol';
import { ILayerZeroEndpoint } from './interfaces/ILayerZeroEndpoint.sol';
import { GatewayBase } from '../GatewayBase.sol';
import { SystemVersionId } from '../../SystemVersionId.sol';
import { ZeroAddressError } from '../../Errors.sol';
import '../../helpers/AddressHelper.sol' as AddressHelper;
import '../../helpers/GasReserveHelper.sol' as GasReserveHelper;
import '../../helpers/TransferHelper.sol' as TransferHelper;
import '../../DataStructures.sol' as DataStructures;

/**
 * @title LayerZeroGatewayV2
 * @notice The contract implementing the cross-chain messaging logic specific to LayerZero
 */
contract LayerZeroGatewayV2 is SystemVersionId, GatewayBase {
    /**
     * @notice Chain ID pair structure
     * @dev See https://layerzero.gitbook.io/docs/technical-reference/mainnet/supported-chain-ids
     * @param standardId The standard EVM chain ID
     * @param layerZeroId The LayerZero chain ID
     */
    struct ChainIdPair {
        uint256 standardId;
        uint16 layerZeroId;
    }

    /**
     * @dev LayerZero endpoint contract reference
     */
    ILayerZeroEndpoint public endpoint;

    /**
     * @dev The correspondence between standard EVM chain IDs and LayerZero chain IDs
     */
    mapping(uint256 /*standardId*/ => uint16 /*layerZeroId*/) public standardToLayerZeroChainId;

    /**
     * @dev The correspondence between LayerZero chain IDs and standard EVM chain IDs
     */
    mapping(uint16 /*layerZeroId*/ => uint256 /*standardId*/) public layerZeroToStandardChainId;

    /**
     * @dev The default value of minimum target gas
     */
    uint256 public minTargetGasDefault;

    /**
     * @dev The custom values of minimum target gas by standard chain IDs
     */
    mapping(uint256 /*standardChainId*/ => DataStructures.OptionalValue /*minTargetGas*/)
        public minTargetGasCustom;

    /**
     * @dev The address of the processing fee collector
     */
    address public processingFeeCollector;

    uint16 private constant ADAPTER_PARAMETERS_VERSION = 1;

    /**
     * @notice Emitted when the cross-chain endpoint contract reference is set
     * @param endpointAddress The address of the cross-chain endpoint contract
     */
    event SetEndpoint(address indexed endpointAddress);

    /**
     * @notice Emitted when a chain ID pair is added or updated
     * @param standardId The standard EVM chain ID
     * @param layerZeroId The LayerZero chain ID
     */
    event SetChainIdPair(uint256 indexed standardId, uint16 indexed layerZeroId);

    /**
     * @notice Emitted when a chain ID pair is removed
     * @param standardId The standard EVM chain ID
     * @param layerZeroId The LayerZero chain ID
     */
    event RemoveChainIdPair(uint256 indexed standardId, uint16 indexed layerZeroId);

    /**
     * @notice Emitted when the default value of minimum target gas is set
     * @param minTargetGas The value of minimum target gas
     */
    event SetMinTargetGasDefault(uint256 minTargetGas);

    /**
     * @notice Emitted when the custom value of minimum target gas is set
     * @param standardChainId The standard EVM chain ID
     * @param minTargetGas The value of minimum target gas
     */
    event SetMinTargetGasCustom(uint256 standardChainId, uint256 minTargetGas);

    /**
     * @notice Emitted when the custom value of minimum target gas is removed
     * @param standardChainId The standard EVM chain ID
     */
    event RemoveMinTargetGasCustom(uint256 standardChainId);

    /**
     * @notice Emitted when the address of the processing fee collector is set
     * @param processingFeeCollector The address of the processing fee collector
     */
    event SetProcessingFeeCollector(address indexed processingFeeCollector);

    /**
     * @notice Emitted when there is no registered LayerZero chain ID matching the standard EVM chain ID
     */
    error LayerZeroChainIdNotSetError();

    /**
     * @notice Emitted when the provided target gas value is not sufficient for the message processing
     */
    error MinTargetGasError();

    /**
     * @notice Emitted when the provided call value is not sufficient for the message processing
     */
    error ProcessingFeeError();

    /**
     * @notice Emitted when the caller is not the LayerZero endpoint contract
     */
    error OnlyEndpointError();

    /**
     * @dev Modifier to check if the caller is the LayerZero endpoint contract
     */
    modifier onlyEndpoint() {
        if (msg.sender != address(endpoint)) {
            revert OnlyEndpointError();
        }

        _;
    }

    /**
     * @notice Deploys the LayerZeroGateway contract
     * @param _endpointAddress The cross-chain endpoint address
     * @param _chainIdPairs The correspondence between standard EVM chain IDs and LayerZero chain IDs
     * @param _minTargetGasDefault The default value of minimum target gas
     * @param _minTargetGasCustomData The custom values of minimum target gas by standard chain IDs
     * @param _targetGasReserve The initial gas reserve value for target chain action processing
     * @param _processingFeeCollector The initial address of the processing fee collector
     * @param _owner The address of the initial owner of the contract
     * @param _managers The addresses of initial managers of the contract
     * @param _addOwnerToManagers The flag to optionally add the owner to the list of managers
     */
    constructor(
        address _endpointAddress,
        ChainIdPair[] memory _chainIdPairs,
        uint256 _minTargetGasDefault,
        DataStructures.KeyToValue[] memory _minTargetGasCustomData,
        uint256 _targetGasReserve,
        address _processingFeeCollector,
        address _owner,
        address[] memory _managers,
        bool _addOwnerToManagers
    ) {
        _setEndpoint(_endpointAddress);

        for (uint256 index; index < _chainIdPairs.length; index++) {
            ChainIdPair memory chainIdPair = _chainIdPairs[index];

            _setChainIdPair(chainIdPair.standardId, chainIdPair.layerZeroId);
        }

        _setMinTargetGasDefault(_minTargetGasDefault);

        for (uint256 index; index < _minTargetGasCustomData.length; index++) {
            DataStructures.KeyToValue memory minTargetGasCustomEntry = _minTargetGasCustomData[
                index
            ];

            _setMinTargetGasCustom(minTargetGasCustomEntry.key, minTargetGasCustomEntry.value);
        }

        _setTargetGasReserve(_targetGasReserve);

        _setProcessingFeeCollector(_processingFeeCollector);

        _initRoles(_owner, _managers, _addOwnerToManagers);
    }

    /**
     * @notice Sets the cross-chain endpoint contract reference
     * @param _endpointAddress The address of the cross-chain endpoint contract
     */
    function setEndpoint(address _endpointAddress) external onlyManager {
        _setEndpoint(_endpointAddress);
    }

    /**
     * @notice Adds or updates registered chain ID pairs
     * @param _chainIdPairs The list of chain ID pairs
     */
    function setChainIdPairs(ChainIdPair[] calldata _chainIdPairs) external onlyManager {
        for (uint256 index; index < _chainIdPairs.length; index++) {
            ChainIdPair calldata chainIdPair = _chainIdPairs[index];

            _setChainIdPair(chainIdPair.standardId, chainIdPair.layerZeroId);
        }
    }

    /**
     * @notice Removes registered chain ID pairs
     * @param _standardChainIds The list of standard EVM chain IDs
     */
    function removeChainIdPairs(uint256[] calldata _standardChainIds) external onlyManager {
        for (uint256 index; index < _standardChainIds.length; index++) {
            uint256 standardId = _standardChainIds[index];

            _removeChainIdPair(standardId);
        }
    }

    /**
     * @notice Sets the default value of minimum target gas
     * @param _minTargetGas The value of minimum target gas
     */
    function setMinTargetGasDefault(uint256 _minTargetGas) external onlyManager {
        _setMinTargetGasDefault(_minTargetGas);
    }

    /**
     * @notice Sets the custom value of minimum target gas by the standard chain ID
     * @param _standardChainId The standard EVM ID of the target chain
     * @param _minTargetGas The value of minimum target gas
     */
    function setMinTargetGasCustom(
        uint256 _standardChainId,
        uint256 _minTargetGas
    ) external onlyManager {
        _setMinTargetGasCustom(_standardChainId, _minTargetGas);
    }

    /**
     * @notice Removes the custom value of minimum target gas by the standard chain ID
     * @param _standardChainId The standard EVM ID of the target chain
     */
    function removeMinTargetGasCustom(uint256 _standardChainId) external onlyManager {
        _removeMinTargetGasCustom(_standardChainId);
    }

    /**
     * @notice Sets the address of the processing fee collector
     * @param _processingFeeCollector The address of the processing fee collector
     */
    function setProcessingFeeCollector(address _processingFeeCollector) external onlyManager {
        _setProcessingFeeCollector(_processingFeeCollector);
    }

    /**
     * @notice Send a cross-chain message
     * @dev The settings parameter contains an ABI-encoded uint256 value of the target chain gas
     * @param _targetChainId The message target chain ID
     * @param _message The message content
     * @param _settings The gateway-specific settings
     */
    function sendMessage(
        uint256 _targetChainId,
        bytes calldata _message,
        bytes calldata _settings
    ) external payable onlyClient whenNotPaused {
        address peerAddress = _checkPeerAddress(_targetChainId);

        uint16 targetLayerZeroChainId = standardToLayerZeroChainId[_targetChainId];

        if (targetLayerZeroChainId == 0) {
            revert LayerZeroChainIdNotSetError();
        }

        (bytes memory adapterParameters, uint256 processingFee) = _checkSettings(
            _settings,
            _targetChainId
        );

        // - - - Processing fee transfer - - -

        if (msg.value < processingFee) {
            revert ProcessingFeeError();
        }

        if (processingFee > 0 && processingFeeCollector != address(0)) {
            TransferHelper.safeTransferNative(processingFeeCollector, processingFee);
        }

        // - - -

        endpoint.send{ value: msg.value - processingFee }(
            targetLayerZeroChainId,
            abi.encodePacked(peerAddress, address(this)),
            _message,
            payable(client), // refund address
            address(0), // future parameter
            adapterParameters
        );
    }

    /**
     * @notice Receives cross-chain messages
     * @dev The function is called by the cross-chain endpoint
     * @param _srcChainId The message source chain ID
     * @param _srcAddress The message source address
     * @param _payload The message content
     */
    function lzReceive(
        uint16 _srcChainId,
        bytes memory _srcAddress,
        uint64 /*_nonce*/,
        bytes calldata _payload
    ) external nonReentrant onlyEndpoint {
        if (paused()) {
            emit TargetPausedFailure();

            return;
        }

        if (address(client) == address(0)) {
            emit TargetClientNotSetFailure();

            return;
        }

        uint256 sourceStandardChainId = layerZeroToStandardChainId[_srcChainId];

        // use assembly to extract the address
        address fromAddress;
        assembly {
            fromAddress := mload(add(_srcAddress, 20))
        }

        bool condition = sourceStandardChainId != 0 &&
            fromAddress != address(0) &&
            fromAddress == peerMap[sourceStandardChainId];

        if (!condition) {
            emit TargetFromAddressFailure(sourceStandardChainId, fromAddress);

            return;
        }

        (bool hasGasReserve, uint256 gasAllowed) = GasReserveHelper.checkGasReserve(
            targetGasReserve
        );

        if (!hasGasReserve) {
            emit TargetGasReserveFailure(sourceStandardChainId);

            return;
        }

        try
            client.handleExecutionPayload{ gas: gasAllowed }(sourceStandardChainId, _payload)
        {} catch {
            emit TargetExecutionFailure();
        }
    }

    /**
     * @notice Cross-chain message fee estimation
     * @dev The settings parameter contains an ABI-encoded uint256 value of the target chain gas
     * @param _targetChainId The ID of the target chain
     * @param _message The message content
     * @param _settings The gateway-specific settings
     * @return Message fee
     */
    function messageFee(
        uint256 _targetChainId,
        bytes calldata _message,
        bytes calldata _settings
    ) external view returns (uint256) {
        uint16 targetLayerZeroChainId = standardToLayerZeroChainId[_targetChainId];

        (bytes memory adapterParameters, uint256 processingFee) = _checkSettings(
            _settings,
            _targetChainId
        );

        (uint256 endpointNativeFee, ) = endpoint.estimateFees(
            targetLayerZeroChainId,
            address(this),
            _message,
            false,
            adapterParameters
        );

        return endpointNativeFee + processingFee;
    }

    /**
     * @notice The value of minimum target gas by the standard chain ID
     * @param _standardChainId The standard EVM ID of the target chain
     * @return The value of minimum target gas
     */
    function minTargetGas(uint256 _standardChainId) public view returns (uint256) {
        DataStructures.OptionalValue storage optionalValue = minTargetGasCustom[_standardChainId];

        if (optionalValue.isSet) {
            return optionalValue.value;
        }

        return minTargetGasDefault;
    }

    function _setEndpoint(address _endpointAddress) private {
        AddressHelper.requireContract(_endpointAddress);

        endpoint = ILayerZeroEndpoint(_endpointAddress);

        emit SetEndpoint(_endpointAddress);
    }

    function _setChainIdPair(uint256 _standardId, uint16 _layerZeroId) private {
        standardToLayerZeroChainId[_standardId] = _layerZeroId;
        layerZeroToStandardChainId[_layerZeroId] = _standardId;

        emit SetChainIdPair(_standardId, _layerZeroId);
    }

    function _removeChainIdPair(uint256 _standardId) private {
        uint16 layerZeroId = standardToLayerZeroChainId[_standardId];

        delete standardToLayerZeroChainId[_standardId];
        delete layerZeroToStandardChainId[layerZeroId];

        emit RemoveChainIdPair(_standardId, layerZeroId);
    }

    function _setMinTargetGasDefault(uint256 _minTargetGas) private {
        minTargetGasDefault = _minTargetGas;

        emit SetMinTargetGasDefault(_minTargetGas);
    }

    function _setMinTargetGasCustom(uint256 _standardChainId, uint256 _minTargetGas) private {
        minTargetGasCustom[_standardChainId] = DataStructures.OptionalValue({
            isSet: true,
            value: _minTargetGas
        });

        emit SetMinTargetGasCustom(_standardChainId, _minTargetGas);
    }

    function _removeMinTargetGasCustom(uint256 _standardChainId) private {
        delete minTargetGasCustom[_standardChainId];

        emit RemoveMinTargetGasCustom(_standardChainId);
    }

    function _setProcessingFeeCollector(address _processingFeeCollector) private {
        processingFeeCollector = _processingFeeCollector;

        emit SetProcessingFeeCollector(_processingFeeCollector);
    }

    function _checkSettings(
        bytes calldata _settings,
        uint256 _targetChainId
    ) private view returns (bytes memory adapterParameters, uint256 processingFee) {
        uint256 targetGas;
        (targetGas, processingFee) = abi.decode(_settings, (uint256, uint256));

        uint256 minTargetGasValue = minTargetGas(_targetChainId);

        if (targetGas < minTargetGasValue) {
            revert MinTargetGasError();
        }

        adapterParameters = abi.encodePacked(ADAPTER_PARAMETERS_VERSION, targetGas);
    }
}

File 2 of 22 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

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

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

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

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

File 3 of 22 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

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

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

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

    bool private _paused;

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

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

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

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

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

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

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

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

File 4 of 22 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

File 5 of 22 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

File 6 of 22 : BalanceManagement.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { ITokenBalance } from './interfaces/ITokenBalance.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;

/**
 * @title BalanceManagement
 * @notice Base contract for the withdrawal of tokens, except for reserved ones
 */
abstract contract BalanceManagement is ManagerRole {
    /**
     * @notice Emitted when the specified token is reserved
     */
    error ReservedTokenError();

    /**
     * @notice Performs the withdrawal of tokens, except for reserved ones
     * @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
     * @param _tokenAddress The address of the token
     * @param _tokenAmount The amount of the token
     */
    function cleanup(address _tokenAddress, uint256 _tokenAmount) external onlyManager {
        if (isReservedToken(_tokenAddress)) {
            revert ReservedTokenError();
        }

        if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
            TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
        } else {
            TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
        }
    }

    /**
     * @notice Getter of the token balance of the current contract
     * @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
     * @param _tokenAddress The address of the token
     * @return The token balance of the current contract
     */
    function tokenBalance(address _tokenAddress) public view returns (uint256) {
        if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
            return address(this).balance;
        } else {
            return ITokenBalance(_tokenAddress).balanceOf(address(this));
        }
    }

    /**
     * @notice Getter of the reserved token flag
     * @dev Override to add reserved token addresses
     * @param _tokenAddress The address of the token
     * @return The reserved token flag
     */
    function isReservedToken(address _tokenAddress) public view virtual returns (bool) {
        // The function returns false by default.
        // The explicit return statement is omitted to avoid the unused parameter warning.
        // See https://github.com/ethereum/solidity/issues/5295
    }
}

File 7 of 22 : Constants.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @dev The default token decimals value
 */
uint256 constant DECIMALS_DEFAULT = 18;

/**
 * @dev The maximum uint256 value for swap amount limit settings
 */
uint256 constant INFINITY = type(uint256).max;

/**
 * @dev The default limit of account list size
 */
uint256 constant LIST_SIZE_LIMIT_DEFAULT = 100;

/**
 * @dev The limit of swap router list size
 */
uint256 constant LIST_SIZE_LIMIT_ROUTERS = 200;

/**
 * @dev The factor for percentage settings. Example: 100 is 0.1%
 */
uint256 constant MILLIPERCENT_FACTOR = 100_000;

/**
 * @dev The de facto standard address to denote the native token
 */
address constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

File 8 of 22 : GatewayBase.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import { IGateway } from './interfaces/IGateway.sol';
import { IGatewayClient } from './interfaces/IGatewayClient.sol';
import { BalanceManagement } from '../BalanceManagement.sol';
import { Pausable } from '../Pausable.sol';
import { TargetGasReserve } from './TargetGasReserve.sol';
import { ZeroAddressError } from '../Errors.sol';
import '../helpers/AddressHelper.sol' as AddressHelper;
import '../Constants.sol' as Constants;
import '../DataStructures.sol' as DataStructures;

/**
 * @title GatewayBase
 * @notice Base contract that implements the cross-chain gateway logic
 */
abstract contract GatewayBase is
    Pausable,
    ReentrancyGuard,
    TargetGasReserve,
    BalanceManagement,
    IGateway
{
    /**
     * @dev Gateway client contract reference
     */
    IGatewayClient public client;

    /**
     * @dev Registered peer gateway addresses by the chain ID
     */
    mapping(uint256 /*peerChainId*/ => address /*peerAddress*/) public peerMap;

    /**
     * @dev Registered peer gateway chain IDs
     */
    uint256[] public peerChainIdList;

    /**
     * @dev Registered peer gateway chain ID indices
     */
    mapping(uint256 /*peerChainId*/ => DataStructures.OptionalValue /*peerChainIdIndex*/)
        public peerChainIdIndexMap;

    /**
     * @notice Emitted when the gateway client contract reference is set
     * @param clientAddress The gateway client contract address
     */
    event SetClient(address indexed clientAddress);

    /**
     * @notice Emitted when a registered peer gateway contract address is added or updated
     * @param chainId The chain ID of the registered peer gateway
     * @param peerAddress The address of the registered peer gateway contract
     */
    event SetPeer(uint256 indexed chainId, address indexed peerAddress);

    /**
     * @notice Emitted when a registered peer gateway contract address is removed
     * @param chainId The chain ID of the registered peer gateway
     */
    event RemovePeer(uint256 indexed chainId);

    /**
     * @notice Emitted when the target chain gateway is paused
     */
    event TargetPausedFailure();

    /**
     * @notice Emitted when the target chain gateway client contract is not set
     */
    event TargetClientNotSetFailure();

    /**
     * @notice Emitted when the message source address does not match the registered peer gateway on the target chain
     * @param sourceChainId The ID of the message source chain
     * @param sourceChainId The address of the message source
     */
    event TargetFromAddressFailure(uint256 indexed sourceChainId, address indexed fromAddress);

    /**
     * @notice Emitted when the gas reserve on the target chain does not allow further action processing
     * @param sourceChainId The ID of the message source chain
     */
    event TargetGasReserveFailure(uint256 indexed sourceChainId);

    /**
     * @notice Emitted when the gateway client execution on the target chain fails
     */
    event TargetExecutionFailure();

    /**
     * @notice Emitted when the caller is not the gateway client contract
     */
    error OnlyClientError();

    /**
     * @notice Emitted when the peer config address for the current chain does not match the current contract
     */
    error PeerAddressMismatchError();

    /**
     * @notice Emitted when the peer gateway address for the specified chain is not set
     */
    error PeerNotSetError();

    /**
     * @notice Emitted when the chain ID is not set
     */
    error ZeroChainIdError();

    /**
     * @dev Modifier to check if the caller is the gateway client contract
     */
    modifier onlyClient() {
        if (msg.sender != address(client)) {
            revert OnlyClientError();
        }

        _;
    }

    /**
     * @notice Sets the gateway client contract reference
     * @param _clientAddress The gateway client contract address
     */
    function setClient(address payable _clientAddress) external virtual onlyManager {
        AddressHelper.requireContract(_clientAddress);

        client = IGatewayClient(_clientAddress);

        emit SetClient(_clientAddress);
    }

    /**
     * @notice Adds or updates registered peer gateways
     * @param _peers Chain IDs and addresses of peer gateways
     */
    function setPeers(
        DataStructures.KeyToAddressValue[] calldata _peers
    ) external virtual onlyManager {
        for (uint256 index; index < _peers.length; index++) {
            DataStructures.KeyToAddressValue calldata item = _peers[index];

            uint256 chainId = item.key;
            address peerAddress = item.value;

            // Allow the same configuration on multiple chains
            if (chainId == block.chainid) {
                if (peerAddress != address(this)) {
                    revert PeerAddressMismatchError();
                }
            } else {
                _setPeer(chainId, peerAddress);
            }
        }
    }

    /**
     * @notice Removes registered peer gateways
     * @param _chainIds Peer gateway chain IDs
     */
    function removePeers(uint256[] calldata _chainIds) external virtual onlyManager {
        for (uint256 index; index < _chainIds.length; index++) {
            uint256 chainId = _chainIds[index];

            // Allow the same configuration on multiple chains
            if (chainId != block.chainid) {
                _removePeer(chainId);
            }
        }
    }

    /**
     * @notice Getter of the peer gateway count
     * @return The peer gateway count
     */
    function peerCount() external view virtual returns (uint256) {
        return peerChainIdList.length;
    }

    /**
     * @notice Getter of the complete list of the peer gateway chain IDs
     * @return The complete list of the peer gateway chain IDs
     */
    function fullPeerChainIdList() external view virtual returns (uint256[] memory) {
        return peerChainIdList;
    }

    function _setPeer(uint256 _chainId, address _peerAddress) internal virtual {
        if (_chainId == 0) {
            revert ZeroChainIdError();
        }

        if (_peerAddress == address(0)) {
            revert ZeroAddressError();
        }

        DataStructures.combinedMapSet(
            peerMap,
            peerChainIdList,
            peerChainIdIndexMap,
            _chainId,
            _peerAddress,
            Constants.LIST_SIZE_LIMIT_DEFAULT
        );

        emit SetPeer(_chainId, _peerAddress);
    }

    function _removePeer(uint256 _chainId) internal virtual {
        if (_chainId == 0) {
            revert ZeroChainIdError();
        }

        DataStructures.combinedMapRemove(peerMap, peerChainIdList, peerChainIdIndexMap, _chainId);

        emit RemovePeer(_chainId);
    }

    function _checkPeerAddress(uint256 _chainId) internal virtual returns (address) {
        address peerAddress = peerMap[_chainId];

        if (peerAddress == address(0)) {
            revert PeerNotSetError();
        }

        return peerAddress;
    }
}

File 9 of 22 : IGateway.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title IGateway
 * @notice Cross-chain gateway interface
 */
interface IGateway {
    /**
     * @notice Send a cross-chain message
     * @param _targetChainId The message target chain ID
     * @param _message The message content
     * @param _settings The gateway-specific settings
     */
    function sendMessage(
        uint256 _targetChainId,
        bytes calldata _message,
        bytes calldata _settings
    ) external payable;

    /**
     * @notice Cross-chain message fee estimation
     * @param _targetChainId The ID of the target chain
     * @param _message The message content
     * @param _settings The gateway-specific settings
     */
    function messageFee(
        uint256 _targetChainId,
        bytes calldata _message,
        bytes calldata _settings
    ) external view returns (uint256);
}

File 10 of 22 : IGatewayClient.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title IGatewayClient
 * @notice Cross-chain gateway client interface
 */
interface IGatewayClient {
    /**
     * @notice Cross-chain message handler on the target chain
     * @dev The function is called by cross-chain gateways
     * @param _messageSourceChainId The ID of the message source chain
     * @param _payloadData The content of the cross-chain message
     */
    function handleExecutionPayload(
        uint256 _messageSourceChainId,
        bytes calldata _payloadData
    ) external;

    /**
     * @notice The standard "receive" function
     */
    receive() external payable;
}

File 11 of 22 : ILayerZeroEndpoint.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title ILayerZeroEndpoint
 * @notice LayerZero endpoint interface
 */
interface ILayerZeroEndpoint {
    /**
     * @notice Send a cross-chain message
     * @param _dstChainId The destination chain identifier
     * @param _destination Remote address concatenated with local address packed into 40 bytes
     * @param _payload The message content
     * @param _refundAddress Refund the additional amount to this address
     * @param _zroPaymentAddress The address of the ZRO token holder who would pay for the transaction
     * @param _adapterParam Parameters for the adapter service
     */
    function send(
        uint16 _dstChainId,
        bytes calldata _destination,
        bytes calldata _payload,
        address payable _refundAddress,
        address _zroPaymentAddress,
        bytes calldata _adapterParam
    ) external payable;

    /**
     * @notice Cross-chain message fee estimation
     * @param _dstChainId The destination chain identifier
     * @param _userApplication The application address on the source chain
     * @param _payload The message content
     * @param _payInZRO If false, the user application pays the protocol fee in the native token
     * @param _adapterParam Parameters for the adapter service
     * @return nativeFee The native token fee for the message
     * @return zroFee The ZRO token fee for the message
     */
    function estimateFees(
        uint16 _dstChainId,
        address _userApplication,
        bytes calldata _payload,
        bool _payInZRO,
        bytes calldata _adapterParam
    ) external view returns (uint256 nativeFee, uint256 zroFee);
}

File 12 of 22 : TargetGasReserve.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { ManagerRole } from '../roles/ManagerRole.sol';

/**
 * @title TargetGasReserve
 * @notice Base contract that implements the gas reserve logic for the target chain actions
 */
abstract contract TargetGasReserve is ManagerRole {
    /**
     * @dev The target chain gas reserve value
     */
    uint256 public targetGasReserve;

    /**
     * @notice Emitted when the target chain gas reserve value is set
     * @param gasReserve The target chain gas reserve value
     */
    event SetTargetGasReserve(uint256 gasReserve);

    /**
     * @notice Sets the target chain gas reserve value
     * @param _gasReserve The target chain gas reserve value
     */
    function setTargetGasReserve(uint256 _gasReserve) external onlyManager {
        _setTargetGasReserve(_gasReserve);
    }

    function _setTargetGasReserve(uint256 _gasReserve) internal virtual {
        targetGasReserve = _gasReserve;

        emit SetTargetGasReserve(_gasReserve);
    }
}

File 13 of 22 : DataStructures.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @notice Optional value structure
 * @dev Is used in mappings to allow zero values
 * @param isSet Value presence flag
 * @param value Numeric value
 */
struct OptionalValue {
    bool isSet;
    uint256 value;
}

/**
 * @notice Key-to-value structure
 * @dev Is used as an array parameter item to perform multiple key-value settings
 * @param key Numeric key
 * @param value Numeric value
 */
struct KeyToValue {
    uint256 key;
    uint256 value;
}

/**
 * @notice Key-to-value structure for address values
 * @dev Is used as an array parameter item to perform multiple key-value settings with address values
 * @param key Numeric key
 * @param value Address value
 */
struct KeyToAddressValue {
    uint256 key;
    address value;
}

/**
 * @notice Address-to-flag structure
 * @dev Is used as an array parameter item to perform multiple settings
 * @param account Account address
 * @param flag Flag value
 */
struct AccountToFlag {
    address account;
    bool flag;
}

/**
 * @notice Emitted when a list exceeds the size limit
 */
error ListSizeLimitError();

/**
 * @notice Sets or updates a value in a combined map (a mapping with a key list and key index mapping)
 * @param _map The mapping reference
 * @param _keyList The key list reference
 * @param _keyIndexMap The key list index mapping reference
 * @param _key The numeric key
 * @param _value The address value
 * @param _sizeLimit The map and list size limit
 * @return isNewKey True if the key was just added, otherwise false
 */
function combinedMapSet(
    mapping(uint256 => address) storage _map,
    uint256[] storage _keyList,
    mapping(uint256 => OptionalValue) storage _keyIndexMap,
    uint256 _key,
    address _value,
    uint256 _sizeLimit
) returns (bool isNewKey) {
    isNewKey = !_keyIndexMap[_key].isSet;

    if (isNewKey) {
        uniqueListAdd(_keyList, _keyIndexMap, _key, _sizeLimit);
    }

    _map[_key] = _value;
}

/**
 * @notice Removes a value from a combined map (a mapping with a key list and key index mapping)
 * @param _map The mapping reference
 * @param _keyList The key list reference
 * @param _keyIndexMap The key list index mapping reference
 * @param _key The numeric key
 * @return isChanged True if the combined map was changed, otherwise false
 */
function combinedMapRemove(
    mapping(uint256 => address) storage _map,
    uint256[] storage _keyList,
    mapping(uint256 => OptionalValue) storage _keyIndexMap,
    uint256 _key
) returns (bool isChanged) {
    isChanged = _keyIndexMap[_key].isSet;

    if (isChanged) {
        delete _map[_key];
        uniqueListRemove(_keyList, _keyIndexMap, _key);
    }
}

/**
 * @notice Adds a value to a unique value list (a list with value index mapping)
 * @param _list The list reference
 * @param _indexMap The value index mapping reference
 * @param _value The numeric value
 * @param _sizeLimit The list size limit
 * @return isChanged True if the list was changed, otherwise false
 */
function uniqueListAdd(
    uint256[] storage _list,
    mapping(uint256 => OptionalValue) storage _indexMap,
    uint256 _value,
    uint256 _sizeLimit
) returns (bool isChanged) {
    isChanged = !_indexMap[_value].isSet;

    if (isChanged) {
        if (_list.length >= _sizeLimit) {
            revert ListSizeLimitError();
        }

        _indexMap[_value] = OptionalValue(true, _list.length);
        _list.push(_value);
    }
}

/**
 * @notice Removes a value from a unique value list (a list with value index mapping)
 * @param _list The list reference
 * @param _indexMap The value index mapping reference
 * @param _value The numeric value
 * @return isChanged True if the list was changed, otherwise false
 */
function uniqueListRemove(
    uint256[] storage _list,
    mapping(uint256 => OptionalValue) storage _indexMap,
    uint256 _value
) returns (bool isChanged) {
    OptionalValue storage indexItem = _indexMap[_value];

    isChanged = indexItem.isSet;

    if (isChanged) {
        uint256 itemIndex = indexItem.value;
        uint256 lastIndex = _list.length - 1;

        if (itemIndex != lastIndex) {
            uint256 lastValue = _list[lastIndex];
            _list[itemIndex] = lastValue;
            _indexMap[lastValue].value = itemIndex;
        }

        _list.pop();
        delete _indexMap[_value];
    }
}

/**
 * @notice Adds a value to a unique address value list (a list with value index mapping)
 * @param _list The list reference
 * @param _indexMap The value index mapping reference
 * @param _value The address value
 * @param _sizeLimit The list size limit
 * @return isChanged True if the list was changed, otherwise false
 */
function uniqueAddressListAdd(
    address[] storage _list,
    mapping(address => OptionalValue) storage _indexMap,
    address _value,
    uint256 _sizeLimit
) returns (bool isChanged) {
    isChanged = !_indexMap[_value].isSet;

    if (isChanged) {
        if (_list.length >= _sizeLimit) {
            revert ListSizeLimitError();
        }

        _indexMap[_value] = OptionalValue(true, _list.length);
        _list.push(_value);
    }
}

/**
 * @notice Removes a value from a unique address value list (a list with value index mapping)
 * @param _list The list reference
 * @param _indexMap The value index mapping reference
 * @param _value The address value
 * @return isChanged True if the list was changed, otherwise false
 */
function uniqueAddressListRemove(
    address[] storage _list,
    mapping(address => OptionalValue) storage _indexMap,
    address _value
) returns (bool isChanged) {
    OptionalValue storage indexItem = _indexMap[_value];

    isChanged = indexItem.isSet;

    if (isChanged) {
        uint256 itemIndex = indexItem.value;
        uint256 lastIndex = _list.length - 1;

        if (itemIndex != lastIndex) {
            address lastValue = _list[lastIndex];
            _list[itemIndex] = lastValue;
            _indexMap[lastValue].value = itemIndex;
        }

        _list.pop();
        delete _indexMap[_value];
    }
}

/**
 * @notice Adds or removes a value to/from a unique address value list (a list with value index mapping)
 * @dev The list size limit is checked on items adding only
 * @param _list The list reference
 * @param _indexMap The value index mapping reference
 * @param _value The address value
 * @param _flag The value inclusion flag
 * @param _sizeLimit The list size limit
 * @return isChanged True if the list was changed, otherwise false
 */
function uniqueAddressListUpdate(
    address[] storage _list,
    mapping(address => OptionalValue) storage _indexMap,
    address _value,
    bool _flag,
    uint256 _sizeLimit
) returns (bool isChanged) {
    return
        _flag
            ? uniqueAddressListAdd(_list, _indexMap, _value, _sizeLimit)
            : uniqueAddressListRemove(_list, _indexMap, _value);
}

File 14 of 22 : Errors.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @notice Emitted when an attempt to burn a token fails
 */
error TokenBurnError();

/**
 * @notice Emitted when an attempt to mint a token fails
 */
error TokenMintError();

/**
 * @notice Emitted when a zero address is specified where it is not allowed
 */
error ZeroAddressError();

File 15 of 22 : AddressHelper.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @notice Emitted when the account is not a contract
 * @param account The account address
 */
error NonContractAddressError(address account);

/**
 * @notice Function to check if the account is a contract
 * @return The account contract status flag
 */
function isContract(address _account) view returns (bool) {
    return _account.code.length > 0;
}

/**
 * @notice Function to require an account to be a contract
 */
function requireContract(address _account) view {
    if (!isContract(_account)) {
        revert NonContractAddressError(_account);
    }
}

/**
 * @notice Function to require an account to be a contract or a zero address
 */
function requireContractOrZeroAddress(address _account) view {
    if (_account != address(0)) {
        requireContract(_account);
    }
}

File 16 of 22 : GasReserveHelper.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @notice Function to check if the available gas matches the specified gas reserve value
 * @param _gasReserve Gas reserve value
 * @return hasGasReserve Flag of gas reserve availability
 * @return gasAllowed The remaining gas quantity taking the reserve into account
 */
function checkGasReserve(
    uint256 _gasReserve
) view returns (bool hasGasReserve, uint256 gasAllowed) {
    uint256 gasLeft = gasleft();

    hasGasReserve = gasLeft >= _gasReserve;
    gasAllowed = hasGasReserve ? gasLeft - _gasReserve : 0;
}

File 17 of 22 : TransferHelper.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @notice Emitted when an approval action fails
 */
error SafeApproveError();

/**
 * @notice Emitted when a transfer action fails
 */
error SafeTransferError();

/**
 * @notice Emitted when a transferFrom action fails
 */
error SafeTransferFromError();

/**
 * @notice Emitted when a transfer of the native token fails
 */
error SafeTransferNativeError();

/**
 * @notice Safely approve the token to the account
 * @param _token The token address
 * @param _to The token approval recipient address
 * @param _value The token approval amount
 */
function safeApprove(address _token, address _to, uint256 _value) {
    // 0x095ea7b3 is the selector for "approve(address,uint256)"
    (bool success, bytes memory data) = _token.call(
        abi.encodeWithSelector(0x095ea7b3, _to, _value)
    );

    bool condition = success && (data.length == 0 || abi.decode(data, (bool)));

    if (!condition) {
        revert SafeApproveError();
    }
}

/**
 * @notice Safely transfer the token to the account
 * @param _token The token address
 * @param _to The token transfer recipient address
 * @param _value The token transfer amount
 */
function safeTransfer(address _token, address _to, uint256 _value) {
    // 0xa9059cbb is the selector for "transfer(address,uint256)"
    (bool success, bytes memory data) = _token.call(
        abi.encodeWithSelector(0xa9059cbb, _to, _value)
    );

    bool condition = success && (data.length == 0 || abi.decode(data, (bool)));

    if (!condition) {
        revert SafeTransferError();
    }
}

/**
 * @notice Safely transfer the token between the accounts
 * @param _token The token address
 * @param _from The token transfer source address
 * @param _to The token transfer recipient address
 * @param _value The token transfer amount
 */
function safeTransferFrom(address _token, address _from, address _to, uint256 _value) {
    // 0x23b872dd is the selector for "transferFrom(address,address,uint256)"
    (bool success, bytes memory data) = _token.call(
        abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
    );

    bool condition = success && (data.length == 0 || abi.decode(data, (bool)));

    if (!condition) {
        revert SafeTransferFromError();
    }
}

/**
 * @notice Safely transfer the native token to the account
 * @param _to The native token transfer recipient address
 * @param _value The native token transfer amount
 */
function safeTransferNative(address _to, uint256 _value) {
    (bool success, ) = _to.call{ value: _value }(new bytes(0));

    if (!success) {
        revert SafeTransferNativeError();
    }
}

File 18 of 22 : ITokenBalance.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title ITokenBalance
 * @notice Token balance interface
 */
interface ITokenBalance {
    /**
     * @notice Getter of the token balance by the account
     * @param _account The account address
     * @return Token balance
     */
    function balanceOf(address _account) external view returns (uint256);
}

File 19 of 22 : Pausable.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { Pausable as PausableBase } from '@openzeppelin/contracts/security/Pausable.sol';
import { ManagerRole } from './roles/ManagerRole.sol';

/**
 * @title Pausable
 * @notice Base contract that implements the emergency pause mechanism
 */
abstract contract Pausable is PausableBase, ManagerRole {
    /**
     * @notice Enter pause state
     */
    function pause() external onlyManager whenNotPaused {
        _pause();
    }

    /**
     * @notice Exit pause state
     */
    function unpause() external onlyManager whenPaused {
        _unpause();
    }
}

File 20 of 22 : ManagerRole.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { RoleBearers } from './RoleBearers.sol';

/**
 * @title ManagerRole
 * @notice Base contract that implements the Manager role.
 * The manager role is a high-permission role for core team members only.
 * Managers can set vaults and routers addresses, fees, cross-chain protocols,
 * and other parameters for Interchain (cross-chain) swaps and single-network swaps.
 * Please note, the manager role is unique for every contract,
 * hence different addresses may be assigned as managers for different contracts.
 */
abstract contract ManagerRole is Ownable, RoleBearers {
    bytes32 private constant ROLE_KEY = keccak256('Manager');

    /**
     * @notice Emitted when the Manager role status for the account is updated
     * @param account The account address
     * @param value The Manager role status flag
     */
    event SetManager(address indexed account, bool indexed value);

    /**
     * @notice Emitted when the Manager role status for the account is renounced
     * @param account The account address
     */
    event RenounceManagerRole(address indexed account);

    /**
     * @notice Emitted when the caller is not a Manager role bearer
     */
    error OnlyManagerError();

    /**
     * @dev Modifier to check if the caller is a Manager role bearer
     */
    modifier onlyManager() {
        if (!isManager(msg.sender)) {
            revert OnlyManagerError();
        }

        _;
    }

    /**
     * @notice Updates the Manager role status for the account
     * @param _account The account address
     * @param _value The Manager role status flag
     */
    function setManager(address _account, bool _value) public onlyOwner {
        _setRoleBearer(ROLE_KEY, _account, _value);

        emit SetManager(_account, _value);
    }

    /**
     * @notice Renounces the Manager role
     */
    function renounceManagerRole() external onlyManager {
        _setRoleBearer(ROLE_KEY, msg.sender, false);

        emit RenounceManagerRole(msg.sender);
    }

    /**
     * @notice Getter of the Manager role bearer count
     * @return The Manager role bearer count
     */
    function managerCount() external view returns (uint256) {
        return _roleBearerCount(ROLE_KEY);
    }

    /**
     * @notice Getter of the complete list of the Manager role bearers
     * @return The complete list of the Manager role bearers
     */
    function fullManagerList() external view returns (address[] memory) {
        return _fullRoleBearerList(ROLE_KEY);
    }

    /**
     * @notice Getter of the Manager role bearer status
     * @param _account The account address
     */
    function isManager(address _account) public view returns (bool) {
        return _isRoleBearer(ROLE_KEY, _account);
    }

    function _initRoles(
        address _owner,
        address[] memory _managers,
        bool _addOwnerToManagers
    ) internal {
        address ownerAddress = _owner == address(0) ? msg.sender : _owner;

        for (uint256 index; index < _managers.length; index++) {
            setManager(_managers[index], true);
        }

        if (_addOwnerToManagers && !isManager(ownerAddress)) {
            setManager(ownerAddress, true);
        }

        if (ownerAddress != msg.sender) {
            transferOwnership(ownerAddress);
        }
    }
}

File 21 of 22 : RoleBearers.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import '../Constants.sol' as Constants;
import '../DataStructures.sol' as DataStructures;

/**
 * @title RoleBearers
 * @notice Base contract that implements role-based access control
 * @dev A custom implementation providing full role bearer lists
 */
abstract contract RoleBearers {
    mapping(bytes32 /*roleKey*/ => address[] /*roleBearers*/) private roleBearerTable;
    mapping(bytes32 /*roleKey*/ => mapping(address /*account*/ => DataStructures.OptionalValue /*status*/))
        private roleBearerIndexTable;

    function _setRoleBearer(bytes32 _roleKey, address _account, bool _value) internal {
        DataStructures.uniqueAddressListUpdate(
            roleBearerTable[_roleKey],
            roleBearerIndexTable[_roleKey],
            _account,
            _value,
            Constants.LIST_SIZE_LIMIT_DEFAULT
        );
    }

    function _isRoleBearer(bytes32 _roleKey, address _account) internal view returns (bool) {
        return roleBearerIndexTable[_roleKey][_account].isSet;
    }

    function _roleBearerCount(bytes32 _roleKey) internal view returns (uint256) {
        return roleBearerTable[_roleKey].length;
    }

    function _fullRoleBearerList(bytes32 _roleKey) internal view returns (address[] memory) {
        return roleBearerTable[_roleKey];
    }
}

File 22 of 22 : SystemVersionId.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title SystemVersionId
 * @notice Base contract providing the system version identifier
 */
abstract contract SystemVersionId {
    /**
     * @dev The system version identifier
     */
    uint256 public constant SYSTEM_VERSION_ID = uint256(keccak256('Initial'));
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_endpointAddress","type":"address"},{"components":[{"internalType":"uint256","name":"standardId","type":"uint256"},{"internalType":"uint16","name":"layerZeroId","type":"uint16"}],"internalType":"struct LayerZeroGatewayV2.ChainIdPair[]","name":"_chainIdPairs","type":"tuple[]"},{"internalType":"uint256","name":"_minTargetGasDefault","type":"uint256"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct KeyToValue[]","name":"_minTargetGasCustomData","type":"tuple[]"},{"internalType":"uint256","name":"_targetGasReserve","type":"uint256"},{"internalType":"address","name":"_processingFeeCollector","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_managers","type":"address[]"},{"internalType":"bool","name":"_addOwnerToManagers","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"LayerZeroChainIdNotSetError","type":"error"},{"inputs":[],"name":"ListSizeLimitError","type":"error"},{"inputs":[],"name":"MinTargetGasError","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NonContractAddressError","type":"error"},{"inputs":[],"name":"OnlyClientError","type":"error"},{"inputs":[],"name":"OnlyEndpointError","type":"error"},{"inputs":[],"name":"OnlyManagerError","type":"error"},{"inputs":[],"name":"PeerAddressMismatchError","type":"error"},{"inputs":[],"name":"PeerNotSetError","type":"error"},{"inputs":[],"name":"ProcessingFeeError","type":"error"},{"inputs":[],"name":"ReservedTokenError","type":"error"},{"inputs":[],"name":"SafeTransferError","type":"error"},{"inputs":[],"name":"SafeTransferNativeError","type":"error"},{"inputs":[],"name":"ZeroAddressError","type":"error"},{"inputs":[],"name":"ZeroChainIdError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"standardId","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"layerZeroId","type":"uint16"}],"name":"RemoveChainIdPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"standardChainId","type":"uint256"}],"name":"RemoveMinTargetGasCustom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"RemovePeer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RenounceManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"standardId","type":"uint256"},{"indexed":true,"internalType":"uint16","name":"layerZeroId","type":"uint16"}],"name":"SetChainIdPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clientAddress","type":"address"}],"name":"SetClient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"endpointAddress","type":"address"}],"name":"SetEndpoint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"standardChainId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minTargetGas","type":"uint256"}],"name":"SetMinTargetGasCustom","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minTargetGas","type":"uint256"}],"name":"SetMinTargetGasDefault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"peerAddress","type":"address"}],"name":"SetPeer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"processingFeeCollector","type":"address"}],"name":"SetProcessingFeeCollector","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasReserve","type":"uint256"}],"name":"SetTargetGasReserve","type":"event"},{"anonymous":false,"inputs":[],"name":"TargetClientNotSetFailure","type":"event"},{"anonymous":false,"inputs":[],"name":"TargetExecutionFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"}],"name":"TargetFromAddressFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sourceChainId","type":"uint256"}],"name":"TargetGasReserveFailure","type":"event"},{"anonymous":false,"inputs":[],"name":"TargetPausedFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"SYSTEM_VERSION_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"cleanup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"client","outputs":[{"internalType":"contract IGatewayClient","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullManagerList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullPeerChainIdList","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"","type":"uint16"}],"name":"layerZeroToStandardChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"_srcChainId","type":"uint16"},{"internalType":"bytes","name":"_srcAddress","type":"bytes"},{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"managerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_targetChainId","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"bytes","name":"_settings","type":"bytes"}],"name":"messageFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_standardChainId","type":"uint256"}],"name":"minTargetGas","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"minTargetGasCustom","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minTargetGasDefault","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"peerChainIdIndexMap","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"peerChainIdList","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"peerMap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"processingFeeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_standardChainIds","type":"uint256[]"}],"name":"removeChainIdPairs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_standardChainId","type":"uint256"}],"name":"removeMinTargetGasCustom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_chainIds","type":"uint256[]"}],"name":"removePeers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_targetChainId","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"bytes","name":"_settings","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"standardId","type":"uint256"},{"internalType":"uint16","name":"layerZeroId","type":"uint16"}],"internalType":"struct LayerZeroGatewayV2.ChainIdPair[]","name":"_chainIdPairs","type":"tuple[]"}],"name":"setChainIdPairs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_clientAddress","type":"address"}],"name":"setClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_endpointAddress","type":"address"}],"name":"setEndpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_standardChainId","type":"uint256"},{"internalType":"uint256","name":"_minTargetGas","type":"uint256"}],"name":"setMinTargetGasCustom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minTargetGas","type":"uint256"}],"name":"setMinTargetGasDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"address","name":"value","type":"address"}],"internalType":"struct KeyToAddressValue[]","name":"_peers","type":"tuple[]"}],"name":"setPeers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_processingFeeCollector","type":"address"}],"name":"setProcessingFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasReserve","type":"uint256"}],"name":"setTargetGasReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"standardToLayerZeroChainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"targetGasReserve","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"tokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620034ae380380620034ae833981016040819052620000349162000ac2565b6000805460ff19169055620000493362000154565b60016003556200005989620001ad565b60005b8851811015620000b75760008982815181106200007d576200007d62000bb3565b60200260200101519050620000a1816000015182602001516200020260201b60201c565b5080620000ae8162000bdf565b9150506200005c565b50620000c38762000260565b60005b865181101562000121576000878281518110620000e757620000e762000bb3565b602002602001015190506200010b816000015182602001516200029c60201b60201c565b5080620001188162000bdf565b915050620000c6565b506200012d856200030f565b620001388462000345565b620001458383836200038f565b50505050505050505062000c27565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b620001b88162000449565b600980546001600160a01b0319166001600160a01b0383169081179091556040517fc8e81a4efc849969069ec6aae575cf7a6bc5f9d3abac59f4ed190a6f7e05fc6f90600090a250565b6000828152600a60209081526040808320805461ffff191661ffff8616908117909155808452600b90925280832085905551909184917fe8b662b513ff40c8ca90e64deacc96541614246ae47724df4d670d6b3ba2e5d79190a35050565b600c8190556040518181527f4482bd706ea2970ea43d9096440f831b2d23a97cb2ac77bde31bf5efff14ee42906020015b60405180910390a150565b604080518082018252600180825260208083018581526000878152600d83528590209351845460ff191690151517845551929091019190915581518481529081018390527f0bf9fc5793c10b41b09b96b32d3c1378d9156d4d0eec49a2fbe259c2605afdb0910160405180910390a15050565b60048190556040518181527fec9e8f9ec7dd2c5310e5b87c7bedeb6ba1c5943cb4d2da1ee80335508a5bc5a49060200162000291565b600e80546001600160a01b0319166001600160a01b0383169081179091556040517f9113819388a87769f8958d74097d68f96e457d5bc25f0168a8ffb3d3a55672a390600090a250565b60006001600160a01b03841615620003a85783620003aa565b335b905060005b8351811015620003fd57620003e8848281518110620003d257620003d262000bb3565b602002602001015160016200048560201b60201c565b80620003f48162000bdf565b915050620003af565b508180156200041457506200041281620004f8565b155b1562000427576200042781600162000485565b6001600160a01b0381163314620004435762000443816200053a565b50505050565b6001600160a01b0381163b6200048257604051638c50d7cd60e01b81526001600160a01b03821660048201526024015b60405180910390fd5b50565b6200048f620005b6565b620004bc7f6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6f83836200061a565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff165b92915050565b62000544620005b6565b6001600160a01b038116620005ab5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000479565b620004828162000154565b6000546001600160a01b03610100909104163314620006185760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000479565b565b600083815260016020908152604080832060029092529091206200044391908484606460008262000658576200065286868662000670565b62000666565b6200066686868685620007a5565b9695505050505050565b6001600160a01b0381166000908152602083905260409020805460ff169081156200079d5760018082015486549091600091620006ae919062000bfb565b905080821462000742576000878281548110620006cf57620006cf62000bb3565b9060005260206000200160009054906101000a90046001600160a01b031690508088848154811062000705576200070562000bb3565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b8680548062000755576200075562000c11565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015620008525784548211620007eb5760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b03191690911790555b949350505050565b80516001600160a01b03811681146200087257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715620008b257620008b262000877565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620008e357620008e362000877565b604052919050565b60006001600160401b0382111562000907576200090762000877565b5060051b60200190565b600082601f8301126200092357600080fd5b815160206200093c6200093683620008eb565b620008b8565b82815260069290921b840181019181810190868411156200095c57600080fd5b8286015b84811015620009b257604081890312156200097b5760008081fd5b620009856200088d565b815181528482015161ffff811681146200099f5760008081fd5b8186015283529183019160400162000960565b509695505050505050565b600082601f830112620009cf57600080fd5b81516020620009e26200093683620008eb565b82815260069290921b8401810191818101908684111562000a0257600080fd5b8286015b84811015620009b2576040818903121562000a215760008081fd5b62000a2b6200088d565b81518152848201518582015283529183019160400162000a06565b600082601f83011262000a5857600080fd5b8151602062000a6b6200093683620008eb565b82815260059290921b8401810191818101908684111562000a8b57600080fd5b8286015b84811015620009b25762000aa3816200085a565b835291830191830162000a8f565b805180151581146200087257600080fd5b60008060008060008060008060006101208a8c03121562000ae257600080fd5b62000aed8a6200085a565b60208b01519099506001600160401b038082111562000b0b57600080fd5b62000b198d838e0162000911565b995060408c0151985060608c015191508082111562000b3757600080fd5b62000b458d838e01620009bd565b975060808c0151965062000b5c60a08d016200085a565b955062000b6c60c08d016200085a565b945060e08c015191508082111562000b8357600080fd5b5062000b928c828d0162000a46565b92505062000ba46101008b0162000ab1565b90509295985092959850929598565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162000bf45762000bf462000bc9565b5060010190565b8181038181111562000534576200053462000bc9565b634e487b7160e01b600052603160045260246000fd5b6128778062000c376000396000f3fe60806040526004361061025b5760003560e01c8063832b549111610144578063c84e329e116100b6578063e81ea5951161007a578063e81ea595146107b4578063eca7faab146107c9578063ee10bf88146107f6578063eedc966a14610816578063f2fde38b14610836578063f3ae24151461085657600080fd5b8063c84e329e146106e2578063cb2beb3d14610718578063dbbb415514610752578063dcd44d7114610772578063e3725b151461079257600080fd5b8063a5e90eee11610108578063a5e90eee1461062b578063aa4fc83d1461064b578063bb6e49361461066b578063bc7881691461068b578063bd1fd0ab146106ad578063c2c518e1146106cd57600080fd5b8063832b5491146105935780638456cb59146105b35780638526690a146105c85780638da5cb5b146105e8578063a4b1ce9a1461060b57600080fd5b806330eb1278116101dd5780635c975abb116101a15780635c975abb146104c25780635e280f11146104da578063630eae08146104fa5780636ea9cec91461051a578063715018a61461052d578063786ea0ce1461054257600080fd5b806330eb12781461040257806336c3aaba146104225780633f4ba83a14610466578063440d72481461047b5780635a9fab50146104ac57600080fd5b80631fd83e67116102245780631fd83e671461036c5780632460f34b1461038c5780632d7bb409146103ac5780632f204e81146103c25780632fac88c0146103e257600080fd5b80621d3567146102605780630275dfd214610282578063093f0e27146102a2578063103b7397146102e9578063109e94cf14610334575b600080fd5b34801561026c57600080fd5b5061028061027b366004612200565b610876565b005b34801561028e57600080fd5b5061028061029d3660046122fe565b610aaf565b3480156102ae57600080fd5b506102d67f22ad9585a395edc8067b50da4778cafbb7fa2c4bbd7619fad6aeba403857fd7481565b6040519081526020015b60405180910390f35b3480156102f557600080fd5b5060008051602061282283398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546102d6565b34801561034057600080fd5b50600554610354906001600160a01b031681565b6040516001600160a01b0390911681526020016102e0565b34801561037857600080fd5b5061028061038736600461235c565b610ae6565b34801561039857600080fd5b506102806103a73660046122fe565b610b6a565b3480156103b857600080fd5b506102d6600c5481565b3480156103ce57600080fd5b506102806103dd36600461239e565b610b99565b3480156103ee57600080fd5b506102806103fd36600461235c565b610c03565b34801561040e57600080fd5b5061028061041d366004612428565b610cbf565b34801561042e57600080fd5b5061045361043d3660046122fe565b600a6020526000908152604090205461ffff1681565b60405161ffff90911681526020016102e0565b34801561047257600080fd5b50610280610d23565b34801561048757600080fd5b5061049c610496366004612454565b50600090565b60405190151581526020016102e0565b3480156104b857600080fd5b506102d660045481565b3480156104ce57600080fd5b5060005460ff1661049c565b3480156104e657600080fd5b50600954610354906001600160a01b031681565b34801561050657600080fd5b506102806105153660046122fe565b610d5b565b610280610528366004612478565b610d8a565b34801561053957600080fd5b50610280610f33565b34801561054e57600080fd5b5061057c61055d3660046122fe565b6008602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016102e0565b34801561059f57600080fd5b506102d66105ae3660046122fe565b610f45565b3480156105bf57600080fd5b50610280610f66565b3480156105d457600080fd5b506102806105e3366004612454565b610f9c565b3480156105f457600080fd5b5060005461010090046001600160a01b0316610354565b34801561061757600080fd5b506102d66106263660046122fe565b611015565b34801561063757600080fd5b506102806106463660046124e2565b611041565b34801561065757600080fd5b506102d6610666366004612478565b61109e565b34801561067757600080fd5b50600e54610354906001600160a01b031681565b34801561069757600080fd5b506106a061115c565b6040516102e0919061251b565b3480156106b957600080fd5b506102806106c836600461255f565b6111b4565b3480156106d957600080fd5b506102806111e4565b3480156106ee57600080fd5b506103546106fd3660046122fe565b6006602052600090815260409020546001600160a01b031681565b34801561072457600080fd5b5061057c6107333660046122fe565b600d602052600090815260409020805460019091015460ff9091169082565b34801561075e57600080fd5b5061028061076d366004612454565b611251565b34801561077e57600080fd5b5061028061078d36600461239e565b611280565b34801561079e57600080fd5b506107a76112f1565b6040516102e09190612581565b3480156107c057600080fd5b506007546102d6565b3480156107d557600080fd5b506102d66107e43660046125c2565b600b6020526000908152604090205481565b34801561080257600080fd5b50610280610811366004612454565b61130a565b34801561082257600080fd5b506102d6610831366004612454565b611339565b34801561084257600080fd5b50610280610851366004612454565b6113da565b34801561086257600080fd5b5061049c610871366004612454565b611455565b61087e611495565b6009546001600160a01b031633146108a95760405163d9b0b35560e01b815260040160405180910390fd5b60005460ff16156108e2576040517febfa14817ead60a20b8a0fc2f6e70025b7414b60eeb0f786c0446e7e543db64b90600090a1610a9e565b6005546001600160a01b0316610920576040517fe01ba9b0feb354b2205901cb697991b39ccdfdb7967cd9d28eed6d2b9ab0903490600090a1610a9e565b61ffff85166000908152600b602052604081205460148601519091821580159061095257506001600160a01b03821615155b801561097757506000838152600660205260409020546001600160a01b038381169116145b9050806109bc576040516001600160a01b0383169084907fac80426faf130d4151e14cb1e038276f673086f5fc3dd98833115986676840cf90600090a3505050610a9e565b6000806109ca6004546114ee565b9150915081610a085760405185907f4222f6e215aa16476c9027f9b1025ddb1b27a125d45d40a9e87a76caa5133db890600090a25050505050610a9e565b60055460405163032ad3cf60e51b81526001600160a01b039091169063655a79e0908390610a3e9089908c908c90600401612606565b600060405180830381600088803b158015610a5857600080fd5b5087f193505050508015610a6a575060015b610a98576040517f3004b2d8ec75a545f6abc58879cd00cc4fb6c951131a7cf023a21fc01020e78690600090a15b50505050505b610aa86001600355565b5050505050565b610ab833611455565b610ad557604051637c3ea23f60e01b815260040160405180910390fd5b610ade8161151a565b50565b905090565b610aef33611455565b610b0c57604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b655736838383818110610b2a57610b2a612629565b9050604002019050610b528160000135826020016020810190610b4d91906125c2565b611573565b5080610b5d81612655565b915050610b0f565b505050565b610b7333611455565b610b9057604051637c3ea23f60e01b815260040160405180910390fd5b610ade816115d1565b610ba233611455565b610bbf57604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b65576000838383818110610bde57610bde612629565b905060200201359050610bf081611606565b5080610bfb81612655565b915050610bc2565b610c0c33611455565b610c2957604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b655736838383818110610c4757610c47612629565b604090810292909201925050813590600090610c6890840160208501612454565b9050468203610c9f576001600160a01b0381163014610c9a57604051631131ed9760e31b815260040160405180910390fd5b610ca9565b610ca98282611662565b5050508080610cb790612655565b915050610c2c565b610cc833611455565b610ce557604051637c3ea23f60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610d1857610d1433826116f7565b5050565b610d14823383611785565b610d2c33611455565b610d4957604051637c3ea23f60e01b815260040160405180910390fd5b610d51611877565b610d596118c0565b565b610d6433611455565b610d8157604051637c3ea23f60e01b815260040160405180910390fd5b610ade81611912565b6005546001600160a01b03163314610db55760405163424029e160e01b815260040160405180910390fd5b610dbd611947565b6000610dc88661198d565b6000878152600a602052604081205491925061ffff90911690819003610e015760405163d5a6cc2d60e01b815260040160405180910390fd5b600080610e0f86868b6119c3565b9150915080341015610e34576040516360b5c54960e01b815260040160405180910390fd5b600081118015610e4e5750600e546001600160a01b031615155b15610e6957600e54610e69906001600160a01b0316826116f7565b6009546001600160a01b031663c5803100610e84833461266e565b6040516bffffffffffffffffffffffff19606089811b8216602084015230901b166034820152869060480160408051601f19818403018152908290526005546001600160e01b031960e087901b168352610ef693928f918f916001600160a01b03909116906000908c906004016126d1565b6000604051808303818588803b158015610f0f57600080fd5b505af1158015610f23573d6000803e3d6000fd5b5050505050505050505050505050565b610f3b611a38565b610d596000611a98565b60078181548110610f5557600080fd5b600091825260209091200154905081565b610f6f33611455565b610f8c57604051637c3ea23f60e01b815260040160405180910390fd5b610f94611947565b610d59611af1565b610fa533611455565b610fc257604051637c3ea23f60e01b815260040160405180910390fd5b610fcb81611b2e565b600580546001600160a01b0319166001600160a01b0383169081179091556040517f764166c557b419ae9f4bca81c505141ce7017b4bdb4c610ad113a50ec7e578a990600090a250565b6000818152600d60205260408120805460ff1615611037576001015492915050565b5050600c54919050565b611049611a38565b6110626000805160206128228339815191528383611b61565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6000858152600a602052604081205461ffff1681806110be86868b6119c3565b60095460405163040a7bb160e41b81529294509092506000916001600160a01b03909116906340a7bb109061110190879030908e908e9088908b9060040161272c565b6040805180830381865afa15801561111d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111419190612782565b50905061114e82826127a6565b9a9950505050505050505050565b606060078054806020026020016040519081016040528092919081815260200182805480156111aa57602002820191906000526020600020905b815481526020019060010190808311611196575b5050505050905090565b6111bd33611455565b6111da57604051637c3ea23f60e01b815260040160405180910390fd5b610d148282611b8e565b6111ed33611455565b61120a57604051637c3ea23f60e01b815260040160405180910390fd5b611224600080516020612822833981519152336000611b61565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b61125a33611455565b61127757604051637c3ea23f60e01b815260040160405180910390fd5b610ade81611c01565b61128933611455565b6112a657604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b655760008383838181106112c5576112c5612629565b9050602002013590504681146112de576112de81611c54565b50806112e981612655565b9150506112a9565b6060610ae1600080516020612822833981519152611cb3565b61131333611455565b61133057604051637c3ea23f60e01b815260040160405180910390fd5b610ade81611d1f565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611367575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf91906127b9565b92915050565b919050565b6113e2611a38565b6001600160a01b03811661144c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610ade81611a98565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff166113cf565b6002600354036114e75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611443565b6002600355565b60008060005a905083811015925082611508576000611512565b611512848261266e565b915050915091565b6000818152600d6020526040808220805460ff1916815560010191909155517f7333f4fc2afbb7d9887b8beab88e2deb99cc44fe3405f0f174e50c53116b922f906115689083815260200190565b60405180910390a150565b6000828152600a60209081526040808320805461ffff191661ffff8616908117909155808452600b90925280832085905551909184917fe8b662b513ff40c8ca90e64deacc96541614246ae47724df4d670d6b3ba2e5d79190a35050565b600c8190556040518181527f4482bd706ea2970ea43d9096440f831b2d23a97cb2ac77bde31bf5efff14ee4290602001611568565b6000818152600a60209081526040808320805461ffff19811690915561ffff16808452600b909252808320839055519091829184917f487d90e6c0c486fcf4e9b12707215f206056b5371b667b782a65b559a001122b91a35050565b81600003611683576040516381e7376360e01b815260040160405180910390fd5b6001600160a01b0381166116aa57604051633efa09af60e01b815260040160405180910390fd5b6116bc60066007600885856064611d69565b506040516001600160a01b0382169083907f357d1ebd1dc0d53cc15161206b9a39c9ca30667bd997cf921eb00e4c78a454f590600090a35050565b604080516000808252602082019092526001600160a01b03841690839060405161172191906127d2565b60006040518083038185875af1925050503d806000811461175e576040519150601f19603f3d011682016040523d82523d6000602084013e611763565b606091505b5050905080610b6557604051632e05b05360e21b815260040160405180910390fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916117e191906127d2565b6000604051808303816000865af19150503d806000811461181e576040519150601f19603f3d011682016040523d82523d6000602084013e611823565b606091505b5091509150600082801561184f57508151158061184f57508180602001905181019061184f91906127ee565b90508061186f57604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b60005460ff16610d595760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401611443565b6118c8611877565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60048190556040518181527fec9e8f9ec7dd2c5310e5b87c7bedeb6ba1c5943cb4d2da1ee80335508a5bc5a490602001611568565b60005460ff1615610d595760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401611443565b6000818152600660205260408120546001600160a01b0316806113cf57604051631a81634560e01b815260040160405180910390fd5b60606000806119d48587018761255f565b9250905060006119e385611015565b905080821015611a0657604051637d6aa4df60e01b815260040160405180910390fd5b604051600160f01b60208201526022810183905260420160405160208183030381529060405293505050935093915050565b6000546001600160a01b03610100909104163314610d595760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611443565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b611af9611947565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586118f53390565b6001600160a01b0381163b610ade57604051638c50d7cd60e01b81526001600160a01b0382166004820152602401611443565b60008381526001602090815260408083206002909252909120611b88919084846064611dc5565b50505050565b604080518082018252600180825260208083018581526000878152600d83528590209351845460ff191690151517845551929091019190915581518481529081018390527f0bf9fc5793c10b41b09b96b32d3c1378d9156d4d0eec49a2fbe259c2605afdb0910160405180910390a15050565b611c0a81611b2e565b600980546001600160a01b0319166001600160a01b0383169081179091556040517fc8e81a4efc849969069ec6aae575cf7a6bc5f9d3abac59f4ed190a6f7e05fc6f90600090a250565b80600003611c75576040516381e7376360e01b815260040160405180910390fd5b611c8460066007600884611df2565b5060405181907feb39225b53386d0eb02af9cf2c6b6a0c345a97654f1e67fb21b0b5aaac81ec4a90600090a250565b600081815260016020908152604091829020805483518184028101840190945280845260609392830182828015611d1357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cf5575b50505050509050919050565b600e80546001600160a01b0319166001600160a01b0383169081179091556040517f9113819388a87769f8958d74097d68f96e457d5bc25f0168a8ffb3d3a55672a390600090a250565b60008381526020859052604090205460ff16158015611d9057611d8e86868685611e3b565b505b600093845260209690965250604090912080546001600160a01b0319166001600160a01b039092169190911790555090919050565b600082611ddc57611dd7868686611ec4565b611de8565b611de886868685611fec565b9695505050505050565b60008181526020839052604090205460ff168015611e3357600082815260208690526040902080546001600160a01b0319169055611e3184848461209c565b505b949350505050565b60008281526020849052604090205460ff16158015611e335784548211611e755760405163b1655e3360e01b815260040160405180910390fd5b60408051808201825260018082528754602080840191825260008881529881529388209251835460ff191690151517835551918101919091558654908101875595855290932090930155919050565b6001600160a01b0381166000908152602083905260409020805460ff16908115611fe45760018082015486549091600091611eff919061266e565b9050808214611f8c576000878281548110611f1c57611f1c612629565b9060005260206000200160009054906101000a90046001600160a01b0316905080888481548110611f4f57611f4f612629565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b86805480611f9c57611f9c61280b565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015611e3357845482116120305760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b039790971660008181529888529388209251835460ff19169015151783555191810191909155865490810187559585529290932090930180546001600160a01b0319169091179055919050565b6000818152602083905260409020805460ff16908115611fe457600180820154865490916000916120cd919061266e565b905080821461212c5760008782815481106120ea576120ea612629565b906000526020600020015490508088848154811061210a5761210a612629565b6000918252602080832090910192909255918252879052604090206001018290555b8680548061213c5761213c61280b565b60008281526020808220830160001990810183905590920190925586825287905260408120805460ff19168155600101555050509392505050565b803561ffff811681146113d557600080fd5b634e487b7160e01b600052604160045260246000fd5b803567ffffffffffffffff811681146113d557600080fd5b60008083601f8401126121c957600080fd5b50813567ffffffffffffffff8111156121e157600080fd5b6020830191508360208285010111156121f957600080fd5b9250929050565b60008060008060006080868803121561221857600080fd5b61222186612177565b9450602086013567ffffffffffffffff8082111561223e57600080fd5b818801915088601f83011261225257600080fd5b81358181111561226457612264612189565b604051601f8201601f19908116603f0116810190838211818310171561228c5761228c612189565b816040528281528b60208487010111156122a557600080fd5b826020860160208301376000602084830101528098505050506122ca6040890161219f565b945060608801359150808211156122e057600080fd5b506122ed888289016121b7565b969995985093965092949392505050565b60006020828403121561231057600080fd5b5035919050565b60008083601f84011261232957600080fd5b50813567ffffffffffffffff81111561234157600080fd5b6020830191508360208260061b85010111156121f957600080fd5b6000806020838503121561236f57600080fd5b823567ffffffffffffffff81111561238657600080fd5b61239285828601612317565b90969095509350505050565b600080602083850312156123b157600080fd5b823567ffffffffffffffff808211156123c957600080fd5b818501915085601f8301126123dd57600080fd5b8135818111156123ec57600080fd5b8660208260051b850101111561240157600080fd5b60209290920196919550909350505050565b6001600160a01b0381168114610ade57600080fd5b6000806040838503121561243b57600080fd5b823561244681612413565b946020939093013593505050565b60006020828403121561246657600080fd5b813561247181612413565b9392505050565b60008060008060006060868803121561249057600080fd5b85359450602086013567ffffffffffffffff808211156124af57600080fd5b6124bb89838a016121b7565b909650945060408801359150808211156122e057600080fd5b8015158114610ade57600080fd5b600080604083850312156124f557600080fd5b823561250081612413565b91506020830135612510816124d4565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561255357835183529284019291840191600101612537565b50909695505050505050565b6000806040838503121561257257600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156125535783516001600160a01b03168352928401929184019160010161259d565b6000602082840312156125d457600080fd5b61247182612177565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006126206040830184866125dd565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016126675761266761263f565b5060010190565b818103818111156113cf576113cf61263f565b60005b8381101561269c578181015183820152602001612684565b50506000910152565b600081518084526126bd816020860160208601612681565b601f01601f19169290920160200192915050565b61ffff8816815260c0602082015260006126ee60c08301896126a5565b828103604084015261270181888a6125dd565b6001600160a01b0387811660608601528616608085015283810360a0850152905061114e81856126a5565b61ffff871681526001600160a01b038616602082015260a06040820181905260009061275b90830186886125dd565b8415156060840152828103608084015261277581856126a5565b9998505050505050505050565b6000806040838503121561279557600080fd5b505080516020909101519092909150565b808201808211156113cf576113cf61263f565b6000602082840312156127cb57600080fd5b5051919050565b600082516127e4818460208701612681565b9190910192915050565b60006020828403121561280057600080fd5b8151612471816124d4565b634e487b7160e01b600052603160045260246000fdfe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa2646970667358221220977d7da2c021523b35a532faedc5277896234f7d5500bcd36c8943712b23580164736f6c6343000813003300000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000249f000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000ed648d84268502b512e175d7d4873bfe685db8aa00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000066000000000000000000000000000000000000000000000000000000000000a86a000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000089000000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000a4b1000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000000a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001440000000000000000000000000000000000000000000000000000000000124f8000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005e0fde554be338e3682b7c3f724ade791d3e80ca

Deployed Bytecode

0x60806040526004361061025b5760003560e01c8063832b549111610144578063c84e329e116100b6578063e81ea5951161007a578063e81ea595146107b4578063eca7faab146107c9578063ee10bf88146107f6578063eedc966a14610816578063f2fde38b14610836578063f3ae24151461085657600080fd5b8063c84e329e146106e2578063cb2beb3d14610718578063dbbb415514610752578063dcd44d7114610772578063e3725b151461079257600080fd5b8063a5e90eee11610108578063a5e90eee1461062b578063aa4fc83d1461064b578063bb6e49361461066b578063bc7881691461068b578063bd1fd0ab146106ad578063c2c518e1146106cd57600080fd5b8063832b5491146105935780638456cb59146105b35780638526690a146105c85780638da5cb5b146105e8578063a4b1ce9a1461060b57600080fd5b806330eb1278116101dd5780635c975abb116101a15780635c975abb146104c25780635e280f11146104da578063630eae08146104fa5780636ea9cec91461051a578063715018a61461052d578063786ea0ce1461054257600080fd5b806330eb12781461040257806336c3aaba146104225780633f4ba83a14610466578063440d72481461047b5780635a9fab50146104ac57600080fd5b80631fd83e67116102245780631fd83e671461036c5780632460f34b1461038c5780632d7bb409146103ac5780632f204e81146103c25780632fac88c0146103e257600080fd5b80621d3567146102605780630275dfd214610282578063093f0e27146102a2578063103b7397146102e9578063109e94cf14610334575b600080fd5b34801561026c57600080fd5b5061028061027b366004612200565b610876565b005b34801561028e57600080fd5b5061028061029d3660046122fe565b610aaf565b3480156102ae57600080fd5b506102d67f22ad9585a395edc8067b50da4778cafbb7fa2c4bbd7619fad6aeba403857fd7481565b6040519081526020015b60405180910390f35b3480156102f557600080fd5b5060008051602061282283398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546102d6565b34801561034057600080fd5b50600554610354906001600160a01b031681565b6040516001600160a01b0390911681526020016102e0565b34801561037857600080fd5b5061028061038736600461235c565b610ae6565b34801561039857600080fd5b506102806103a73660046122fe565b610b6a565b3480156103b857600080fd5b506102d6600c5481565b3480156103ce57600080fd5b506102806103dd36600461239e565b610b99565b3480156103ee57600080fd5b506102806103fd36600461235c565b610c03565b34801561040e57600080fd5b5061028061041d366004612428565b610cbf565b34801561042e57600080fd5b5061045361043d3660046122fe565b600a6020526000908152604090205461ffff1681565b60405161ffff90911681526020016102e0565b34801561047257600080fd5b50610280610d23565b34801561048757600080fd5b5061049c610496366004612454565b50600090565b60405190151581526020016102e0565b3480156104b857600080fd5b506102d660045481565b3480156104ce57600080fd5b5060005460ff1661049c565b3480156104e657600080fd5b50600954610354906001600160a01b031681565b34801561050657600080fd5b506102806105153660046122fe565b610d5b565b610280610528366004612478565b610d8a565b34801561053957600080fd5b50610280610f33565b34801561054e57600080fd5b5061057c61055d3660046122fe565b6008602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016102e0565b34801561059f57600080fd5b506102d66105ae3660046122fe565b610f45565b3480156105bf57600080fd5b50610280610f66565b3480156105d457600080fd5b506102806105e3366004612454565b610f9c565b3480156105f457600080fd5b5060005461010090046001600160a01b0316610354565b34801561061757600080fd5b506102d66106263660046122fe565b611015565b34801561063757600080fd5b506102806106463660046124e2565b611041565b34801561065757600080fd5b506102d6610666366004612478565b61109e565b34801561067757600080fd5b50600e54610354906001600160a01b031681565b34801561069757600080fd5b506106a061115c565b6040516102e0919061251b565b3480156106b957600080fd5b506102806106c836600461255f565b6111b4565b3480156106d957600080fd5b506102806111e4565b3480156106ee57600080fd5b506103546106fd3660046122fe565b6006602052600090815260409020546001600160a01b031681565b34801561072457600080fd5b5061057c6107333660046122fe565b600d602052600090815260409020805460019091015460ff9091169082565b34801561075e57600080fd5b5061028061076d366004612454565b611251565b34801561077e57600080fd5b5061028061078d36600461239e565b611280565b34801561079e57600080fd5b506107a76112f1565b6040516102e09190612581565b3480156107c057600080fd5b506007546102d6565b3480156107d557600080fd5b506102d66107e43660046125c2565b600b6020526000908152604090205481565b34801561080257600080fd5b50610280610811366004612454565b61130a565b34801561082257600080fd5b506102d6610831366004612454565b611339565b34801561084257600080fd5b50610280610851366004612454565b6113da565b34801561086257600080fd5b5061049c610871366004612454565b611455565b61087e611495565b6009546001600160a01b031633146108a95760405163d9b0b35560e01b815260040160405180910390fd5b60005460ff16156108e2576040517febfa14817ead60a20b8a0fc2f6e70025b7414b60eeb0f786c0446e7e543db64b90600090a1610a9e565b6005546001600160a01b0316610920576040517fe01ba9b0feb354b2205901cb697991b39ccdfdb7967cd9d28eed6d2b9ab0903490600090a1610a9e565b61ffff85166000908152600b602052604081205460148601519091821580159061095257506001600160a01b03821615155b801561097757506000838152600660205260409020546001600160a01b038381169116145b9050806109bc576040516001600160a01b0383169084907fac80426faf130d4151e14cb1e038276f673086f5fc3dd98833115986676840cf90600090a3505050610a9e565b6000806109ca6004546114ee565b9150915081610a085760405185907f4222f6e215aa16476c9027f9b1025ddb1b27a125d45d40a9e87a76caa5133db890600090a25050505050610a9e565b60055460405163032ad3cf60e51b81526001600160a01b039091169063655a79e0908390610a3e9089908c908c90600401612606565b600060405180830381600088803b158015610a5857600080fd5b5087f193505050508015610a6a575060015b610a98576040517f3004b2d8ec75a545f6abc58879cd00cc4fb6c951131a7cf023a21fc01020e78690600090a15b50505050505b610aa86001600355565b5050505050565b610ab833611455565b610ad557604051637c3ea23f60e01b815260040160405180910390fd5b610ade8161151a565b50565b905090565b610aef33611455565b610b0c57604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b655736838383818110610b2a57610b2a612629565b9050604002019050610b528160000135826020016020810190610b4d91906125c2565b611573565b5080610b5d81612655565b915050610b0f565b505050565b610b7333611455565b610b9057604051637c3ea23f60e01b815260040160405180910390fd5b610ade816115d1565b610ba233611455565b610bbf57604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b65576000838383818110610bde57610bde612629565b905060200201359050610bf081611606565b5080610bfb81612655565b915050610bc2565b610c0c33611455565b610c2957604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b655736838383818110610c4757610c47612629565b604090810292909201925050813590600090610c6890840160208501612454565b9050468203610c9f576001600160a01b0381163014610c9a57604051631131ed9760e31b815260040160405180910390fd5b610ca9565b610ca98282611662565b5050508080610cb790612655565b915050610c2c565b610cc833611455565b610ce557604051637c3ea23f60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610d1857610d1433826116f7565b5050565b610d14823383611785565b610d2c33611455565b610d4957604051637c3ea23f60e01b815260040160405180910390fd5b610d51611877565b610d596118c0565b565b610d6433611455565b610d8157604051637c3ea23f60e01b815260040160405180910390fd5b610ade81611912565b6005546001600160a01b03163314610db55760405163424029e160e01b815260040160405180910390fd5b610dbd611947565b6000610dc88661198d565b6000878152600a602052604081205491925061ffff90911690819003610e015760405163d5a6cc2d60e01b815260040160405180910390fd5b600080610e0f86868b6119c3565b9150915080341015610e34576040516360b5c54960e01b815260040160405180910390fd5b600081118015610e4e5750600e546001600160a01b031615155b15610e6957600e54610e69906001600160a01b0316826116f7565b6009546001600160a01b031663c5803100610e84833461266e565b6040516bffffffffffffffffffffffff19606089811b8216602084015230901b166034820152869060480160408051601f19818403018152908290526005546001600160e01b031960e087901b168352610ef693928f918f916001600160a01b03909116906000908c906004016126d1565b6000604051808303818588803b158015610f0f57600080fd5b505af1158015610f23573d6000803e3d6000fd5b5050505050505050505050505050565b610f3b611a38565b610d596000611a98565b60078181548110610f5557600080fd5b600091825260209091200154905081565b610f6f33611455565b610f8c57604051637c3ea23f60e01b815260040160405180910390fd5b610f94611947565b610d59611af1565b610fa533611455565b610fc257604051637c3ea23f60e01b815260040160405180910390fd5b610fcb81611b2e565b600580546001600160a01b0319166001600160a01b0383169081179091556040517f764166c557b419ae9f4bca81c505141ce7017b4bdb4c610ad113a50ec7e578a990600090a250565b6000818152600d60205260408120805460ff1615611037576001015492915050565b5050600c54919050565b611049611a38565b6110626000805160206128228339815191528383611b61565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6000858152600a602052604081205461ffff1681806110be86868b6119c3565b60095460405163040a7bb160e41b81529294509092506000916001600160a01b03909116906340a7bb109061110190879030908e908e9088908b9060040161272c565b6040805180830381865afa15801561111d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111419190612782565b50905061114e82826127a6565b9a9950505050505050505050565b606060078054806020026020016040519081016040528092919081815260200182805480156111aa57602002820191906000526020600020905b815481526020019060010190808311611196575b5050505050905090565b6111bd33611455565b6111da57604051637c3ea23f60e01b815260040160405180910390fd5b610d148282611b8e565b6111ed33611455565b61120a57604051637c3ea23f60e01b815260040160405180910390fd5b611224600080516020612822833981519152336000611b61565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b61125a33611455565b61127757604051637c3ea23f60e01b815260040160405180910390fd5b610ade81611c01565b61128933611455565b6112a657604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610b655760008383838181106112c5576112c5612629565b9050602002013590504681146112de576112de81611c54565b50806112e981612655565b9150506112a9565b6060610ae1600080516020612822833981519152611cb3565b61131333611455565b61133057604051637c3ea23f60e01b815260040160405180910390fd5b610ade81611d1f565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611367575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156113ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113cf91906127b9565b92915050565b919050565b6113e2611a38565b6001600160a01b03811661144c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b610ade81611a98565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff166113cf565b6002600354036114e75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611443565b6002600355565b60008060005a905083811015925082611508576000611512565b611512848261266e565b915050915091565b6000818152600d6020526040808220805460ff1916815560010191909155517f7333f4fc2afbb7d9887b8beab88e2deb99cc44fe3405f0f174e50c53116b922f906115689083815260200190565b60405180910390a150565b6000828152600a60209081526040808320805461ffff191661ffff8616908117909155808452600b90925280832085905551909184917fe8b662b513ff40c8ca90e64deacc96541614246ae47724df4d670d6b3ba2e5d79190a35050565b600c8190556040518181527f4482bd706ea2970ea43d9096440f831b2d23a97cb2ac77bde31bf5efff14ee4290602001611568565b6000818152600a60209081526040808320805461ffff19811690915561ffff16808452600b909252808320839055519091829184917f487d90e6c0c486fcf4e9b12707215f206056b5371b667b782a65b559a001122b91a35050565b81600003611683576040516381e7376360e01b815260040160405180910390fd5b6001600160a01b0381166116aa57604051633efa09af60e01b815260040160405180910390fd5b6116bc60066007600885856064611d69565b506040516001600160a01b0382169083907f357d1ebd1dc0d53cc15161206b9a39c9ca30667bd997cf921eb00e4c78a454f590600090a35050565b604080516000808252602082019092526001600160a01b03841690839060405161172191906127d2565b60006040518083038185875af1925050503d806000811461175e576040519150601f19603f3d011682016040523d82523d6000602084013e611763565b606091505b5050905080610b6557604051632e05b05360e21b815260040160405180910390fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916117e191906127d2565b6000604051808303816000865af19150503d806000811461181e576040519150601f19603f3d011682016040523d82523d6000602084013e611823565b606091505b5091509150600082801561184f57508151158061184f57508180602001905181019061184f91906127ee565b90508061186f57604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b60005460ff16610d595760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401611443565b6118c8611877565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60048190556040518181527fec9e8f9ec7dd2c5310e5b87c7bedeb6ba1c5943cb4d2da1ee80335508a5bc5a490602001611568565b60005460ff1615610d595760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401611443565b6000818152600660205260408120546001600160a01b0316806113cf57604051631a81634560e01b815260040160405180910390fd5b60606000806119d48587018761255f565b9250905060006119e385611015565b905080821015611a0657604051637d6aa4df60e01b815260040160405180910390fd5b604051600160f01b60208201526022810183905260420160405160208183030381529060405293505050935093915050565b6000546001600160a01b03610100909104163314610d595760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611443565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b611af9611947565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586118f53390565b6001600160a01b0381163b610ade57604051638c50d7cd60e01b81526001600160a01b0382166004820152602401611443565b60008381526001602090815260408083206002909252909120611b88919084846064611dc5565b50505050565b604080518082018252600180825260208083018581526000878152600d83528590209351845460ff191690151517845551929091019190915581518481529081018390527f0bf9fc5793c10b41b09b96b32d3c1378d9156d4d0eec49a2fbe259c2605afdb0910160405180910390a15050565b611c0a81611b2e565b600980546001600160a01b0319166001600160a01b0383169081179091556040517fc8e81a4efc849969069ec6aae575cf7a6bc5f9d3abac59f4ed190a6f7e05fc6f90600090a250565b80600003611c75576040516381e7376360e01b815260040160405180910390fd5b611c8460066007600884611df2565b5060405181907feb39225b53386d0eb02af9cf2c6b6a0c345a97654f1e67fb21b0b5aaac81ec4a90600090a250565b600081815260016020908152604091829020805483518184028101840190945280845260609392830182828015611d1357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611cf5575b50505050509050919050565b600e80546001600160a01b0319166001600160a01b0383169081179091556040517f9113819388a87769f8958d74097d68f96e457d5bc25f0168a8ffb3d3a55672a390600090a250565b60008381526020859052604090205460ff16158015611d9057611d8e86868685611e3b565b505b600093845260209690965250604090912080546001600160a01b0319166001600160a01b039092169190911790555090919050565b600082611ddc57611dd7868686611ec4565b611de8565b611de886868685611fec565b9695505050505050565b60008181526020839052604090205460ff168015611e3357600082815260208690526040902080546001600160a01b0319169055611e3184848461209c565b505b949350505050565b60008281526020849052604090205460ff16158015611e335784548211611e755760405163b1655e3360e01b815260040160405180910390fd5b60408051808201825260018082528754602080840191825260008881529881529388209251835460ff191690151517835551918101919091558654908101875595855290932090930155919050565b6001600160a01b0381166000908152602083905260409020805460ff16908115611fe45760018082015486549091600091611eff919061266e565b9050808214611f8c576000878281548110611f1c57611f1c612629565b9060005260206000200160009054906101000a90046001600160a01b0316905080888481548110611f4f57611f4f612629565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b86805480611f9c57611f9c61280b565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015611e3357845482116120305760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b039790971660008181529888529388209251835460ff19169015151783555191810191909155865490810187559585529290932090930180546001600160a01b0319169091179055919050565b6000818152602083905260409020805460ff16908115611fe457600180820154865490916000916120cd919061266e565b905080821461212c5760008782815481106120ea576120ea612629565b906000526020600020015490508088848154811061210a5761210a612629565b6000918252602080832090910192909255918252879052604090206001018290555b8680548061213c5761213c61280b565b60008281526020808220830160001990810183905590920190925586825287905260408120805460ff19168155600101555050509392505050565b803561ffff811681146113d557600080fd5b634e487b7160e01b600052604160045260246000fd5b803567ffffffffffffffff811681146113d557600080fd5b60008083601f8401126121c957600080fd5b50813567ffffffffffffffff8111156121e157600080fd5b6020830191508360208285010111156121f957600080fd5b9250929050565b60008060008060006080868803121561221857600080fd5b61222186612177565b9450602086013567ffffffffffffffff8082111561223e57600080fd5b818801915088601f83011261225257600080fd5b81358181111561226457612264612189565b604051601f8201601f19908116603f0116810190838211818310171561228c5761228c612189565b816040528281528b60208487010111156122a557600080fd5b826020860160208301376000602084830101528098505050506122ca6040890161219f565b945060608801359150808211156122e057600080fd5b506122ed888289016121b7565b969995985093965092949392505050565b60006020828403121561231057600080fd5b5035919050565b60008083601f84011261232957600080fd5b50813567ffffffffffffffff81111561234157600080fd5b6020830191508360208260061b85010111156121f957600080fd5b6000806020838503121561236f57600080fd5b823567ffffffffffffffff81111561238657600080fd5b61239285828601612317565b90969095509350505050565b600080602083850312156123b157600080fd5b823567ffffffffffffffff808211156123c957600080fd5b818501915085601f8301126123dd57600080fd5b8135818111156123ec57600080fd5b8660208260051b850101111561240157600080fd5b60209290920196919550909350505050565b6001600160a01b0381168114610ade57600080fd5b6000806040838503121561243b57600080fd5b823561244681612413565b946020939093013593505050565b60006020828403121561246657600080fd5b813561247181612413565b9392505050565b60008060008060006060868803121561249057600080fd5b85359450602086013567ffffffffffffffff808211156124af57600080fd5b6124bb89838a016121b7565b909650945060408801359150808211156122e057600080fd5b8015158114610ade57600080fd5b600080604083850312156124f557600080fd5b823561250081612413565b91506020830135612510816124d4565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561255357835183529284019291840191600101612537565b50909695505050505050565b6000806040838503121561257257600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b818110156125535783516001600160a01b03168352928401929184019160010161259d565b6000602082840312156125d457600080fd5b61247182612177565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8381526040602082015260006126206040830184866125dd565b95945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016126675761266761263f565b5060010190565b818103818111156113cf576113cf61263f565b60005b8381101561269c578181015183820152602001612684565b50506000910152565b600081518084526126bd816020860160208601612681565b601f01601f19169290920160200192915050565b61ffff8816815260c0602082015260006126ee60c08301896126a5565b828103604084015261270181888a6125dd565b6001600160a01b0387811660608601528616608085015283810360a0850152905061114e81856126a5565b61ffff871681526001600160a01b038616602082015260a06040820181905260009061275b90830186886125dd565b8415156060840152828103608084015261277581856126a5565b9998505050505050505050565b6000806040838503121561279557600080fd5b505080516020909101519092909150565b808201808211156113cf576113cf61263f565b6000602082840312156127cb57600080fd5b5051919050565b600082516127e4818460208701612681565b9190910192915050565b60006020828403121561280057600080fd5b8151612471816124d4565b634e487b7160e01b600052603160045260246000fdfe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa2646970667358221220977d7da2c021523b35a532faedc5277896234f7d5500bcd36c8943712b23580164736f6c63430008130033

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

00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000249f000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000ed648d84268502b512e175d7d4873bfe685db8aa00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006500000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000066000000000000000000000000000000000000000000000000000000000000a86a000000000000000000000000000000000000000000000000000000000000006a00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000089000000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000a4b1000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000000a5000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001440000000000000000000000000000000000000000000000000000000000124f8000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005e0fde554be338e3682b7c3f724ade791d3e80ca

-----Decoded View---------------
Arg [0] : _endpointAddress (address): 0x66A71Dcef29A0fFBDBE3c6a460a3B5BC225Cd675
Arg [1] : _chainIdPairs (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : _minTargetGasDefault (uint256): 150000
Arg [3] : _minTargetGasCustomData (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [4] : _targetGasReserve (uint256): 10000
Arg [5] : _processingFeeCollector (address): 0xed648d84268502B512e175D7d4873bFE685Db8AA
Arg [6] : _owner (address): 0x72E28c7F34100AfefC399fcc0AE041B8fe5841AE
Arg [7] : _managers (address[]): 0x5E0fde554BE338E3682B7C3F724aDe791D3E80ca
Arg [8] : _addOwnerToManagers (bool): True

-----Encoded View---------------
29 Constructor Arguments found :
Arg [0] : 00000000000000000000000066a71dcef29a0ffbdbe3c6a460a3b5bc225cd675
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 00000000000000000000000000000000000000000000000000000000000249f0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000300
Arg [4] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [5] : 000000000000000000000000ed648d84268502b512e175d7d4873bfe685db8aa
Arg [6] : 00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000360
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000065
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000038
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000066
Arg [14] : 000000000000000000000000000000000000000000000000000000000000a86a
Arg [15] : 000000000000000000000000000000000000000000000000000000000000006a
Arg [16] : 00000000000000000000000000000000000000000000000000000000000000fa
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000070
Arg [18] : 0000000000000000000000000000000000000000000000000000000000000089
Arg [19] : 000000000000000000000000000000000000000000000000000000000000006d
Arg [20] : 000000000000000000000000000000000000000000000000000000000000a4b1
Arg [21] : 000000000000000000000000000000000000000000000000000000000000006e
Arg [22] : 0000000000000000000000000000000000000000000000000000000000000144
Arg [23] : 00000000000000000000000000000000000000000000000000000000000000a5
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [25] : 0000000000000000000000000000000000000000000000000000000000000144
Arg [26] : 0000000000000000000000000000000000000000000000000000000000124f80
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [28] : 0000000000000000000000005e0fde554be338e3682b7c3f724ade791d3e80ca


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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