ETH Price: $2,915.45 (-10.04%)
Gas: 15 Gwei

Contract

0x7C888C0cAC0886a4FF6D1A4d26f93BFD9698d618
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Transaction Hash
Method
Block
From
To
Value
Execute Target202352022024-07-04 19:22:118 hrs ago1720120931IN
0x7C888C0c...D9698d618
0 ETH0.002441088.03615507
Execute Target202350332024-07-04 18:47:479 hrs ago1720118867IN
0x7C888C0c...D9698d618
0 ETH0.00237847.82849955
Execute Target202344762024-07-04 16:55:2311 hrs ago1720112123IN
0x7C888C0c...D9698d618
0 ETH0.0032260410.61968545
Execute Target202113842024-07-01 11:30:593 days ago1719833459IN
0x7C888C0c...D9698d618
0 ETH0.001738486.06444994
Execute Target202053522024-06-30 15:19:114 days ago1719760751IN
0x7C888C0c...D9698d618
0 ETH0.001327754.37156423
Execute Target201771272024-06-26 16:42:358 days ago1719420155IN
0x7C888C0c...D9698d618
0 ETH0.0030542210.65511129
Execute Target201708222024-06-25 19:35:359 days ago1719344135IN
0x7C888C0c...D9698d618
0 ETH0.002125596.99714283
Execute Target201583552024-06-24 1:46:1111 days ago1719193571IN
0x7C888C0c...D9698d618
0 ETH0.000796312.77795281
Execute Target201578462024-06-24 0:04:1111 days ago1719187451IN
0x7C888C0c...D9698d618
0 ETH0.00087713.0595936
Execute Target201175352024-06-18 8:43:3516 days ago1718700215IN
0x7C888C0c...D9698d618
0 ETH0.001916356.30901421
Execute Target200999582024-06-15 21:45:1119 days ago1718487911IN
0x7C888C0c...D9698d618
0 ETH0.001346544.43214291
Execute Target200720432024-06-12 0:02:5923 days ago1718150579IN
0x7C888C0c...D9698d618
0 ETH0.002529778.32962922
Execute Target200152692024-06-04 1:47:2331 days ago1717465643IN
0x7C888C0c...D9698d618
0 ETH0.002221087.31237016
Execute Target199732312024-05-29 4:47:4736 days ago1716958067IN
0x7C888C0c...D9698d618
0 ETH0.0031552210.38834479
Execute Target199545192024-05-26 14:03:1139 days ago1716732191IN
0x7C888C0c...D9698d618
0 ETH0.00280459.23364346
Execute Target199540482024-05-26 12:27:1139 days ago1716726431IN
0x7C888C0c...D9698d618
0 ETH0.001823576.00364585
Execute Target199214892024-05-21 23:13:1144 days ago1716333191IN
0x7C888C0c...D9698d618
0 ETH0.002155427.09772237
Execute Target198949832024-05-18 6:15:2347 days ago1716012923IN
0x7C888C0c...D9698d618
0 ETH0.001187773.9112795
Execute Target198623592024-05-13 16:42:1152 days ago1715618531IN
0x7C888C0c...D9698d618
0 ETH0.0065572321.58425939
Execute Target198596872024-05-13 7:45:1152 days ago1715586311IN
0x7C888C0c...D9698d618
0 ETH0.001765695.81321312
Execute Target198585822024-05-13 4:02:3553 days ago1715572955IN
0x7C888C0c...D9698d618
0 ETH0.001288244.24048515
Execute Target198408862024-05-10 16:39:5955 days ago1715359199IN
0x7C888C0c...D9698d618
0 ETH0.002451218.06987832
Execute Target198072232024-05-05 23:38:3560 days ago1714952315IN
0x7C888C0c...D9698d618
0 ETH0.001612285.62511741
Execute Target197758472024-05-01 14:22:3564 days ago1714573355IN
0x7C888C0c...D9698d618
0 ETH0.0039950913.15179239
Execute Target197710782024-04-30 22:23:1165 days ago1714515791IN
0x7C888C0c...D9698d618
0 ETH0.002414567.94946019
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
201635652024-06-24 19:15:2310 days ago1719256523
0x7C888C0c...D9698d618
0.0045369 ETH
201635652024-06-24 19:15:2310 days ago1719256523
0x7C888C0c...D9698d618
0.0045369 ETH
201325662024-06-20 11:13:1114 days ago1718881991
0x7C888C0c...D9698d618
0.00365469 ETH
201325662024-06-20 11:13:1114 days ago1718881991
0x7C888C0c...D9698d618
0.00365469 ETH
201318652024-06-20 8:52:1114 days ago1718873531
0x7C888C0c...D9698d618
0.00419949 ETH
201318652024-06-20 8:52:1114 days ago1718873531
0x7C888C0c...D9698d618
0.00419949 ETH
200705022024-06-11 18:53:1123 days ago1718131991
0x7C888C0c...D9698d618
0.00023323 ETH
200705022024-06-11 18:53:1123 days ago1718131991
0x7C888C0c...D9698d618
0.00023323 ETH
200567642024-06-09 20:50:3525 days ago1717966235
0x7C888C0c...D9698d618
0.00013832 ETH
200567642024-06-09 20:50:3525 days ago1717966235
0x7C888C0c...D9698d618
0.00013832 ETH
200122732024-06-03 15:44:5931 days ago1717429499
0x7C888C0c...D9698d618
0.0031885 ETH
200122732024-06-03 15:44:5931 days ago1717429499
0x7C888C0c...D9698d618
0.0031885 ETH
200118922024-06-03 14:28:4731 days ago1717424927
0x7C888C0c...D9698d618
0.00395427 ETH
200118922024-06-03 14:28:4731 days ago1717424927
0x7C888C0c...D9698d618
0.00395427 ETH
197690782024-04-30 15:39:5965 days ago1714491599
0x7C888C0c...D9698d618
0.00010954 ETH
197690782024-04-30 15:39:5965 days ago1714491599
0x7C888C0c...D9698d618
0.00010954 ETH
194649242024-03-18 23:25:23108 days ago1710804323
0x7C888C0c...D9698d618
0.00056786 ETH
194649242024-03-18 23:25:23108 days ago1710804323
0x7C888C0c...D9698d618
0.00056786 ETH
193234122024-02-28 3:39:59128 days ago1709091599
0x7C888C0c...D9698d618
0.00042869 ETH
193234122024-02-28 3:39:59128 days ago1709091599
0x7C888C0c...D9698d618
0.00042869 ETH
191548712024-02-04 12:12:23151 days ago1707048743
0x7C888C0c...D9698d618
0.00015635 ETH
191548712024-02-04 12:12:23151 days ago1707048743
0x7C888C0c...D9698d618
0.00015635 ETH
191297592024-01-31 23:33:47155 days ago1706744027
0x7C888C0c...D9698d618
0.0000399 ETH
191297592024-01-31 23:33:47155 days ago1706744027
0x7C888C0c...D9698d618
0.0000399 ETH
189699552024-01-09 14:18:59177 days ago1704809939
0x7C888C0c...D9698d618
0.00015712 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CircleCctpGateway

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

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

pragma solidity 0.8.19;

import { IActionDataStructures } from '../../interfaces/IActionDataStructures.sol';
import { IMessageHandler } from './interfaces/IMessageHandler.sol';
import { IMessageTransmitter } from './interfaces/IMessageTransmitter.sol';
import { ITokenBalance } from '../../interfaces/ITokenBalance.sol';
import { ITokenMessenger } from './interfaces/ITokenMessenger.sol';
import { IVault } from '../../interfaces/IVault.sol';
import { AssetSpenderRole } from '../../roles/AssetSpenderRole.sol';
import { CallerGuard } from '../../CallerGuard.sol';
import { GatewayBase } from '../GatewayBase.sol';
import { SystemVersionId } from '../../SystemVersionId.sol';
import '../../helpers/GasReserveHelper.sol' as GasReserveHelper;
import '../../helpers/TransferHelper.sol' as TransferHelper;
import '../../DataStructures.sol' as DataStructures;

/**
 * @title CircleCctpGateway
 * @notice The contract implementing the cross-chain messaging logic specific to Circle CCTP
 */
contract CircleCctpGateway is
    SystemVersionId,
    GatewayBase,
    CallerGuard,
    AssetSpenderRole,
    IActionDataStructures,
    IVault,
    IMessageHandler
{
    /**
     * @notice Chain domain structure
     * @dev See https://developers.circle.com/stablecoin/docs/cctp-technical-reference#domain
     * @param chainId The EVM chain ID
     * @param domain The CCTP domain
     */
    struct ChainDomain {
        uint256 chainId;
        uint32 domain;
    }

    /**
     * @notice Variables for the sendMessage function
     * @param peerAddressBytes32 The peer address as bytes32
     * @param targetDomain The target domain
     * @param assetMessageNonce The asset message nonce
     * @param dataMessageNonce The data message nonce
     */
    struct SendMessageVariables {
        bytes32 peerAddressBytes32;
        uint32 targetDomain;
        uint64 assetMessageNonce;
        uint64 dataMessageNonce;
        bool useTargetExecutor;
    }

    /**
     * @notice CCTP message handler context structure
     * @param caller The address of the caller
     * @param assetReceived The received amount of the CCTP asset
     */
    struct MessageHandlerContext {
        address caller;
        uint256 assetReceived;
    }

    /**
     * @dev cctpTokenMessenger The CCTP token messenger address
     */
    ITokenMessenger public immutable cctpTokenMessenger;

    /**
     * @dev cctpMessageTransmitter The CCTP message transmitter address
     */
    IMessageTransmitter public immutable cctpMessageTransmitter;

    /**
     * @dev asset The USDC token address
     */
    address public immutable asset;

    /**
     * @dev Chain id to CCTP domain
     */
    mapping(uint256 /*chainId*/ => DataStructures.OptionalValue /*domain*/) public chainIdToDomain;

    /**
     * @dev CCTP domain to chain id
     */
    mapping(uint32 /*domain*/ => uint256 /*chainId*/) public domainToChainId;

    /**
     * @dev The state of variable token and balance actions
     */
    bool public variableRepaymentEnabled;

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

    /**
     * @dev The address of the target executor
     */
    address public targetExecutor;

    MessageHandlerContext private messageHandlerContext;

    /**
     * @notice Emitted when a chain ID and CCTP domain pair is added or updated
     * @param chainId The chain ID
     * @param domain The CCTP domain
     */
    event SetChainDomain(uint256 indexed chainId, uint32 indexed domain);

    /**
     * @notice Emitted when a chain ID and CCTP domain pair is removed
     * @param chainId The chain ID
     * @param domain The CCTP domain
     */
    event RemoveChainDomain(uint256 indexed chainId, uint32 indexed domain);

    /**
     * @notice Emitted when the state of variable token and balance actions is updated
     * @param variableRepaymentEnabled The state of variable token and balance actions
     */
    event SetVariableRepaymentEnabled(bool indexed variableRepaymentEnabled);

    /**
     * @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 the address of the target executor is set
     * @param targetExecutor The address of the target executor
     */
    event SetTargetExecutor(address indexed targetExecutor);

    /**
     * @notice Emitted when the call to the CCTP receiveMessage fails
     * @param sourceChainId The ID of the message source chain
     */
    event TargetCctpMessageFailure(uint256 indexed sourceChainId);

    /**
     * @notice Emitted when a gateway action is performed on the source chain
     * @param actionId The ID of the action
     * @param targetChainId The ID of the target chain
     * @param useTargetExecutor The flag to use the target executor
     * @param assetMessageNonce The nonce of the CCTP asset message
     * @param dataMessageNonce The nonce of the CCTP data message
     * @param assetAmount The amount of the asset used for the action
     * @param processingFee The amount of the processing fee
     * @param processingGas The amount of the processing gas
     * @param timestamp The timestamp of the action (in seconds)
     */
    event GatewayActionSource(
        uint256 indexed actionId,
        uint256 indexed targetChainId,
        bool indexed useTargetExecutor,
        uint64 assetMessageNonce,
        uint64 dataMessageNonce,
        uint256 assetAmount,
        uint256 processingFee,
        uint256 processingGas,
        uint256 timestamp
    );

    /**
     * @notice Emitted when the domain for the specified chain is not set
     */
    error DomainNotSetError();

    /**
     * @notice Emitted when the caller is not an allowed executor
     */
    error ExecutorError();

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

    /**
     * @notice Emitted when a variable token or balance action is not allowed
     */
    error VariableRepaymentNotEnabledError();

    /**
     * @notice Emitted when a variable token action is attempted while the token address is not set
     */
    error VariableTokenNotSetError();

    /**
     * @notice Emitted when the context vault is not the current contract
     */
    error OnlyCurrentVaultError();

    /**
     * @notice Emitted when the caller is not the CCTP message transmitter
     */
    error OnlyMessageTransmitterError();

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

    /**
     * @notice Emitted when the asset message receiving fails
     */
    error AssetMessageError();

    /**
     * @notice Emitted when the data message receiving fails
     */
    error DataMessageError();

    /**
     * @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 fromAddress The address of the message source
     */
    error TargetFromAddressError(uint256 sourceChainId, address fromAddress);

    /**
     * @notice Emitted when the caller is not allowed to perform the action on the target chain
     */
    error TargetCallerError();

    /**
     * @notice Emitted when the swap amount does not match the received asset amount
     */
    error TargetAssetAmountMismatchError();

    /**
     * @notice Emitted when the gas reserve on the target chain does not allow further action processing
     */
    error TargetGasReserveError();

    /**
     * @dev Modifier to check if the caller is the CCTP message transmitter
     */
    modifier onlyMessageTransmitter() {
        if (msg.sender != address(cctpMessageTransmitter)) {
            revert OnlyMessageTransmitterError();
        }

        _;
    }

    /**
     * @notice Deploys the CircleCctpGateway contract
     * @param _cctpTokenMessenger The CCTP token messenger address
     * @param _cctpMessageTransmitter The CCTP message transmitter address
     * @param _chainDomains The list of registered chain domains
     * @param _asset The USDC token address
     * @param _variableRepaymentEnabled The state of variable token and balance actions
     * @param _targetGasReserve The initial gas reserve value for target chain action processing
     * @param _processingFeeCollector The initial address of the processing fee collector
     * @param _targetExecutor The address of the target executor
     * @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(
        ITokenMessenger _cctpTokenMessenger,
        IMessageTransmitter _cctpMessageTransmitter,
        ChainDomain[] memory _chainDomains,
        address _asset,
        bool _variableRepaymentEnabled,
        uint256 _targetGasReserve,
        address _processingFeeCollector,
        address _targetExecutor,
        address _owner,
        address[] memory _managers,
        bool _addOwnerToManagers
    ) {
        cctpTokenMessenger = _cctpTokenMessenger;
        cctpMessageTransmitter = _cctpMessageTransmitter;

        for (uint256 index; index < _chainDomains.length; index++) {
            ChainDomain memory chainDomain = _chainDomains[index];

            _setChainDomain(chainDomain.chainId, chainDomain.domain);
        }

        asset = _asset;

        _setVariableRepaymentEnabled(_variableRepaymentEnabled);

        _setTargetGasReserve(_targetGasReserve);

        _setProcessingFeeCollector(_processingFeeCollector);
        _setTargetExecutor(_targetExecutor);

        _initRoles(_owner, _managers, _addOwnerToManagers);
    }

    /**
     * @notice The standard "receive" function
     * @dev Is payable to allow receiving native token funds from the cross-chain endpoint
     */
    receive() external payable {}

    /**
     * @notice Updates the Asset Spender role status for the account
     * @param _account The account address
     * @param _value The Asset Spender role status flag
     */
    function setAssetSpender(address _account, bool _value) external onlyManager {
        _setAssetSpender(_account, _value);
    }

    /**
     * @notice Adds or updates registered chain domains (CCTP-specific)
     * @param _chainDomains The list of registered chain domains
     */
    function setChainDomains(ChainDomain[] calldata _chainDomains) external onlyManager {
        for (uint256 index; index < _chainDomains.length; index++) {
            ChainDomain calldata chainDomain = _chainDomains[index];

            _setChainDomain(chainDomain.chainId, chainDomain.domain);
        }
    }

    /**
     * @notice Removes registered chain domains (CCTP-specific)
     * @param _chainIds The list of EVM chain IDs
     */
    function removeChainDomains(uint256[] calldata _chainIds) external onlyManager {
        for (uint256 index; index < _chainIds.length; index++) {
            uint256 chainId = _chainIds[index];

            _removeChainDomain(chainId);
        }
    }

    /**
     * @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 Sets the address of the target executor
     * @param _targetExecutor The address of the target executor
     */
    function setTargetExecutor(address _targetExecutor) external onlyManager {
        _setTargetExecutor(_targetExecutor);
    }

    /**
     * @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 onlyClient whenNotPaused {
        (IVault vault, uint256 assetAmount) = client.getSourceGatewayContext();

        if (address(vault) != address(this)) {
            revert OnlyCurrentVaultError();
        }

        SendMessageVariables memory variables = _prepareSendMessageVariables();

        variables.peerAddressBytes32 = _addressToBytes32(_checkPeerAddress(_targetChainId));
        variables.targetDomain = _checkTargetDomain(_targetChainId);

        uint256 processingFee;
        uint256 processingGas;
        (variables.useTargetExecutor, processingFee, processingGas) = _decodeSettings(_settings);

        // - - - Processing fee transfer - - -

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

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

        // - - -

        TargetMessage memory targetMessage = abi.decode(_message, (TargetMessage));

        // - - - CCTP - Burn USDC on the source chain - - -

        TransferHelper.safeApprove(asset, address(cctpTokenMessenger), assetAmount);

        variables.assetMessageNonce = cctpTokenMessenger.depositForBurnWithCaller(
            assetAmount,
            variables.targetDomain,
            variables.peerAddressBytes32, // _mintRecipient
            asset,
            variables.peerAddressBytes32 // _destinationCaller
        );

        TransferHelper.safeApprove(asset, address(cctpTokenMessenger), 0);

        // - - -

        // - - - CCTP - Send the message - - -

        variables.dataMessageNonce = cctpMessageTransmitter.sendMessageWithCaller(
            variables.targetDomain,
            variables.peerAddressBytes32, // recipient
            variables.peerAddressBytes32, // destinationCaller
            _message
        );

        // - - -

        emit GatewayActionSource(
            targetMessage.actionId,
            _targetChainId,
            variables.useTargetExecutor,
            variables.assetMessageNonce,
            variables.dataMessageNonce,
            assetAmount,
            processingFee,
            processingGas,
            block.timestamp
        );
    }

    /**
     * @notice Executes the target actions
     * @param _assetMessage The CCTP asset message
     * @param _assetAttestation The CCTP asset message attestation
     * @param _dataMessage The CCTP data message
     * @param _dataAttestation The CCTP data message attestation
     */
    function executeTarget(
        bytes calldata _assetMessage,
        bytes calldata _assetAttestation,
        bytes calldata _dataMessage,
        bytes calldata _dataAttestation
    ) external whenNotPaused nonReentrant checkCaller {
        if (address(client) == address(0)) {
            revert TargetClientNotSetError();
        }

        uint256 assetBalanceBefore = tokenBalance(asset);

        bool assetMessageSuccess = cctpMessageTransmitter.receiveMessage(
            _assetMessage,
            _assetAttestation
        );

        if (!assetMessageSuccess) {
            revert AssetMessageError();
        }

        messageHandlerContext = MessageHandlerContext({
            caller: msg.sender,
            assetReceived: tokenBalance(asset) - assetBalanceBefore
        });

        bool dataMessageSuccess = cctpMessageTransmitter.receiveMessage(
            _dataMessage,
            _dataAttestation
        );

        if (!dataMessageSuccess) {
            revert DataMessageError();
        }

        delete messageHandlerContext;
    }

    /**
     * @notice handles an incoming message from a Receiver
     * @dev IMessageHandler interface
     * @param _sourceDomain The source domain of the message
     * @param _sender The sender of the message
     * @param _messageBody The message raw bytes
     * @return success bool, true if successful
     */
    function handleReceiveMessage(
        uint32 _sourceDomain,
        bytes32 _sender,
        bytes calldata _messageBody
    ) external whenNotPaused onlyMessageTransmitter returns (bool) {
        uint256 sourceChainId = domainToChainId[_sourceDomain];
        address fromAddress = _bytes32ToAddress(_sender);

        {
            bool fromAddressCondition = sourceChainId != 0 &&
                fromAddress != address(0) &&
                fromAddress == peerMap[sourceChainId];

            if (!fromAddressCondition) {
                revert TargetFromAddressError(sourceChainId, fromAddress);
            }
        }

        TargetMessage memory targetMessage = abi.decode(_messageBody, (TargetMessage));

        {
            address caller = messageHandlerContext.caller;

            bool targetCallerCondition = caller == targetExecutor ||
                caller == targetMessage.sourceSender ||
                caller == targetMessage.targetRecipient;

            if (!targetCallerCondition) {
                revert TargetCallerError();
            }
        }

        if (targetMessage.targetSwapInfo.fromAmount != messageHandlerContext.assetReceived) {
            revert TargetAssetAmountMismatchError();
        }

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

        if (!hasGasReserve) {
            revert TargetGasReserveError();
        }

        client.handleExecutionPayload{ gas: gasAllowed }(sourceChainId, _messageBody);

        return true;
    }

    /**
     * @notice Receives the asset tokens from CCTP and transfers them to the specified account
     * @param _assetMessage The CCTP asset message
     * @param _assetAttestation The CCTP asset attestation
     * @param _to The address of the asset tokens receiver
     */
    function extractCctpAsset(
        bytes calldata _assetMessage,
        bytes calldata _assetAttestation,
        address _to
    ) external onlyManager {
        uint256 tokenBalanceBefore = ITokenBalance(asset).balanceOf(address(this));

        cctpMessageTransmitter.receiveMessage(_assetMessage, _assetAttestation);

        uint256 tokenAmount = ITokenBalance(asset).balanceOf(address(this)) - tokenBalanceBefore;

        if (tokenAmount > 0 && _to != address(this)) {
            TransferHelper.safeTransfer(asset, _to, tokenAmount);
        }
    }

    /**
     * @notice Requests the vault asset tokens
     * @param _amount The amount of the vault asset tokens
     * @param _to The address of the vault asset tokens receiver
     * @param _forVariableBalance True if the request is made for a variable balance repayment, otherwise false
     * @return assetAddress The address of the vault asset token
     */
    function requestAsset(
        uint256 _amount,
        address _to,
        bool _forVariableBalance
    ) external whenNotPaused onlyAssetSpender returns (address assetAddress) {
        if (_forVariableBalance && !variableRepaymentEnabled) {
            revert VariableRepaymentNotEnabledError();
        }

        TransferHelper.safeTransfer(asset, _to, _amount);

        return asset;
    }

    /**
     * @notice Cross-chain message fee estimation
     * @param _settings The gateway-specific settings
     */
    function messageFee(
        uint256 /*_targetChainId*/,
        bytes calldata /*_message*/,
        bytes calldata _settings
    ) external pure returns (uint256) {
        (, uint256 processingFee, ) = _decodeSettings(_settings);

        return processingFee;
    }

    /**
     * @notice Checks the status of the variable token and balance actions and the variable token address
     * @return The address of the variable token
     */
    function checkVariableTokenState() external view returns (address) {
        if (!variableRepaymentEnabled) {
            revert VariableRepaymentNotEnabledError();
        }

        revert VariableTokenNotSetError();
    }

    function _setChainDomain(uint256 _chainId, uint32 _domain) private {
        DataStructures.OptionalValue storage previousDomainEntry = chainIdToDomain[_chainId];

        if (previousDomainEntry.isSet) {
            delete domainToChainId[uint32(previousDomainEntry.value)];
        }

        chainIdToDomain[_chainId] = DataStructures.OptionalValue({ isSet: true, value: _domain });
        domainToChainId[_domain] = _chainId;

        emit SetChainDomain(_chainId, _domain);
    }

    function _removeChainDomain(uint256 _chainId) private {
        DataStructures.OptionalValue storage domainEntry = chainIdToDomain[_chainId];

        uint32 domain;

        if (domainEntry.isSet) {
            domain = uint32(domainEntry.value);

            delete domainToChainId[uint32(domainEntry.value)];
        }

        delete chainIdToDomain[_chainId];

        emit RemoveChainDomain(_chainId, domain);
    }

    function _setVariableRepaymentEnabled(bool _variableRepaymentEnabled) private {
        variableRepaymentEnabled = _variableRepaymentEnabled;

        emit SetVariableRepaymentEnabled(_variableRepaymentEnabled);
    }

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

        emit SetProcessingFeeCollector(_processingFeeCollector);
    }

    function _setTargetExecutor(address _targetExecutor) private {
        targetExecutor = _targetExecutor;

        emit SetTargetExecutor(_targetExecutor);
    }

    function _checkTargetDomain(uint256 _targetChainId) private view returns (uint32) {
        DataStructures.OptionalValue storage domainEntry = chainIdToDomain[_targetChainId];

        if (!domainEntry.isSet) {
            revert DomainNotSetError();
        }

        return uint32(domainEntry.value);
    }

    function _prepareSendMessageVariables() private pure returns (SendMessageVariables memory) {
        return
            SendMessageVariables({
                peerAddressBytes32: bytes32(0),
                targetDomain: 0,
                assetMessageNonce: 0,
                dataMessageNonce: 0,
                useTargetExecutor: false
            });
    }

    function _decodeSettings(
        bytes calldata _settings
    ) private pure returns (bool useTargetExecutor, uint256 processingFee, uint256 processingGas) {
        return abi.decode(_settings, (bool, uint256, uint256));
    }

    function _addressToBytes32(address _address) private pure returns (bytes32) {
        return bytes32(uint256(uint160(_address)));
    }

    function _bytes32ToAddress(bytes32 _buffer) private pure returns (address) {
        return address(uint160(uint256(_buffer)));
    }
}

File 2 of 30 : 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 30 : 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 30 : 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 30 : 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 30 : 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 30 : CallerGuard.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './Constants.sol' as Constants;
import './DataStructures.sol' as DataStructures;

/**
 * @title CallerGuard
 * @notice Base contract to control access from other contracts
 */
abstract contract CallerGuard is ManagerRole {
    /**
     * @dev Caller guard mode enumeration
     */
    enum CallerGuardMode {
        ContractForbidden,
        ContractList,
        ContractAllowed
    }

    /**
     * @dev Caller guard mode value
     */
    CallerGuardMode public callerGuardMode = CallerGuardMode.ContractForbidden;

    /**
     * @dev Registered contract list for "ContractList" mode
     */
    address[] public listedCallerGuardContractList;

    /**
     * @dev Registered contract list indices for "ContractList" mode
     */
    mapping(address /*account*/ => DataStructures.OptionalValue /*index*/)
        public listedCallerGuardContractIndexMap;

    /**
     * @notice Emitted when the caller guard mode is set
     * @param callerGuardMode The caller guard mode
     */
    event SetCallerGuardMode(CallerGuardMode indexed callerGuardMode);

    /**
     * @notice Emitted when a registered contract for "ContractList" mode is added or removed
     * @param contractAddress The contract address
     * @param isListed The registered contract list inclusion flag
     */
    event SetListedCallerGuardContract(address indexed contractAddress, bool indexed isListed);

    /**
     * @notice Emitted when the caller is not allowed to perform the intended action
     */
    error CallerGuardError(address caller);

    /**
     * @dev Modifier to check if the caller is allowed to perform the intended action
     */
    modifier checkCaller() {
        if (msg.sender != tx.origin) {
            bool condition = (callerGuardMode == CallerGuardMode.ContractAllowed ||
                (callerGuardMode == CallerGuardMode.ContractList &&
                    isListedCallerGuardContract(msg.sender)));

            if (!condition) {
                revert CallerGuardError(msg.sender);
            }
        }

        _;
    }

    /**
     * @notice Sets the caller guard mode
     * @param _callerGuardMode The caller guard mode
     */
    function setCallerGuardMode(CallerGuardMode _callerGuardMode) external onlyManager {
        callerGuardMode = _callerGuardMode;

        emit SetCallerGuardMode(_callerGuardMode);
    }

    /**
     * @notice Updates the list of registered contracts for the "ContractList" mode
     * @param _items The addresses and flags for the contracts
     */
    function setListedCallerGuardContracts(
        DataStructures.AccountToFlag[] calldata _items
    ) external onlyManager {
        for (uint256 index; index < _items.length; index++) {
            DataStructures.AccountToFlag calldata item = _items[index];

            if (item.flag) {
                AddressHelper.requireContract(item.account);
            }

            DataStructures.uniqueAddressListUpdate(
                listedCallerGuardContractList,
                listedCallerGuardContractIndexMap,
                item.account,
                item.flag,
                Constants.LIST_SIZE_LIMIT_DEFAULT
            );

            emit SetListedCallerGuardContract(item.account, item.flag);
        }
    }

    /**
     * @notice Getter of the registered contract count
     * @return The registered contract count
     */
    function listedCallerGuardContractCount() external view returns (uint256) {
        return listedCallerGuardContractList.length;
    }

    /**
     * @notice Getter of the complete list of registered contracts
     * @return The complete list of registered contracts
     */
    function fullListedCallerGuardContractList() external view returns (address[] memory) {
        return listedCallerGuardContractList;
    }

    /**
     * @notice Getter of a listed contract flag
     * @param _account The contract address
     * @return The listed contract flag
     */
    function isListedCallerGuardContract(address _account) public view returns (bool) {
        return listedCallerGuardContractIndexMap[_account].isSet;
    }
}

File 8 of 30 : 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 9 of 30 : IMessageHandler.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright (c) 2022, Circle Internet Financial Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
pragma solidity 0.8.19;

/**
 * @title IMessageHandler
 * @notice Handles messages on destination domain forwarded from
 * an IReceiver
 */
interface IMessageHandler {
    /**
     * @notice handles an incoming message from a Receiver
     * @param _sourceDomain the source domain of the message
     * @param _sender the sender of the message
     * @param _messageBody The message raw bytes
     * @return success bool, true if successful
     */
    function handleReceiveMessage(
        uint32 _sourceDomain,
        bytes32 _sender,
        bytes calldata _messageBody
    ) external returns (bool);
}

File 10 of 30 : IMessageTransmitter.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright (c) 2022, Circle Internet Financial Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
pragma solidity 0.8.19;

import './IRelayer.sol';
import './IReceiver.sol';

/**
 * @title IMessageTransmitter
 * @notice Interface for message transmitters, which both relay and receive messages.
 */
interface IMessageTransmitter is IRelayer, IReceiver {

}

File 11 of 30 : IReceiver.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright (c) 2022, Circle Internet Financial Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
pragma solidity 0.8.19;

/**
 * @title IReceiver
 * @notice Receives messages on destination chain and forwards them to IMessageDestinationHandler
 */
interface IReceiver {
    /**
     * @notice Receives an incoming message, validating the header and passing
     * the body to application-specific handler.
     * @param message The message raw bytes
     * @param signature The message signature
     * @return success bool, true if successful
     */
    function receiveMessage(
        bytes calldata message,
        bytes calldata signature
    ) external returns (bool success);
}

File 12 of 30 : IRelayer.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright (c) 2022, Circle Internet Financial Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
pragma solidity 0.8.19;

/**
 * @title IRelayer
 * @notice Sends messages from source domain to destination domain
 */
interface IRelayer {
    /**
     * @notice Sends an outgoing message from the source domain.
     * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.
     * @param destinationDomain Domain of destination chain
     * @param recipient Address of message recipient on destination domain as bytes32
     * @param messageBody Raw bytes content of message
     * @return nonce reserved by message
     */
    function sendMessage(
        uint32 destinationDomain,
        bytes32 recipient,
        bytes calldata messageBody
    ) external returns (uint64);

    /**
     * @notice Sends an outgoing message from the source domain, with a specified caller on the
     * destination domain.
     * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.
     * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible
     * to broadcast the message on the destination domain. This is an advanced feature, and the standard
     * sendMessage() should be preferred for use cases where a specific destination caller is not required.
     * @param destinationDomain Domain of destination chain
     * @param recipient Address of message recipient on destination domain as bytes32
     * @param destinationCaller caller on the destination domain, as bytes32
     * @param messageBody Raw bytes content of message
     * @return nonce reserved by message
     */
    function sendMessageWithCaller(
        uint32 destinationDomain,
        bytes32 recipient,
        bytes32 destinationCaller,
        bytes calldata messageBody
    ) external returns (uint64);

    /**
     * @notice Replace a message with a new message body and/or destination caller.
     * @dev The `originalAttestation` must be a valid attestation of `originalMessage`.
     * @param originalMessage original message to replace
     * @param originalAttestation attestation of `originalMessage`
     * @param newMessageBody new message body of replaced message
     * @param newDestinationCaller the new destination caller
     */
    function replaceMessage(
        bytes calldata originalMessage,
        bytes calldata originalAttestation,
        bytes calldata newMessageBody,
        bytes32 newDestinationCaller
    ) external;
}

File 13 of 30 : ITokenMessenger.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title ITokenMessenger
 * @notice Sends messages to MessageTransmitters and to TokenMinters
 */
interface ITokenMessenger {
    function depositForBurnWithCaller(
        uint256 _amount,
        uint32 _destinationDomain,
        bytes32 _mintRecipient,
        address _burnToken,
        bytes32 _destinationCaller
    ) external returns (uint64 _nonce);
}

File 14 of 30 : 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 fromAddress 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 15 of 30 : 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 16 of 30 : IGatewayClient.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

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

/**
 * @title IGatewayClient
 * @notice Cross-chain gateway client interface
 */
interface IGatewayClient {
    /**
     * @notice The standard "receive" function
     */
    receive() external payable;

    /**
     * @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 Getter of the source gateway context
     * @return vault The source vault
     * @return assetAmount The source vault asset amount
     */
    function getSourceGatewayContext() external view returns (IVault vault, uint256 assetAmount);
}

File 17 of 30 : 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 18 of 30 : 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 19 of 30 : 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 20 of 30 : 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 21 of 30 : 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 22 of 30 : 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 23 of 30 : IActionDataStructures.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title IActionDataStructures
 * @notice Action data structure declarations
 */
interface IActionDataStructures {
    /**
     * @notice Single-chain action data structure
     * @param fromTokenAddress The address of the input token
     * @param toTokenAddress The address of the output token
     * @param swapInfo The data for the single-chain swap
     * @param recipient The address of the recipient
     */
    struct LocalAction {
        address fromTokenAddress;
        address toTokenAddress;
        SwapInfo swapInfo;
        address recipient;
    }

    /**
     * @notice Cross-chain action data structure
     * @param gatewayType The numeric type of the cross-chain gateway
     * @param vaultType The numeric type of the vault
     * @param sourceTokenAddress The address of the input token on the source chain
     * @param sourceSwapInfo The data for the source chain swap
     * @param targetChainId The action target chain ID
     * @param targetTokenAddress The address of the output token on the destination chain
     * @param targetSwapInfoOptions The list of data options for the target chain swap
     * @param targetRecipient The address of the recipient on the target chain
     * @param gatewaySettings The gateway-specific settings data
     */
    struct Action {
        uint256 gatewayType;
        uint256 vaultType;
        address sourceTokenAddress;
        SwapInfo sourceSwapInfo;
        uint256 targetChainId;
        address targetTokenAddress;
        SwapInfo[] targetSwapInfoOptions;
        address targetRecipient;
        bytes gatewaySettings;
    }

    /**
     * @notice Token swap data structure
     * @param fromAmount The quantity of the token
     * @param routerType The numeric type of the swap router
     * @param routerData The data for the swap router call
     */
    struct SwapInfo {
        uint256 fromAmount;
        uint256 routerType;
        bytes routerData;
    }

    /**
     * @notice Cross-chain message data structure
     * @param actionId The unique identifier of the cross-chain action
     * @param sourceSender The address of the sender on the source chain
     * @param vaultType The numeric type of the vault
     * @param targetTokenAddress The address of the output token on the target chain
     * @param targetSwapInfo The data for the target chain swap
     * @param targetRecipient The address of the recipient on the target chain
     */
    struct TargetMessage {
        uint256 actionId;
        address sourceSender;
        uint256 vaultType;
        address targetTokenAddress;
        SwapInfo targetSwapInfo;
        address targetRecipient;
    }
}

File 24 of 30 : 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 25 of 30 : IVault.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

/**
 * @title IVault
 * @notice Vault interface
 */
interface IVault {
    /**
     * @notice The getter of the vault asset address
     */
    function asset() external view returns (address);

    /**
     * @notice Checks the status of the variable token and balance actions and the variable token address
     * @return The address of the variable token
     */
    function checkVariableTokenState() external view returns (address);

    /**
     * @notice Requests the vault asset tokens
     * @param _amount The amount of the vault asset tokens
     * @param _to The address of the vault asset tokens receiver
     * @param _forVariableBalance True if the request is made for a variable balance repayment, otherwise false
     * @return assetAddress The address of the vault asset token
     */
    function requestAsset(
        uint256 _amount,
        address _to,
        bool _forVariableBalance
    ) external returns (address assetAddress);
}

File 26 of 30 : 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 27 of 30 : AssetSpenderRole.sol
// SPDX-License-Identifier: AGPL-3.0-only

pragma solidity 0.8.19;

import { RoleBearers } from './RoleBearers.sol';

/**
 * @title AssetSpenderRole
 * @notice Base contract that implements the Asset Spender role
 */
abstract contract AssetSpenderRole is RoleBearers {
    bytes32 private constant ROLE_KEY = keccak256('AssetSpender');

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

    /**
     * @notice Emitted when the caller is not an Asset Spender role bearer
     */
    error OnlyAssetSpenderError();

    /**
     * @dev Modifier to check if the caller is an Asset Spender role bearer
     */
    modifier onlyAssetSpender() {
        if (!isAssetSpender(msg.sender)) {
            revert OnlyAssetSpenderError();
        }

        _;
    }

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

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

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

    function _setAssetSpender(address _account, bool _value) internal {
        _setRoleBearer(ROLE_KEY, _account, _value);

        emit SetAssetSpender(_account, _value);
    }
}

File 28 of 30 : 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 29 of 30 : 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 30 of 30 : 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('Circle CCTP - 2023-06-26'));
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ITokenMessenger","name":"_cctpTokenMessenger","type":"address"},{"internalType":"contract IMessageTransmitter","name":"_cctpMessageTransmitter","type":"address"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint32","name":"domain","type":"uint32"}],"internalType":"struct CircleCctpGateway.ChainDomain[]","name":"_chainDomains","type":"tuple[]"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"bool","name":"_variableRepaymentEnabled","type":"bool"},{"internalType":"uint256","name":"_targetGasReserve","type":"uint256"},{"internalType":"address","name":"_processingFeeCollector","type":"address"},{"internalType":"address","name":"_targetExecutor","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":"AssetMessageError","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerGuardError","type":"error"},{"inputs":[],"name":"DataMessageError","type":"error"},{"inputs":[],"name":"DomainNotSetError","type":"error"},{"inputs":[],"name":"ExecutorError","type":"error"},{"inputs":[],"name":"ListSizeLimitError","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NonContractAddressError","type":"error"},{"inputs":[],"name":"OnlyAssetSpenderError","type":"error"},{"inputs":[],"name":"OnlyClientError","type":"error"},{"inputs":[],"name":"OnlyCurrentVaultError","type":"error"},{"inputs":[],"name":"OnlyManagerError","type":"error"},{"inputs":[],"name":"OnlyMessageTransmitterError","type":"error"},{"inputs":[],"name":"PeerAddressMismatchError","type":"error"},{"inputs":[],"name":"PeerNotSetError","type":"error"},{"inputs":[],"name":"ProcessingFeeError","type":"error"},{"inputs":[],"name":"ReservedTokenError","type":"error"},{"inputs":[],"name":"SafeApproveError","type":"error"},{"inputs":[],"name":"SafeTransferError","type":"error"},{"inputs":[],"name":"SafeTransferNativeError","type":"error"},{"inputs":[],"name":"TargetAssetAmountMismatchError","type":"error"},{"inputs":[],"name":"TargetCallerError","type":"error"},{"inputs":[],"name":"TargetClientNotSetError","type":"error"},{"inputs":[{"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"internalType":"address","name":"fromAddress","type":"address"}],"name":"TargetFromAddressError","type":"error"},{"inputs":[],"name":"TargetGasReserveError","type":"error"},{"inputs":[],"name":"VariableRepaymentNotEnabledError","type":"error"},{"inputs":[],"name":"VariableTokenNotSetError","type":"error"},{"inputs":[],"name":"ZeroAddressError","type":"error"},{"inputs":[],"name":"ZeroChainIdError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"targetChainId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"useTargetExecutor","type":"bool"},{"indexed":false,"internalType":"uint64","name":"assetMessageNonce","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"dataMessageNonce","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"processingFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"processingGas","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"GatewayActionSource","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"}],"name":"RemoveChainDomain","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":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetAssetSpender","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum CallerGuard.CallerGuardMode","name":"callerGuardMode","type":"uint8"}],"name":"SetCallerGuardMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"}],"name":"SetChainDomain","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":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"isListed","type":"bool"}],"name":"SetListedCallerGuardContract","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":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":true,"internalType":"address","name":"targetExecutor","type":"address"}],"name":"SetTargetExecutor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasReserve","type":"uint256"}],"name":"SetTargetGasReserve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"variableRepaymentEnabled","type":"bool"}],"name":"SetVariableRepaymentEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sourceChainId","type":"uint256"}],"name":"TargetCctpMessageFailure","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":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetSpenderCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callerGuardMode","outputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cctpMessageTransmitter","outputs":[{"internalType":"contract IMessageTransmitter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cctpTokenMessenger","outputs":[{"internalType":"contract ITokenMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"chainIdToDomain","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkVariableTokenState","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"domainToChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_assetMessage","type":"bytes"},{"internalType":"bytes","name":"_assetAttestation","type":"bytes"},{"internalType":"bytes","name":"_dataMessage","type":"bytes"},{"internalType":"bytes","name":"_dataAttestation","type":"bytes"}],"name":"executeTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_assetMessage","type":"bytes"},{"internalType":"bytes","name":"_assetAttestation","type":"bytes"},{"internalType":"address","name":"_to","type":"address"}],"name":"extractCctpAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fullAssetSpenderList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullListedCallerGuardContractList","outputs":[{"internalType":"address[]","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":"uint32","name":"_sourceDomain","type":"uint32"},{"internalType":"bytes32","name":"_sender","type":"bytes32"},{"internalType":"bytes","name":"_messageBody","type":"bytes"}],"name":"handleReceiveMessage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isAssetSpender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isListedCallerGuardContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"listedCallerGuardContractCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"listedCallerGuardContractIndexMap","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"listedCallerGuardContractList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"_settings","type":"bytes"}],"name":"messageFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":"_chainIds","type":"uint256[]"}],"name":"removeChainDomains","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":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"bool","name":"_forVariableBalance","type":"bool"}],"name":"requestAsset","outputs":[{"internalType":"address","name":"assetAddress","type":"address"}],"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":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setAssetSpender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"_callerGuardMode","type":"uint8"}],"name":"setCallerGuardMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"uint32","name":"domain","type":"uint32"}],"internalType":"struct CircleCctpGateway.ChainDomain[]","name":"_chainDomains","type":"tuple[]"}],"name":"setChainDomains","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_clientAddress","type":"address"}],"name":"setClient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"flag","type":"bool"}],"internalType":"struct AccountToFlag[]","name":"_items","type":"tuple[]"}],"name":"setListedCallerGuardContracts","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":[{"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":"address","name":"_targetExecutor","type":"address"}],"name":"setTargetExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasReserve","type":"uint256"}],"name":"setTargetGasReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetExecutor","outputs":[{"internalType":"address","name":"","type":"address"}],"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"},{"inputs":[],"name":"variableRepaymentEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60e06040526009805460ff191690553480156200001b57600080fd5b506040516200458e3803806200458e8339810160408190526200003e91620009c4565b6000805460ff19169055620000533362000121565b60016003556001600160a01b03808c166080528a1660a05260005b8951811015620000c95760008a82815181106200008f576200008f62000ad6565b60200260200101519050620000b3816000015182602001516200017a60201b60201c565b5080620000c08162000b02565b9150506200006e565b506001600160a01b03881660c052620000e2876200022c565b620000ed8662000269565b620000f885620002a4565b6200010384620002f6565b6200011083838362000340565b505050505050505050505062000b4a565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6000828152600c60205260409020805460ff1615620001ae57600181015463ffffffff166000908152600d60205260408120555b604080518082018252600180825263ffffffff851660208084018281526000898152600c83528681209551865460ff191690151517865590519490930193909355808252600d9092528281208690559151909185917f55fdf4a71f93ff89177262ca6b1cfa79f18f4425d1b8e928bb2ef7a18883a33c9190a3505050565b600e805460ff19168215159081179091556040517fdf888ec24e9081be857eb58887c4c9e546edf94ee7dbc643c07f69dd32c0d13590600090a250565b60048190556040518181527fec9e8f9ec7dd2c5310e5b87c7bedeb6ba1c5943cb4d2da1ee80335508a5bc5a49060200160405180910390a150565b600e8054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517f9113819388a87769f8958d74097d68f96e457d5bc25f0168a8ffb3d3a55672a390600090a250565b600f80546001600160a01b0319166001600160a01b0383169081179091556040517f23f86a3e9ecbe238d0d1110e33eeec3ca6121dfd07f56ec10fdbf8aee36cdd3790600090a250565b60006001600160a01b038416156200035957836200035b565b335b905060005b8351811015620003ae576200039984828151811062000383576200038362000ad6565b60200260200101516001620003fa60201b60201c565b80620003a58162000b02565b91505062000360565b50818015620003c55750620003c3816200046d565b155b15620003d857620003d8816001620003fa565b6001600160a01b0381163314620003f457620003f481620004af565b50505050565b6200040462000532565b620004317f6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6f838362000596565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff165b92915050565b620004b962000532565b6001600160a01b038116620005245760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6200052f8162000121565b50565b6000546001600160a01b03610100909104163314620005945760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200051b565b565b60008381526001602090815260408083206002909252909120620003f4919084846064600082620005d457620005ce868686620005ec565b620005e2565b620005e28686868562000721565b9695505050505050565b6001600160a01b0381166000908152602083905260409020805460ff169081156200071957600180820154865490916000916200062a919062000b1e565b9050808214620006be5760008782815481106200064b576200064b62000ad6565b9060005260206000200160009054906101000a90046001600160a01b031690508088848154811062000681576200068162000ad6565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b86805480620006d157620006d162000b34565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015620007ce5784548211620007675760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b03191690911790555b949350505050565b6001600160a01b03811681146200052f57600080fd5b8051620007f981620007d6565b919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715620008395762000839620007fe565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200086a576200086a620007fe565b604052919050565b60006001600160401b038211156200088e576200088e620007fe565b5060051b60200190565b600082601f830112620008aa57600080fd5b81516020620008c3620008bd8362000872565b6200083f565b82815260069290921b84018101918181019086841115620008e357600080fd5b8286015b848110156200093b5760408189031215620009025760008081fd5b6200090c62000814565b815181528482015163ffffffff81168114620009285760008081fd5b81860152835291830191604001620008e7565b509695505050505050565b80518015158114620007f957600080fd5b600082601f8301126200096957600080fd5b815160206200097c620008bd8362000872565b82815260059290921b840181019181810190868411156200099c57600080fd5b8286015b848110156200093b578051620009b681620007d6565b8352918301918301620009a0565b60008060008060008060008060008060006101608c8e031215620009e757600080fd5b620009f28c620007ec565b9a5062000a0260208d01620007ec565b60408d0151909a506001600160401b0381111562000a1f57600080fd5b62000a2d8e828f0162000898565b99505062000a3e60608d01620007ec565b975062000a4e60808d0162000946565b965060a08c0151955062000a6560c08d01620007ec565b945062000a7560e08d01620007ec565b935062000a866101008d01620007ec565b6101208d01519093506001600160401b0381111562000aa457600080fd5b62000ab28e828f0162000957565b92505062000ac46101408d0162000946565b90509295989b509295989b9093969950565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820162000b175762000b1762000aec565b5060010190565b81810381811115620004a957620004a962000aec565b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05161399662000bf8600039600081816105ae01528181610e8f01528181610eb80152818161112b015281816111aa0152818161125a01528181611593015281816116c10152818161175b01528181611ce70152611de4015260008181610833015281816112a3015281816116200152818161179f01528181611d110152611e4d0152600081816108aa0152818161114c015281816111da015261127b01526139966000f3fe60806040526004361061037a5760003560e01c806385013a1b116101d1578063c116a3cb11610102578063ee10bf88116100a0578063f977350c1161006f578063f977350c14610b45578063fd8a177914610b65578063fe14e8c314610b92578063fe8fc8d414610bb257600080fd5b8063ee10bf8814610ac5578063eedc966a14610ae5578063f2fde38b14610b05578063f3ae241514610b2557600080fd5b8063dcd44d71116100dc578063dcd44d7114610a5b578063e3725b1514610a7b578063e81ea59514610a90578063e96fbd6814610aa557600080fd5b8063c116a3cb146109f0578063c2c518e114610a10578063c84e329e14610a2557600080fd5b80639c90dfa11161016f578063aeb2d2d411610149578063aeb2d2d414610969578063b7e2c37e14610989578063bb6e4936146109a9578063bc788169146109ce57600080fd5b80639c90dfa1146108cc578063a5e90eee14610929578063aa4fc83d1461094957600080fd5b80638c73eb04116101ab5780638c73eb04146108215780638da5cb5b1461085557806396abeb70146108785780639748cf7c1461089857600080fd5b806385013a1b146107c15780638526690a146107e15780638a84fa111461080157600080fd5b80634b15b2a9116102ab5780636ea9cec911610249578063786ea0ce11610223578063786ea0ce146107325780637b25b4d41461076c578063832b54911461078c5780638456cb59146107ac57600080fd5b80636ea9cec9146106d0578063715018a6146106e357806377c3a2db146106f857600080fd5b80635c975abb116102855780635c975abb1461065c578063607ab5e514610674578063630eae081461069b5780636b56a691146106bb57600080fd5b80634b15b2a9146106065780635a9fab50146106265780635c56ca351461063c57600080fd5b80632c966a3411610318578063341328c5116102f2578063341328c51461054b57806338d52e0f1461059c5780633f4ba83a146105d0578063440d7248146105e557600080fd5b80632c966a34146104f65780632fac88c01461050b57806330eb12781461052b57600080fd5b8063103b739711610354578063103b739714610408578063109e94cf1461045357806317daf0b41461048b5780631f8800fa146104d457600080fd5b806304e535e214610386578063093f0e27146103b15780630f937410146103f357600080fd5b3661038157005b600080fd5b34801561039257600080fd5b5061039b610bcc565b6040516103a89190612fc3565b60405180910390f35b3480156103bd57600080fd5b506103e57f823c7e20a184791a7512c6f8ac1d42562079dc51f9442abc45d36a3d003127d781565b6040519081526020016103a8565b3480156103ff57600080fd5b5061039b610c2e565b34801561041457600080fd5b5060008051602061394183398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546103e5565b34801561045f57600080fd5b50600554610473906001600160a01b031681565b6040516001600160a01b0390911681526020016103a8565b34801561049757600080fd5b506104c46104a6366004613030565b6001600160a01b03166000908152600b602052604090205460ff1690565b60405190151581526020016103a8565b3480156104e057600080fd5b506104f46104ef366004613030565b610c5e565b005b34801561050257600080fd5b50610473610c90565b34801561051757600080fd5b506104f461052636600461309f565b610ccf565b34801561053757600080fd5b506104f46105463660046130e0565b610d90565b34801561055757600080fd5b50610585610566366004613030565b600b602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016103a8565b3480156105a857600080fd5b506104737f000000000000000000000000000000000000000000000000000000000000000081565b3480156105dc57600080fd5b506104f4610df4565b3480156105f157600080fd5b506104c4610600366004613030565b50600090565b34801561061257600080fd5b5061047361062136600461311a565b610e2c565b34801561063257600080fd5b506103e560045481565b34801561064857600080fd5b506104c4610657366004613030565b610ede565b34801561066857600080fd5b5060005460ff166104c4565b34801561068057600080fd5b5060095461068e9060ff1681565b6040516103a89190613172565b3480156106a757600080fd5b506104f46106b636600461319a565b610f20565b3480156106c757600080fd5b50600a546103e5565b6104f46106de3660046131f4565b610f4f565b3480156106ef57600080fd5b506104f46113ca565b34801561070457600080fd5b5061058561071336600461319a565b600c602052600090815260409020805460019091015460ff9091169082565b34801561073e57600080fd5b5061058561074d36600461319a565b6008602052600090815260409020805460019091015460ff9091169082565b34801561077857600080fd5b5061047361078736600461319a565b6113dc565b34801561079857600080fd5b506103e56107a736600461319a565b611406565b3480156107b857600080fd5b506104f4611427565b3480156107cd57600080fd5b506104f46107dc36600461309f565b61145d565b3480156107ed57600080fd5b506104f46107fc366004613030565b6114dc565b34801561080d57600080fd5b506104f461081c36600461326d565b611555565b34801561082d57600080fd5b506104737f000000000000000000000000000000000000000000000000000000000000000081565b34801561086157600080fd5b5060005461010090046001600160a01b0316610473565b34801561088457600080fd5b506104c4610893366004613304565b61178a565b3480156108a457600080fd5b506104737f000000000000000000000000000000000000000000000000000000000000000081565b3480156108d857600080fd5b507fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c217460005260016020527fb6368b31e79ffb73a14a00fbd9c0dbbe43a3a26df7f98e18d14334693e18dfce546103e5565b34801561093557600080fd5b506104f461094436600461335d565b6119c6565b34801561095557600080fd5b506103e56109643660046131f4565b611a23565b34801561097557600080fd5b50600f54610473906001600160a01b031681565b34801561099557600080fd5b506104f46109a4366004613396565b611a3d565b3480156109b557600080fd5b50600e546104739061010090046001600160a01b031681565b3480156109da57600080fd5b506109e3611aa7565b6040516103a8919061340a565b3480156109fc57600080fd5b506104f4610a0b36600461335d565b611afe565b348015610a1c57600080fd5b506104f4611b2e565b348015610a3157600080fd5b50610473610a4036600461319a565b6006602052600090815260409020546001600160a01b031681565b348015610a6757600080fd5b506104f4610a76366004613396565b611b9b565b348015610a8757600080fd5b5061039b611c0c565b348015610a9c57600080fd5b506007546103e5565b348015610ab157600080fd5b506104f4610ac0366004613442565b611c25565b348015610ad157600080fd5b506104f4610ae0366004613030565b611f17565b348015610af157600080fd5b506103e5610b00366004613030565b611f46565b348015610b1157600080fd5b506104f4610b20366004613030565b611fe1565b348015610b3157600080fd5b506104c4610b40366004613030565b612057565b348015610b5157600080fd5b506104f4610b60366004613505565b612097565b348015610b7157600080fd5b506103e5610b80366004613526565b600d6020526000908152604090205481565b348015610b9e57600080fd5b506104f4610bad36600461309f565b61211f565b348015610bbe57600080fd5b50600e546104c49060ff1681565b6060600a805480602002602001604051908101604052809291908181526020018280548015610c2457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610c06575b5050505050905090565b6060610c597fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c217461222b565b905090565b610c6733612057565b610c8457604051637c3ea23f60e01b815260040160405180910390fd5b610c8d81612297565b50565b600e5460009060ff16610cb657604051634dd32fa760e11b815260040160405180910390fd5b604051630d51877360e21b815260040160405180910390fd5b610cd833612057565b610cf557604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b5736838383818110610d1357610d13613541565b604090810292909201925050813590600090610d3490840160208501613030565b9050468203610d6b576001600160a01b0381163014610d6657604051631131ed9760e31b815260040160405180910390fd5b610d75565b610d7582826122e1565b5050508080610d839061356d565b915050610cf8565b505050565b610d9933612057565b610db657604051637c3ea23f60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610de957610de53382612376565b5050565b610de5823383612404565b610dfd33612057565b610e1a57604051637c3ea23f60e01b815260040160405180910390fd5b610e226124f6565b610e2a61253f565b565b6000610e36612591565b610e3f33610ede565b610e5c5760405163085c44cb60e31b815260040160405180910390fd5b818015610e6c5750600e5460ff16155b15610e8a57604051634dd32fa760e11b815260040160405180910390fd5b610eb57f00000000000000000000000000000000000000000000000000000000000000008486612404565b507f00000000000000000000000000000000000000000000000000000000000000009392505050565b6001600160a01b03811660009081527f91fc3844d4d576137f627e112fa2b39fcc5933d06153e6698ea43f81fc70b81b602052604081205460ff165b92915050565b610f2933612057565b610f4657604051637c3ea23f60e01b815260040160405180910390fd5b610c8d816125d7565b6005546001600160a01b03163314610f7a5760405163424029e160e01b815260040160405180910390fd5b610f82612591565b6005546040805163018130df60e51b8152815160009384936001600160a01b03909116926330261be092600480830193928290030181865afa158015610fcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff09190613586565b90925090506001600160a01b038216301461101e5760405163f5f9a58f60e01b815260040160405180910390fd5b6040805160a080820183526000808352602080840182905283850182905260608085018390526080948501839052855193840186528284529083018290529382018190529281018390529081019190915261108761107b89612612565b6001600160a01b031690565b815261109288612648565b63ffffffff1660208201526000806110aa8787612682565b911515608086015292509050348211156110d7576040516360b5c54960e01b815260040160405180910390fd5b6000821180156110f65750600e5461010090046001600160a01b031615155b1561111657600e546111169061010090046001600160a01b031683612376565b6000611124898b018b613644565b90506111717f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008761269f565b60208401518451604051637c2b6edb60e11b81526004810188905263ffffffff9092166024830152604482018190526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116606484015260848301919091527f0000000000000000000000000000000000000000000000000000000000000000169063f856ddb69060a4016020604051808303816000875af1158015611223573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611247919061378d565b6001600160401b031660408501526112a17f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000600061269f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f7259a758560200151866000015187600001518e8e6040518663ffffffff1660e01b81526004016113019594939291906137df565b6020604051808303816000875af1158015611320573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611344919061378d565b6001600160401b03908116606086810182905260808088015185516040808b015181519716875260208701959095529385018a905291840187905283018590524260a08401521515918d91907f742fc5a2eb8bd42a536089d583f08bf52f3110072f62c20f54468cd81bc1815a9060c00160405180910390a45050505050505050505050565b6113d2612789565b610e2a60006127e9565b600a81815481106113ec57600080fd5b6000918252602090912001546001600160a01b0316905081565b6007818154811061141657600080fd5b600091825260209091200154905081565b61143033612057565b61144d57604051637c3ea23f60e01b815260040160405180910390fd5b611455612591565b610e2a612842565b61146633612057565b61148357604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b57368383838181106114a1576114a1613541565b90506040020190506114c981600001358260200160208101906114c49190613526565b61287f565b50806114d48161356d565b915050611486565b6114e533612057565b61150257604051637c3ea23f60e01b815260040160405180910390fd5b61150b81612930565b600580546001600160a01b0319166001600160a01b0383169081179091556040517f764166c557b419ae9f4bca81c505141ce7017b4bdb4c610ad113a50ec7e578a990600090a250565b61155e33612057565b61157b57604051637c3ea23f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156115e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116069190613816565b604051630afd9fa560e31b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906357ecfd289061165b90899089908990899060040161382f565b6020604051808303816000875af115801561167a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169e9190613856565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611708573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172c9190613816565b6117369190613873565b905060008111801561175157506001600160a01b0383163014155b15611781576117817f00000000000000000000000000000000000000000000000000000000000000008483612404565b50505050505050565b6000611794612591565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117dd576040516331e4d14960e01b815260040160405180910390fd5b63ffffffff85166000908152600d6020526040812054908590821580159061180d57506001600160a01b03821615155b801561183257506000838152600660205260409020546001600160a01b038381169116145b9050806118685760405162e3894560e01b8152600481018490526001600160a01b03831660248201526044015b60405180910390fd5b50600061187785870187613644565b601054600f549192506001600160a01b0390811691600091168214806118b2575082602001516001600160a01b0316826001600160a01b0316145b806118d257508260a001516001600160a01b0316826001600160a01b0316145b9050806118f25760405163460327af60e11b815260040160405180910390fd5b50506011546080820151511461191b5760405163ec8cb1df60e01b815260040160405180910390fd5b600080611929600454612963565b915091508161194b57604051636d0ea9b360e11b815260040160405180910390fd5b60055460405163032ad3cf60e51b81526001600160a01b039091169063655a79e09083906119819089908d908d90600401613886565b600060405180830381600088803b15801561199b57600080fd5b5087f11580156119af573d6000803e3d6000fd5b50505050506001955050505050505b949350505050565b6119ce612789565b6119e7600080516020613941833981519152838361298f565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b600080611a308484612682565b5098975050505050505050565b611a4633612057565b611a6357604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b576000838383818110611a8257611a82613541565b905060200201359050611a94816129bc565b5080611a9f8161356d565b915050611a66565b60606007805480602002602001604051908101604052809291908181526020018280548015610c2457602002820191906000526020600020905b815481526020019060010190808311611ae1575050505050905090565b611b0733612057565b611b2457604051637c3ea23f60e01b815260040160405180910390fd5b610de58282612a45565b611b3733612057565b611b5457604051637c3ea23f60e01b815260040160405180910390fd5b611b6e60008051602061394183398151915233600061298f565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b611ba433612057565b611bc157604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b576000838383818110611be057611be0613541565b905060200201359050468114611bf957611bf981612aac565b5080611c048161356d565b915050611bc4565b6060610c5960008051602061394183398151915261222b565b611c2d612591565b611c35612b0b565b333214611cb7576000600260095460ff166002811115611c5757611c5761315c565b1480611c935750600160095460ff166002811115611c7757611c7761315c565b148015611c935750336000908152600b602052604090205460ff165b905080611cb557604051630fa0970d60e11b815233600482015260240161185f565b505b6005546001600160a01b0316611ce05760405163bc864a6960e01b815260040160405180910390fd5b6000611d0b7f0000000000000000000000000000000000000000000000000000000000000000611f46565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166357ecfd288b8b8b8b6040518563ffffffff1660e01b8152600401611d61949392919061382f565b6020604051808303816000875af1158015611d80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da49190613856565b905080611dc45760405163ecf5a8ff60e01b815260040160405180910390fd5b6040518060400160405280336001600160a01b0316815260200183611e087f0000000000000000000000000000000000000000000000000000000000000000611f46565b611e129190613873565b90528051601080546001600160a01b0319166001600160a01b03928316179055602090910151601155604051630afd9fa560e31b81526000917f000000000000000000000000000000000000000000000000000000000000000016906357ecfd2890611e88908a908a908a908a9060040161382f565b6020604051808303816000875af1158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecb9190613856565b905080611eeb57604051631c2f23e960e21b815260040160405180910390fd5b5050601080546001600160a01b0319169055506000601155611f0d6001600355565b5050505050505050565b611f2033612057565b611f3d57604051637c3ea23f60e01b815260040160405180910390fd5b610c8d81612b64565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611f74575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611fb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1a9190613816565b919050565b611fe9612789565b6001600160a01b03811661204e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161185f565b610c8d816127e9565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff16610f1a565b6120a033612057565b6120bd57604051637c3ea23f60e01b815260040160405180910390fd5b6009805482919060ff191660018360028111156120dc576120dc61315c565b02179055508060028111156120f3576120f361315c565b6040517f332a9f1d3bd9b0f7abbd95838fed6b417589632d0eb33f2d8ae6e2aa17178efd90600090a250565b61212833612057565b61214557604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b573683838381811061216357612163613541565b905060400201905080602001602081019061217e91906138a9565b15612198576121986121936020830183613030565b612930565b6121c3600a600b6121ac6020850185613030565b6121bc60408601602087016138a9565b6064612bb6565b506121d460408201602083016138a9565b15156121e36020830183613030565b6001600160a01b03167f1470aed653fa8a8ce4c7b2f41287634199f7ec3c4f5fd0ace97d82cf006beec360405160405180910390a350806122238161356d565b915050612148565b60008181526001602090815260409182902080548351818402810184019094528084526060939283018282801561228b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161226d575b50505050509050919050565b600f80546001600160a01b0319166001600160a01b0383169081179091556040517f23f86a3e9ecbe238d0d1110e33eeec3ca6121dfd07f56ec10fdbf8aee36cdd3790600090a250565b81600003612302576040516381e7376360e01b815260040160405180910390fd5b6001600160a01b03811661232957604051633efa09af60e01b815260040160405180910390fd5b61233b60066007600885856064612be3565b506040516001600160a01b0382169083907f357d1ebd1dc0d53cc15161206b9a39c9ca30667bd997cf921eb00e4c78a454f590600090a35050565b604080516000808252602082019092526001600160a01b0384169083906040516123a091906138c6565b60006040518083038185875af1925050503d80600081146123dd576040519150601f19603f3d011682016040523d82523d6000602084013e6123e2565b606091505b5050905080610d8b57604051632e05b05360e21b815260040160405180910390fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161246091906138c6565b6000604051808303816000865af19150503d806000811461249d576040519150601f19603f3d011682016040523d82523d6000602084013e6124a2565b606091505b509150915060008280156124ce5750815115806124ce5750818060200190518101906124ce9190613856565b9050806124ee57604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b60005460ff16610e2a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161185f565b6125476124f6565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60005460ff1615610e2a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161185f565b60048190556040518181527fec9e8f9ec7dd2c5310e5b87c7bedeb6ba1c5943cb4d2da1ee80335508a5bc5a49060200160405180910390a150565b6000818152600660205260408120546001600160a01b031680610f1a57604051631a81634560e01b815260040160405180910390fd5b6000818152600c60205260408120805460ff166126785760405163731da1e960e11b815260040160405180910390fd5b6001015492915050565b60008080612692848601866138f5565b9250925092509250925092565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916126fb91906138c6565b6000604051808303816000865af19150503d8060008114612738576040519150601f19603f3d011682016040523d82523d6000602084013e61273d565b606091505b509150915060008280156127695750815115806127695750818060200190518101906127699190613856565b9050806124ee5760405163b45d44e760e01b815260040160405180910390fd5b6000546001600160a01b03610100909104163314610e2a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161185f565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b61284a612591565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125743390565b6000828152600c60205260409020805460ff16156128b257600181015463ffffffff166000908152600d60205260408120555b604080518082018252600180825263ffffffff851660208084018281526000898152600c83528681209551865460ff191690151517865590519490930193909355808252600d9092528281208690559151909185917f55fdf4a71f93ff89177262ca6b1cfa79f18f4425d1b8e928bb2ef7a18883a33c9190a3505050565b6001600160a01b0381163b610c8d57604051638c50d7cd60e01b81526001600160a01b038216600482015260240161185f565b60008060005a90508381101592508261297d576000612987565b6129878482613873565b915050915091565b600083815260016020908152604080832060029092529091206129b6919084846064612bb6565b50505050565b6000818152600c60205260408120805490919060ff16156129f45750600181015463ffffffff81166000908152600d60205260408120555b6000838152600c6020526040808220805460ff191681556001018290555163ffffffff83169185917ff79bac28779a4bff7a04c8f64491c5be344a30648bb4539212da26244b0a6e1a9190a3505050565b612a707fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c2174838361298f565b604051811515906001600160a01b038416907fc6b049f4dc9561b397b0cef913ea5f18165b682b193be62c0bbbf9ca8763aeba90600090a35050565b80600003612acd576040516381e7376360e01b815260040160405180910390fd5b612adc60066007600884612c3f565b5060405181907feb39225b53386d0eb02af9cf2c6b6a0c345a97654f1e67fb21b0b5aaac81ec4a90600090a250565b600260035403612b5d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161185f565b6002600355565b600e8054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517f9113819388a87769f8958d74097d68f96e457d5bc25f0168a8ffb3d3a55672a390600090a250565b600082612bcd57612bc8868686612c87565b612bd9565b612bd986868685612daf565b9695505050505050565b60008381526020859052604090205460ff16158015612c0a57612c0886868685612e5f565b505b600093845260209690965250604090912080546001600160a01b0319166001600160a01b039092169190911790555090919050565b60008181526020839052604090205460ff1680156119be57600082815260208690526040902080546001600160a01b0319169055612c7e848484612ee8565b50949350505050565b6001600160a01b0381166000908152602083905260409020805460ff16908115612da75760018082015486549091600091612cc29190613873565b9050808214612d4f576000878281548110612cdf57612cdf613541565b9060005260206000200160009054906101000a90046001600160a01b0316905080888481548110612d1257612d12613541565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b86805480612d5f57612d5f61392a565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156119be5784548211612df35760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b039790971660008181529888529388209251835460ff19169015151783555191810191909155865490810187559585529290932090930180546001600160a01b0319169091179055919050565b60008281526020849052604090205460ff161580156119be5784548211612e995760405163b1655e3360e01b815260040160405180910390fd5b60408051808201825260018082528754602080840191825260008881529881529388209251835460ff191690151517835551918101919091558654908101875595855290932090930155919050565b6000818152602083905260409020805460ff16908115612da75760018082015486549091600091612f199190613873565b9050808214612f78576000878281548110612f3657612f36613541565b9060005260206000200154905080888481548110612f5657612f56613541565b6000918252602080832090910192909255918252879052604090206001018290555b86805480612f8857612f8861392a565b60008281526020808220830160001990810183905590920190925586825287905260408120805460ff19168155600101555050509392505050565b6020808252825182820181905260009190848201906040850190845b818110156130045783516001600160a01b031683529284019291840191600101612fdf565b50909695505050505050565b6001600160a01b0381168114610c8d57600080fd5b8035611fdc81613010565b60006020828403121561304257600080fd5b813561304d81613010565b9392505050565b60008083601f84011261306657600080fd5b5081356001600160401b0381111561307d57600080fd5b6020830191508360208260061b850101111561309857600080fd5b9250929050565b600080602083850312156130b257600080fd5b82356001600160401b038111156130c857600080fd5b6130d485828601613054565b90969095509350505050565b600080604083850312156130f357600080fd5b82356130fe81613010565b946020939093013593505050565b8015158114610c8d57600080fd5b60008060006060848603121561312f57600080fd5b83359250602084013561314181613010565b915060408401356131518161310c565b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b602081016003831061319457634e487b7160e01b600052602160045260246000fd5b91905290565b6000602082840312156131ac57600080fd5b5035919050565b60008083601f8401126131c557600080fd5b5081356001600160401b038111156131dc57600080fd5b60208301915083602082850101111561309857600080fd5b60008060008060006060868803121561320c57600080fd5b8535945060208601356001600160401b038082111561322a57600080fd5b61323689838a016131b3565b9096509450604088013591508082111561324f57600080fd5b5061325c888289016131b3565b969995985093965092949392505050565b60008060008060006060868803121561328557600080fd5b85356001600160401b038082111561329c57600080fd5b6132a889838a016131b3565b909750955060208801359150808211156132c157600080fd5b506132ce888289016131b3565b90945092505060408601356132e281613010565b809150509295509295909350565b803563ffffffff81168114611fdc57600080fd5b6000806000806060858703121561331a57600080fd5b613323856132f0565b93506020850135925060408501356001600160401b0381111561334557600080fd5b613351878288016131b3565b95989497509550505050565b6000806040838503121561337057600080fd5b823561337b81613010565b9150602083013561338b8161310c565b809150509250929050565b600080602083850312156133a957600080fd5b82356001600160401b03808211156133c057600080fd5b818501915085601f8301126133d457600080fd5b8135818111156133e357600080fd5b8660208260051b85010111156133f857600080fd5b60209290920196919550909350505050565b6020808252825182820181905260009190848201906040850190845b8181101561300457835183529284019291840191600101613426565b6000806000806000806000806080898b03121561345e57600080fd5b88356001600160401b038082111561347557600080fd5b6134818c838d016131b3565b909a50985060208b013591508082111561349a57600080fd5b6134a68c838d016131b3565b909850965060408b01359150808211156134bf57600080fd5b6134cb8c838d016131b3565b909650945060608b01359150808211156134e457600080fd5b506134f18b828c016131b3565b999c989b5096995094979396929594505050565b60006020828403121561351757600080fd5b81356003811061304d57600080fd5b60006020828403121561353857600080fd5b61304d826132f0565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161357f5761357f613557565b5060010190565b6000806040838503121561359957600080fd5b82516135a481613010565b6020939093015192949293505050565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b03811182821017156135ec576135ec6135b4565b60405290565b604051606081016001600160401b03811182821017156135ec576135ec6135b4565b604051601f8201601f191681016001600160401b038111828210171561363c5761363c6135b4565b604052919050565b6000602080838503121561365757600080fd5b82356001600160401b038082111561366e57600080fd5b9084019060c0828703121561368257600080fd5b61368a6135ca565b823581528383013561369b81613010565b818501526040838101359082015260608301356136b781613010565b60608201526080830135828111156136ce57600080fd5b8301606081890312156136e057600080fd5b6136e86135f2565b81358152858201358682015260408201358481111561370657600080fd5b80830192505088601f83011261371b57600080fd5b81358481111561372d5761372d6135b4565b61373f601f8201601f19168801613614565b9450808552898782850101111561375557600080fd5b808784018887013760009085018701526040810184905260808301525061377e60a08401613025565b60a08201529695505050505050565b60006020828403121561379f57600080fd5b81516001600160401b038116811461304d57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b63ffffffff8616815284602082015283604082015260806060820152600061380b6080830184866137b6565b979650505050505050565b60006020828403121561382857600080fd5b5051919050565b6040815260006138436040830186886137b6565b828103602084015261380b8185876137b6565b60006020828403121561386857600080fd5b815161304d8161310c565b81810381811115610f1a57610f1a613557565b8381526040602082015260006138a06040830184866137b6565b95945050505050565b6000602082840312156138bb57600080fd5b813561304d8161310c565b6000825160005b818110156138e757602081860181015185830152016138cd565b506000920191825250919050565b60008060006060848603121561390a57600080fd5b83356139158161310c565b95602085013595506040909401359392505050565b634e487b7160e01b600052603160045260246000fdfe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa2646970667358221220910caf4033a37ee4941c3ef69ed6e07b97ef76d851c041e7ead9d01de20c62b764736f6c63430008130033000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af31550000000000000000000000000a992d191deec32afe36203ad87d7d289a738f810000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000271000000000000000000000000054c28fdd59025942fe71545de8c6358c30b3a16a00000000000000000000000054c28fdd59025942fe71545de8c6358c30b3a16a00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000a86a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000006741a38adbd040e9e1a8a9c78ba52987e56a3e78

Deployed Bytecode

0x60806040526004361061037a5760003560e01c806385013a1b116101d1578063c116a3cb11610102578063ee10bf88116100a0578063f977350c1161006f578063f977350c14610b45578063fd8a177914610b65578063fe14e8c314610b92578063fe8fc8d414610bb257600080fd5b8063ee10bf8814610ac5578063eedc966a14610ae5578063f2fde38b14610b05578063f3ae241514610b2557600080fd5b8063dcd44d71116100dc578063dcd44d7114610a5b578063e3725b1514610a7b578063e81ea59514610a90578063e96fbd6814610aa557600080fd5b8063c116a3cb146109f0578063c2c518e114610a10578063c84e329e14610a2557600080fd5b80639c90dfa11161016f578063aeb2d2d411610149578063aeb2d2d414610969578063b7e2c37e14610989578063bb6e4936146109a9578063bc788169146109ce57600080fd5b80639c90dfa1146108cc578063a5e90eee14610929578063aa4fc83d1461094957600080fd5b80638c73eb04116101ab5780638c73eb04146108215780638da5cb5b1461085557806396abeb70146108785780639748cf7c1461089857600080fd5b806385013a1b146107c15780638526690a146107e15780638a84fa111461080157600080fd5b80634b15b2a9116102ab5780636ea9cec911610249578063786ea0ce11610223578063786ea0ce146107325780637b25b4d41461076c578063832b54911461078c5780638456cb59146107ac57600080fd5b80636ea9cec9146106d0578063715018a6146106e357806377c3a2db146106f857600080fd5b80635c975abb116102855780635c975abb1461065c578063607ab5e514610674578063630eae081461069b5780636b56a691146106bb57600080fd5b80634b15b2a9146106065780635a9fab50146106265780635c56ca351461063c57600080fd5b80632c966a3411610318578063341328c5116102f2578063341328c51461054b57806338d52e0f1461059c5780633f4ba83a146105d0578063440d7248146105e557600080fd5b80632c966a34146104f65780632fac88c01461050b57806330eb12781461052b57600080fd5b8063103b739711610354578063103b739714610408578063109e94cf1461045357806317daf0b41461048b5780631f8800fa146104d457600080fd5b806304e535e214610386578063093f0e27146103b15780630f937410146103f357600080fd5b3661038157005b600080fd5b34801561039257600080fd5b5061039b610bcc565b6040516103a89190612fc3565b60405180910390f35b3480156103bd57600080fd5b506103e57f823c7e20a184791a7512c6f8ac1d42562079dc51f9442abc45d36a3d003127d781565b6040519081526020016103a8565b3480156103ff57600080fd5b5061039b610c2e565b34801561041457600080fd5b5060008051602061394183398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a546103e5565b34801561045f57600080fd5b50600554610473906001600160a01b031681565b6040516001600160a01b0390911681526020016103a8565b34801561049757600080fd5b506104c46104a6366004613030565b6001600160a01b03166000908152600b602052604090205460ff1690565b60405190151581526020016103a8565b3480156104e057600080fd5b506104f46104ef366004613030565b610c5e565b005b34801561050257600080fd5b50610473610c90565b34801561051757600080fd5b506104f461052636600461309f565b610ccf565b34801561053757600080fd5b506104f46105463660046130e0565b610d90565b34801561055757600080fd5b50610585610566366004613030565b600b602052600090815260409020805460019091015460ff9091169082565b6040805192151583526020830191909152016103a8565b3480156105a857600080fd5b506104737f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b3480156105dc57600080fd5b506104f4610df4565b3480156105f157600080fd5b506104c4610600366004613030565b50600090565b34801561061257600080fd5b5061047361062136600461311a565b610e2c565b34801561063257600080fd5b506103e560045481565b34801561064857600080fd5b506104c4610657366004613030565b610ede565b34801561066857600080fd5b5060005460ff166104c4565b34801561068057600080fd5b5060095461068e9060ff1681565b6040516103a89190613172565b3480156106a757600080fd5b506104f46106b636600461319a565b610f20565b3480156106c757600080fd5b50600a546103e5565b6104f46106de3660046131f4565b610f4f565b3480156106ef57600080fd5b506104f46113ca565b34801561070457600080fd5b5061058561071336600461319a565b600c602052600090815260409020805460019091015460ff9091169082565b34801561073e57600080fd5b5061058561074d36600461319a565b6008602052600090815260409020805460019091015460ff9091169082565b34801561077857600080fd5b5061047361078736600461319a565b6113dc565b34801561079857600080fd5b506103e56107a736600461319a565b611406565b3480156107b857600080fd5b506104f4611427565b3480156107cd57600080fd5b506104f46107dc36600461309f565b61145d565b3480156107ed57600080fd5b506104f46107fc366004613030565b6114dc565b34801561080d57600080fd5b506104f461081c36600461326d565b611555565b34801561082d57600080fd5b506104737f0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f8181565b34801561086157600080fd5b5060005461010090046001600160a01b0316610473565b34801561088457600080fd5b506104c4610893366004613304565b61178a565b3480156108a457600080fd5b506104737f000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af315581565b3480156108d857600080fd5b507fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c217460005260016020527fb6368b31e79ffb73a14a00fbd9c0dbbe43a3a26df7f98e18d14334693e18dfce546103e5565b34801561093557600080fd5b506104f461094436600461335d565b6119c6565b34801561095557600080fd5b506103e56109643660046131f4565b611a23565b34801561097557600080fd5b50600f54610473906001600160a01b031681565b34801561099557600080fd5b506104f46109a4366004613396565b611a3d565b3480156109b557600080fd5b50600e546104739061010090046001600160a01b031681565b3480156109da57600080fd5b506109e3611aa7565b6040516103a8919061340a565b3480156109fc57600080fd5b506104f4610a0b36600461335d565b611afe565b348015610a1c57600080fd5b506104f4611b2e565b348015610a3157600080fd5b50610473610a4036600461319a565b6006602052600090815260409020546001600160a01b031681565b348015610a6757600080fd5b506104f4610a76366004613396565b611b9b565b348015610a8757600080fd5b5061039b611c0c565b348015610a9c57600080fd5b506007546103e5565b348015610ab157600080fd5b506104f4610ac0366004613442565b611c25565b348015610ad157600080fd5b506104f4610ae0366004613030565b611f17565b348015610af157600080fd5b506103e5610b00366004613030565b611f46565b348015610b1157600080fd5b506104f4610b20366004613030565b611fe1565b348015610b3157600080fd5b506104c4610b40366004613030565b612057565b348015610b5157600080fd5b506104f4610b60366004613505565b612097565b348015610b7157600080fd5b506103e5610b80366004613526565b600d6020526000908152604090205481565b348015610b9e57600080fd5b506104f4610bad36600461309f565b61211f565b348015610bbe57600080fd5b50600e546104c49060ff1681565b6060600a805480602002602001604051908101604052809291908181526020018280548015610c2457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610c06575b5050505050905090565b6060610c597fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c217461222b565b905090565b610c6733612057565b610c8457604051637c3ea23f60e01b815260040160405180910390fd5b610c8d81612297565b50565b600e5460009060ff16610cb657604051634dd32fa760e11b815260040160405180910390fd5b604051630d51877360e21b815260040160405180910390fd5b610cd833612057565b610cf557604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b5736838383818110610d1357610d13613541565b604090810292909201925050813590600090610d3490840160208501613030565b9050468203610d6b576001600160a01b0381163014610d6657604051631131ed9760e31b815260040160405180910390fd5b610d75565b610d7582826122e1565b5050508080610d839061356d565b915050610cf8565b505050565b610d9933612057565b610db657604051637c3ea23f60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601610de957610de53382612376565b5050565b610de5823383612404565b610dfd33612057565b610e1a57604051637c3ea23f60e01b815260040160405180910390fd5b610e226124f6565b610e2a61253f565b565b6000610e36612591565b610e3f33610ede565b610e5c5760405163085c44cb60e31b815260040160405180910390fd5b818015610e6c5750600e5460ff16155b15610e8a57604051634dd32fa760e11b815260040160405180910390fd5b610eb57f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488486612404565b507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489392505050565b6001600160a01b03811660009081527f91fc3844d4d576137f627e112fa2b39fcc5933d06153e6698ea43f81fc70b81b602052604081205460ff165b92915050565b610f2933612057565b610f4657604051637c3ea23f60e01b815260040160405180910390fd5b610c8d816125d7565b6005546001600160a01b03163314610f7a5760405163424029e160e01b815260040160405180910390fd5b610f82612591565b6005546040805163018130df60e51b8152815160009384936001600160a01b03909116926330261be092600480830193928290030181865afa158015610fcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff09190613586565b90925090506001600160a01b038216301461101e5760405163f5f9a58f60e01b815260040160405180910390fd5b6040805160a080820183526000808352602080840182905283850182905260608085018390526080948501839052855193840186528284529083018290529382018190529281018390529081019190915261108761107b89612612565b6001600160a01b031690565b815261109288612648565b63ffffffff1660208201526000806110aa8787612682565b911515608086015292509050348211156110d7576040516360b5c54960e01b815260040160405180910390fd5b6000821180156110f65750600e5461010090046001600160a01b031615155b1561111657600e546111169061010090046001600160a01b031683612376565b6000611124898b018b613644565b90506111717f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af31558761269f565b60208401518451604051637c2b6edb60e11b81526004810188905263ffffffff9092166024830152604482018190526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488116606484015260848301919091527f000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155169063f856ddb69060a4016020604051808303816000875af1158015611223573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611247919061378d565b6001600160401b031660408501526112a17f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155600061269f565b7f0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f816001600160a01b031663f7259a758560200151866000015187600001518e8e6040518663ffffffff1660e01b81526004016113019594939291906137df565b6020604051808303816000875af1158015611320573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611344919061378d565b6001600160401b03908116606086810182905260808088015185516040808b015181519716875260208701959095529385018a905291840187905283018590524260a08401521515918d91907f742fc5a2eb8bd42a536089d583f08bf52f3110072f62c20f54468cd81bc1815a9060c00160405180910390a45050505050505050505050565b6113d2612789565b610e2a60006127e9565b600a81815481106113ec57600080fd5b6000918252602090912001546001600160a01b0316905081565b6007818154811061141657600080fd5b600091825260209091200154905081565b61143033612057565b61144d57604051637c3ea23f60e01b815260040160405180910390fd5b611455612591565b610e2a612842565b61146633612057565b61148357604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b57368383838181106114a1576114a1613541565b90506040020190506114c981600001358260200160208101906114c49190613526565b61287f565b50806114d48161356d565b915050611486565b6114e533612057565b61150257604051637c3ea23f60e01b815260040160405180910390fd5b61150b81612930565b600580546001600160a01b0319166001600160a01b0383169081179091556040517f764166c557b419ae9f4bca81c505141ce7017b4bdb4c610ad113a50ec7e578a990600090a250565b61155e33612057565b61157b57604051637c3ea23f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa1580156115e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116069190613816565b604051630afd9fa560e31b81529091506001600160a01b037f0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f8116906357ecfd289061165b90899089908990899060040161382f565b6020604051808303816000875af115801561167a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169e9190613856565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816906370a0823190602401602060405180830381865afa158015611708573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172c9190613816565b6117369190613873565b905060008111801561175157506001600160a01b0383163014155b15611781576117817f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488483612404565b50505050505050565b6000611794612591565b336001600160a01b037f0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f8116146117dd576040516331e4d14960e01b815260040160405180910390fd5b63ffffffff85166000908152600d6020526040812054908590821580159061180d57506001600160a01b03821615155b801561183257506000838152600660205260409020546001600160a01b038381169116145b9050806118685760405162e3894560e01b8152600481018490526001600160a01b03831660248201526044015b60405180910390fd5b50600061187785870187613644565b601054600f549192506001600160a01b0390811691600091168214806118b2575082602001516001600160a01b0316826001600160a01b0316145b806118d257508260a001516001600160a01b0316826001600160a01b0316145b9050806118f25760405163460327af60e11b815260040160405180910390fd5b50506011546080820151511461191b5760405163ec8cb1df60e01b815260040160405180910390fd5b600080611929600454612963565b915091508161194b57604051636d0ea9b360e11b815260040160405180910390fd5b60055460405163032ad3cf60e51b81526001600160a01b039091169063655a79e09083906119819089908d908d90600401613886565b600060405180830381600088803b15801561199b57600080fd5b5087f11580156119af573d6000803e3d6000fd5b50505050506001955050505050505b949350505050565b6119ce612789565b6119e7600080516020613941833981519152838361298f565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b600080611a308484612682565b5098975050505050505050565b611a4633612057565b611a6357604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b576000838383818110611a8257611a82613541565b905060200201359050611a94816129bc565b5080611a9f8161356d565b915050611a66565b60606007805480602002602001604051908101604052809291908181526020018280548015610c2457602002820191906000526020600020905b815481526020019060010190808311611ae1575050505050905090565b611b0733612057565b611b2457604051637c3ea23f60e01b815260040160405180910390fd5b610de58282612a45565b611b3733612057565b611b5457604051637c3ea23f60e01b815260040160405180910390fd5b611b6e60008051602061394183398151915233600061298f565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b611ba433612057565b611bc157604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b576000838383818110611be057611be0613541565b905060200201359050468114611bf957611bf981612aac565b5080611c048161356d565b915050611bc4565b6060610c5960008051602061394183398151915261222b565b611c2d612591565b611c35612b0b565b333214611cb7576000600260095460ff166002811115611c5757611c5761315c565b1480611c935750600160095460ff166002811115611c7757611c7761315c565b148015611c935750336000908152600b602052604090205460ff165b905080611cb557604051630fa0970d60e11b815233600482015260240161185f565b505b6005546001600160a01b0316611ce05760405163bc864a6960e01b815260040160405180910390fd5b6000611d0b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48611f46565b905060007f0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f816001600160a01b03166357ecfd288b8b8b8b6040518563ffffffff1660e01b8152600401611d61949392919061382f565b6020604051808303816000875af1158015611d80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da49190613856565b905080611dc45760405163ecf5a8ff60e01b815260040160405180910390fd5b6040518060400160405280336001600160a01b0316815260200183611e087f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48611f46565b611e129190613873565b90528051601080546001600160a01b0319166001600160a01b03928316179055602090910151601155604051630afd9fa560e31b81526000917f0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f8116906357ecfd2890611e88908a908a908a908a9060040161382f565b6020604051808303816000875af1158015611ea7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ecb9190613856565b905080611eeb57604051631c2f23e960e21b815260040160405180910390fd5b5050601080546001600160a01b0319169055506000601155611f0d6001600355565b5050505050505050565b611f2033612057565b611f3d57604051637c3ea23f60e01b815260040160405180910390fd5b610c8d81612b64565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03831601611f74575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611fb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f1a9190613816565b919050565b611fe9612789565b6001600160a01b03811661204e5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161185f565b610c8d816127e9565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff16610f1a565b6120a033612057565b6120bd57604051637c3ea23f60e01b815260040160405180910390fd5b6009805482919060ff191660018360028111156120dc576120dc61315c565b02179055508060028111156120f3576120f361315c565b6040517f332a9f1d3bd9b0f7abbd95838fed6b417589632d0eb33f2d8ae6e2aa17178efd90600090a250565b61212833612057565b61214557604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610d8b573683838381811061216357612163613541565b905060400201905080602001602081019061217e91906138a9565b15612198576121986121936020830183613030565b612930565b6121c3600a600b6121ac6020850185613030565b6121bc60408601602087016138a9565b6064612bb6565b506121d460408201602083016138a9565b15156121e36020830183613030565b6001600160a01b03167f1470aed653fa8a8ce4c7b2f41287634199f7ec3c4f5fd0ace97d82cf006beec360405160405180910390a350806122238161356d565b915050612148565b60008181526001602090815260409182902080548351818402810184019094528084526060939283018282801561228b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161226d575b50505050509050919050565b600f80546001600160a01b0319166001600160a01b0383169081179091556040517f23f86a3e9ecbe238d0d1110e33eeec3ca6121dfd07f56ec10fdbf8aee36cdd3790600090a250565b81600003612302576040516381e7376360e01b815260040160405180910390fd5b6001600160a01b03811661232957604051633efa09af60e01b815260040160405180910390fd5b61233b60066007600885856064612be3565b506040516001600160a01b0382169083907f357d1ebd1dc0d53cc15161206b9a39c9ca30667bd997cf921eb00e4c78a454f590600090a35050565b604080516000808252602082019092526001600160a01b0384169083906040516123a091906138c6565b60006040518083038185875af1925050503d80600081146123dd576040519150601f19603f3d011682016040523d82523d6000602084013e6123e2565b606091505b5050905080610d8b57604051632e05b05360e21b815260040160405180910390fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161246091906138c6565b6000604051808303816000865af19150503d806000811461249d576040519150601f19603f3d011682016040523d82523d6000602084013e6124a2565b606091505b509150915060008280156124ce5750815115806124ce5750818060200190518101906124ce9190613856565b9050806124ee57604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b60005460ff16610e2a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161185f565b6125476124f6565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60005460ff1615610e2a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161185f565b60048190556040518181527fec9e8f9ec7dd2c5310e5b87c7bedeb6ba1c5943cb4d2da1ee80335508a5bc5a49060200160405180910390a150565b6000818152600660205260408120546001600160a01b031680610f1a57604051631a81634560e01b815260040160405180910390fd5b6000818152600c60205260408120805460ff166126785760405163731da1e960e11b815260040160405180910390fd5b6001015492915050565b60008080612692848601866138f5565b9250925092509250925092565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b17905291516000928392908716916126fb91906138c6565b6000604051808303816000865af19150503d8060008114612738576040519150601f19603f3d011682016040523d82523d6000602084013e61273d565b606091505b509150915060008280156127695750815115806127695750818060200190518101906127699190613856565b9050806124ee5760405163b45d44e760e01b815260040160405180910390fd5b6000546001600160a01b03610100909104163314610e2a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161185f565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b61284a612591565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586125743390565b6000828152600c60205260409020805460ff16156128b257600181015463ffffffff166000908152600d60205260408120555b604080518082018252600180825263ffffffff851660208084018281526000898152600c83528681209551865460ff191690151517865590519490930193909355808252600d9092528281208690559151909185917f55fdf4a71f93ff89177262ca6b1cfa79f18f4425d1b8e928bb2ef7a18883a33c9190a3505050565b6001600160a01b0381163b610c8d57604051638c50d7cd60e01b81526001600160a01b038216600482015260240161185f565b60008060005a90508381101592508261297d576000612987565b6129878482613873565b915050915091565b600083815260016020908152604080832060029092529091206129b6919084846064612bb6565b50505050565b6000818152600c60205260408120805490919060ff16156129f45750600181015463ffffffff81166000908152600d60205260408120555b6000838152600c6020526040808220805460ff191681556001018290555163ffffffff83169185917ff79bac28779a4bff7a04c8f64491c5be344a30648bb4539212da26244b0a6e1a9190a3505050565b612a707fab6730ecea49587e6c50637868078921bc389a6c228c95e1c7259ae5a61c2174838361298f565b604051811515906001600160a01b038416907fc6b049f4dc9561b397b0cef913ea5f18165b682b193be62c0bbbf9ca8763aeba90600090a35050565b80600003612acd576040516381e7376360e01b815260040160405180910390fd5b612adc60066007600884612c3f565b5060405181907feb39225b53386d0eb02af9cf2c6b6a0c345a97654f1e67fb21b0b5aaac81ec4a90600090a250565b600260035403612b5d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161185f565b6002600355565b600e8054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517f9113819388a87769f8958d74097d68f96e457d5bc25f0168a8ffb3d3a55672a390600090a250565b600082612bcd57612bc8868686612c87565b612bd9565b612bd986868685612daf565b9695505050505050565b60008381526020859052604090205460ff16158015612c0a57612c0886868685612e5f565b505b600093845260209690965250604090912080546001600160a01b0319166001600160a01b039092169190911790555090919050565b60008181526020839052604090205460ff1680156119be57600082815260208690526040902080546001600160a01b0319169055612c7e848484612ee8565b50949350505050565b6001600160a01b0381166000908152602083905260409020805460ff16908115612da75760018082015486549091600091612cc29190613873565b9050808214612d4f576000878281548110612cdf57612cdf613541565b9060005260206000200160009054906101000a90046001600160a01b0316905080888481548110612d1257612d12613541565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b86805480612d5f57612d5f61392a565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff161580156119be5784548211612df35760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b039790971660008181529888529388209251835460ff19169015151783555191810191909155865490810187559585529290932090930180546001600160a01b0319169091179055919050565b60008281526020849052604090205460ff161580156119be5784548211612e995760405163b1655e3360e01b815260040160405180910390fd5b60408051808201825260018082528754602080840191825260008881529881529388209251835460ff191690151517835551918101919091558654908101875595855290932090930155919050565b6000818152602083905260409020805460ff16908115612da75760018082015486549091600091612f199190613873565b9050808214612f78576000878281548110612f3657612f36613541565b9060005260206000200154905080888481548110612f5657612f56613541565b6000918252602080832090910192909255918252879052604090206001018290555b86805480612f8857612f8861392a565b60008281526020808220830160001990810183905590920190925586825287905260408120805460ff19168155600101555050509392505050565b6020808252825182820181905260009190848201906040850190845b818110156130045783516001600160a01b031683529284019291840191600101612fdf565b50909695505050505050565b6001600160a01b0381168114610c8d57600080fd5b8035611fdc81613010565b60006020828403121561304257600080fd5b813561304d81613010565b9392505050565b60008083601f84011261306657600080fd5b5081356001600160401b0381111561307d57600080fd5b6020830191508360208260061b850101111561309857600080fd5b9250929050565b600080602083850312156130b257600080fd5b82356001600160401b038111156130c857600080fd5b6130d485828601613054565b90969095509350505050565b600080604083850312156130f357600080fd5b82356130fe81613010565b946020939093013593505050565b8015158114610c8d57600080fd5b60008060006060848603121561312f57600080fd5b83359250602084013561314181613010565b915060408401356131518161310c565b809150509250925092565b634e487b7160e01b600052602160045260246000fd5b602081016003831061319457634e487b7160e01b600052602160045260246000fd5b91905290565b6000602082840312156131ac57600080fd5b5035919050565b60008083601f8401126131c557600080fd5b5081356001600160401b038111156131dc57600080fd5b60208301915083602082850101111561309857600080fd5b60008060008060006060868803121561320c57600080fd5b8535945060208601356001600160401b038082111561322a57600080fd5b61323689838a016131b3565b9096509450604088013591508082111561324f57600080fd5b5061325c888289016131b3565b969995985093965092949392505050565b60008060008060006060868803121561328557600080fd5b85356001600160401b038082111561329c57600080fd5b6132a889838a016131b3565b909750955060208801359150808211156132c157600080fd5b506132ce888289016131b3565b90945092505060408601356132e281613010565b809150509295509295909350565b803563ffffffff81168114611fdc57600080fd5b6000806000806060858703121561331a57600080fd5b613323856132f0565b93506020850135925060408501356001600160401b0381111561334557600080fd5b613351878288016131b3565b95989497509550505050565b6000806040838503121561337057600080fd5b823561337b81613010565b9150602083013561338b8161310c565b809150509250929050565b600080602083850312156133a957600080fd5b82356001600160401b03808211156133c057600080fd5b818501915085601f8301126133d457600080fd5b8135818111156133e357600080fd5b8660208260051b85010111156133f857600080fd5b60209290920196919550909350505050565b6020808252825182820181905260009190848201906040850190845b8181101561300457835183529284019291840191600101613426565b6000806000806000806000806080898b03121561345e57600080fd5b88356001600160401b038082111561347557600080fd5b6134818c838d016131b3565b909a50985060208b013591508082111561349a57600080fd5b6134a68c838d016131b3565b909850965060408b01359150808211156134bf57600080fd5b6134cb8c838d016131b3565b909650945060608b01359150808211156134e457600080fd5b506134f18b828c016131b3565b999c989b5096995094979396929594505050565b60006020828403121561351757600080fd5b81356003811061304d57600080fd5b60006020828403121561353857600080fd5b61304d826132f0565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006001820161357f5761357f613557565b5060010190565b6000806040838503121561359957600080fd5b82516135a481613010565b6020939093015192949293505050565b634e487b7160e01b600052604160045260246000fd5b60405160c081016001600160401b03811182821017156135ec576135ec6135b4565b60405290565b604051606081016001600160401b03811182821017156135ec576135ec6135b4565b604051601f8201601f191681016001600160401b038111828210171561363c5761363c6135b4565b604052919050565b6000602080838503121561365757600080fd5b82356001600160401b038082111561366e57600080fd5b9084019060c0828703121561368257600080fd5b61368a6135ca565b823581528383013561369b81613010565b818501526040838101359082015260608301356136b781613010565b60608201526080830135828111156136ce57600080fd5b8301606081890312156136e057600080fd5b6136e86135f2565b81358152858201358682015260408201358481111561370657600080fd5b80830192505088601f83011261371b57600080fd5b81358481111561372d5761372d6135b4565b61373f601f8201601f19168801613614565b9450808552898782850101111561375557600080fd5b808784018887013760009085018701526040810184905260808301525061377e60a08401613025565b60a08201529695505050505050565b60006020828403121561379f57600080fd5b81516001600160401b038116811461304d57600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b63ffffffff8616815284602082015283604082015260806060820152600061380b6080830184866137b6565b979650505050505050565b60006020828403121561382857600080fd5b5051919050565b6040815260006138436040830186886137b6565b828103602084015261380b8185876137b6565b60006020828403121561386857600080fd5b815161304d8161310c565b81810381811115610f1a57610f1a613557565b8381526040602082015260006138a06040830184866137b6565b95945050505050565b6000602082840312156138bb57600080fd5b813561304d8161310c565b6000825160005b818110156138e757602081860181015185830152016138cd565b506000920191825250919050565b60008060006060848603121561390a57600080fd5b83356139158161310c565b95602085013595506040909401359392505050565b634e487b7160e01b600052603160045260246000fdfe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa2646970667358221220910caf4033a37ee4941c3ef69ed6e07b97ef76d851c041e7ead9d01de20c62b764736f6c63430008130033

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

000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af31550000000000000000000000000a992d191deec32afe36203ad87d7d289a738f810000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000271000000000000000000000000054c28fdd59025942fe71545de8c6358c30b3a16a00000000000000000000000054c28fdd59025942fe71545de8c6358c30b3a16a00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000a4b10000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000a86a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000006741a38adbd040e9e1a8a9c78ba52987e56a3e78

-----Decoded View---------------
Arg [0] : _cctpTokenMessenger (address): 0xBd3fa81B58Ba92a82136038B25aDec7066af3155
Arg [1] : _cctpMessageTransmitter (address): 0x0a992d191DEeC32aFe36203Ad87D7d289a738F81
Arg [2] : _chainDomains (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [3] : _asset (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [4] : _variableRepaymentEnabled (bool): True
Arg [5] : _targetGasReserve (uint256): 10000
Arg [6] : _processingFeeCollector (address): 0x54C28fDD59025942Fe71545DE8c6358c30b3a16A
Arg [7] : _targetExecutor (address): 0x54C28fDD59025942Fe71545DE8c6358c30b3a16A
Arg [8] : _owner (address): 0x72E28c7F34100AfefC399fcc0AE041B8fe5841AE
Arg [9] : _managers (address[]): 0x6741a38ADBd040e9e1a8A9C78bA52987e56a3e78
Arg [10] : _addOwnerToManagers (bool): True

-----Encoded View---------------
18 Constructor Arguments found :
Arg [0] : 000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155
Arg [1] : 0000000000000000000000000a992d191deec32afe36203ad87d7d289a738f81
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [3] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [5] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [6] : 00000000000000000000000054c28fdd59025942fe71545de8c6358c30b3a16a
Arg [7] : 00000000000000000000000054c28fdd59025942fe71545de8c6358c30b3a16a
Arg [8] : 00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [12] : 000000000000000000000000000000000000000000000000000000000000a4b1
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [14] : 000000000000000000000000000000000000000000000000000000000000a86a
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [17] : 0000000000000000000000006741a38adbd040e9e1a8a9c78ba52987e56a3e78


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.