ETH Price: $3,297.95 (+0.56%)

Contract

0x99B5FA03a5ea4315725c43346e55a6A6fbd94098
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
183899662023-10-20 7:11:35457 days ago1697785895  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AxelarGateway

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
london EvmVersion
File 1 of 22 : AxelarGateway.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
import { IImplementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IImplementation.sol';
import { IContractIdentifier } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol';
import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol';
import { SafeTokenCall, SafeTokenTransfer, SafeTokenTransferFrom } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';
import { ContractAddress } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/ContractAddress.sol';
import { Implementation } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/upgradable/Implementation.sol';

import { IAxelarAuth } from './interfaces/IAxelarAuth.sol';
import { IBurnableMintableCappedERC20 } from './interfaces/IBurnableMintableCappedERC20.sol';
import { ITokenDeployer } from './interfaces/ITokenDeployer.sol';

import { ECDSA } from './ECDSA.sol';
import { DepositHandler } from './DepositHandler.sol';
import { EternalStorage } from './EternalStorage.sol';

/**
 * @title AxelarGateway Contract
 * @notice This contract serves as the gateway for cross-chain contract calls,
 * and token transfers within the Axelar network.
 * It includes functions for sending tokens, calling contracts, and validating contract calls.
 * The contract is managed via the decentralized governance mechanism on the Axelar network.
 * @dev EternalStorage is used to simplify storage for upgradability, and InterchainGovernance module is used for governance.
 */
contract AxelarGateway is IAxelarGateway, Implementation, EternalStorage {
    using SafeTokenCall for IERC20;
    using SafeTokenTransfer for IERC20;
    using SafeTokenTransferFrom for IERC20;
    using ContractAddress for address;

    error InvalidImplementation();

    enum TokenType {
        InternalBurnable,
        InternalBurnableFrom,
        External
    }

    /**
     * @dev Deprecated slots. Should not be reused.
     */
    // bytes32 internal constant KEY_ALL_TOKENS_FROZEN = keccak256('all-tokens-frozen');
    // bytes32 internal constant PREFIX_TOKEN_FROZEN = keccak256('token-frozen');

    /**
     * @dev Storage slot with the address of the current implementation. `keccak256('eip1967.proxy.implementation') - 1`.
     */
    bytes32 internal constant KEY_IMPLEMENTATION = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc);

    /**
     * @dev Storage slot with the address of the current governance. keccak256('governance')) - 1
     */
    bytes32 internal constant KEY_GOVERNANCE = bytes32(0xabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909);

    /**
     * @dev Storage slot with the address of the current mint limiter. keccak256('mint-limiter')) - 1
     */
    bytes32 internal constant KEY_MINT_LIMITER = bytes32(0x627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92);

    bytes32 internal constant PREFIX_COMMAND_EXECUTED = keccak256('command-executed');
    bytes32 internal constant PREFIX_TOKEN_ADDRESS = keccak256('token-address');
    bytes32 internal constant PREFIX_TOKEN_TYPE = keccak256('token-type');
    bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED = keccak256('contract-call-approved');
    bytes32 internal constant PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT = keccak256('contract-call-approved-with-mint');
    bytes32 internal constant PREFIX_TOKEN_MINT_LIMIT = keccak256('token-mint-limit');
    bytes32 internal constant PREFIX_TOKEN_MINT_AMOUNT = keccak256('token-mint-amount');

    bytes32 internal constant SELECTOR_BURN_TOKEN = keccak256('burnToken');
    bytes32 internal constant SELECTOR_DEPLOY_TOKEN = keccak256('deployToken');
    bytes32 internal constant SELECTOR_MINT_TOKEN = keccak256('mintToken');
    bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL = keccak256('approveContractCall');
    bytes32 internal constant SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT = keccak256('approveContractCallWithMint');
    bytes32 internal constant SELECTOR_TRANSFER_OPERATORSHIP = keccak256('transferOperatorship');

    address public immutable authModule;
    address public immutable tokenDeployer;

    /**
     * @notice Constructs the AxelarGateway contract.
     * @param authModule_ The address of the authentication module
     * @param tokenDeployer_ The address of the token deployer
     */
    constructor(address authModule_, address tokenDeployer_) {
        if (authModule_.code.length == 0) revert InvalidAuthModule();
        if (tokenDeployer_.code.length == 0) revert InvalidTokenDeployer();

        authModule = authModule_;
        tokenDeployer = tokenDeployer_;
    }

    /**
     * @notice Ensures that the caller of the function is the gateway contract itself.
     */
    modifier onlySelf() {
        if (msg.sender != address(this)) revert NotSelf();

        _;
    }

    /**
     * @notice Ensures that the caller of the function is the governance address.
     */
    modifier onlyGovernance() {
        if (msg.sender != getAddress(KEY_GOVERNANCE)) revert NotGovernance();

        _;
    }

    /**
     * @notice Ensures that the caller of the function is either the mint limiter or governance.
     */
    modifier onlyMintLimiter() {
        if (msg.sender != getAddress(KEY_MINT_LIMITER) && msg.sender != getAddress(KEY_GOVERNANCE)) revert NotMintLimiter();

        _;
    }

    /******************\
    |* Public Methods *|
    \******************/

    /**
     * @notice Send the specified token to the destination chain and address.
     * @param destinationChain The chain to send tokens to. A registered chain name on Axelar must be used here
     * @param destinationAddress The address on the destination chain to send tokens to
     * @param symbol The symbol of the token to send
     * @param amount The amount of tokens to send
     */
    function sendToken(
        string calldata destinationChain,
        string calldata destinationAddress,
        string calldata symbol,
        uint256 amount
    ) external {
        _burnTokenFrom(msg.sender, symbol, amount);
        emit TokenSent(msg.sender, destinationChain, destinationAddress, symbol, amount);
    }

    /**
     * @notice Calls a contract on the specified destination chain with a given payload.
     * This function is the entry point for general message passing between chains.
     * @param destinationChain The chain where the destination contract exists. A registered chain name on Axelar must be used here
     * @param destinationContractAddress The address of the contract to call on the destination chain
     * @param payload The payload to be sent to the destination contract, usually representing an encoded function call with arguments
     */
    function callContract(
        string calldata destinationChain,
        string calldata destinationContractAddress,
        bytes calldata payload
    ) external {
        emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload);
    }

    /**
     * @notice Calls a contract on the specified destination chain with a given payload and token amount.
     * This function is the entry point for general message passing with token transfer between chains.
     * @param destinationChain The chain where the destination contract exists. A registered chain name on Axelar must be used here
     * @param destinationContractAddress The address of the contract to call with tokens on the destination chain
     * @param payload The payload to be sent to the destination contract, usually representing an encoded function call with arguments
     * @param symbol The symbol of the token to be sent with the call
     * @param amount The amount of tokens to be sent with the call
     */
    function callContractWithToken(
        string calldata destinationChain,
        string calldata destinationContractAddress,
        bytes calldata payload,
        string calldata symbol,
        uint256 amount
    ) external {
        _burnTokenFrom(msg.sender, symbol, amount);
        emit ContractCallWithToken(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload, symbol, amount);
    }

    /**
     * @notice Checks whether a contract call has been approved by the gateway.
     * @param commandId The gateway command ID
     * @param sourceChain The source chain of the contract call
     * @param sourceAddress The source address of the contract call
     * @param contractAddress The contract address that will be called
     * @param payloadHash The hash of the payload for that will be sent with the call
     * @return bool A boolean value indicating whether the contract call has been approved by the gateway.
     */
    function isContractCallApproved(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        address contractAddress,
        bytes32 payloadHash
    ) external view override returns (bool) {
        return getBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash));
    }

    /**
     * @notice Checks whether a contract call with token has been approved by the gateway.
     * @param commandId The gateway command ID
     * @param sourceChain The source chain of the contract call
     * @param sourceAddress The source address of the contract call
     * @param contractAddress The contract address that will be called, and where tokens will be sent
     * @param payloadHash The hash of the payload for that will be sent with the call
     * @param symbol The symbol of the token to be sent with the call
     * @param amount The amount of tokens to be sent with the call
     * @return bool A boolean value indicating whether the contract call with token has been approved by the gateway.
     */
    function isContractCallAndMintApproved(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        address contractAddress,
        bytes32 payloadHash,
        string calldata symbol,
        uint256 amount
    ) external view override returns (bool) {
        return
            getBool(
                _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount)
            );
    }

    /**
     * @notice Called on the destination chain gateway by the recipient of the cross-chain contract call to validate it and only allow execution
     * if this function returns true.
     * @dev Once validated, the gateway marks the message as executed so the contract call is not executed twice.
     * @param commandId The gateway command ID
     * @param sourceChain The source chain of the contract call
     * @param sourceAddress The source address of the contract call
     * @param payloadHash The hash of the payload for that will be sent with the call
     * @return valid True if the contract call is approved, false otherwise
     */
    function validateContractCall(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes32 payloadHash
    ) external override returns (bool valid) {
        bytes32 key = _getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash);
        valid = getBool(key);
        if (valid) {
            _setBool(key, false);

            emit ContractCallExecuted(commandId);
        }
    }

    /**
     * @notice Called on the destination chain gateway to validate the approval of a contract call with token transfer and only
     * allow execution if this function returns true.
     * @dev Once validated, the gateway marks the message as executed so the contract call with token is not executed twice.
     * @param commandId The gateway command ID
     * @param sourceChain The source chain of the contract call
     * @param sourceAddress The source address of the contract call
     * @param payloadHash The hash of the payload for that will be sent with the call
     * @param symbol The symbol of the token to be sent with the call
     * @param amount The amount of tokens to be sent with the call
     * @return valid True if the contract call with token is approved, false otherwise
     */
    function validateContractCallAndMint(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes32 payloadHash,
        string calldata symbol,
        uint256 amount
    ) external override returns (bool valid) {
        bytes32 key = _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, msg.sender, payloadHash, symbol, amount);
        valid = getBool(key);
        if (valid) {
            // Prevent re-entrancy
            _setBool(key, false);

            emit ContractCallExecuted(commandId);

            _mintToken(symbol, msg.sender, amount);
        }
    }

    /***********\
    |* Getters *|
    \***********/

    /**
     * @notice Gets the address of governance, should be the address of InterchainGovernance.
     * @return address The address of governance.
     */
    function governance() public view override returns (address) {
        return getAddress(KEY_GOVERNANCE);
    }

    /**
     * @notice Gets the address of the mint limiter, should be the address of Multisig.
     * @return address The address of the mint limiter.
     */
    function mintLimiter() public view override returns (address) {
        return getAddress(KEY_MINT_LIMITER);
    }

    /**
     * @notice Gets the transfer limit for a specific token symbol within the configured epoch.
     * @param symbol The symbol of the token
     * @return uint The transfer limit for the given token.
     */
    function tokenMintLimit(string memory symbol) public view override returns (uint256) {
        return getUint(_getTokenMintLimitKey(symbol));
    }

    /**
     * @notice Gets the transfer amount for a specific token symbol within the configured epoch.
     * @param symbol The symbol of the token
     * @return uint The transfer amount for the given token.
     */
    function tokenMintAmount(string memory symbol) public view override returns (uint256) {
        return getUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours));
    }

    /**
     * @dev This function is kept around to keep things working for internal
     * tokens that were deployed before the token freeze functionality was removed
     */
    function allTokensFrozen() external pure override returns (bool) {
        return false;
    }

    /**
     * @notice Gets the address of the gateway implementation contract.
     * @return address The address of the gateway implementation.
     */
    function implementation() public view override returns (address) {
        return getAddress(KEY_IMPLEMENTATION);
    }

    /**
     * @notice Gets the address of a specific token using its symbol.
     * @param symbol The symbol of the token
     * @return address The address of the token associated with the given symbol.
     */
    function tokenAddresses(string memory symbol) public view override returns (address) {
        return getAddress(_getTokenAddressKey(symbol));
    }

    /**
     * @dev Deprecated. This function is kept around to keep things working for internal tokens that were deployed before the token freeze functionality was removed
     */
    function tokenFrozen(string memory) external pure override returns (bool) {
        return false;
    }

    /**
     * @notice Checks whether a command with a given command ID has been executed.
     * @param commandId The command ID to check
     * @return bool True if the command has been executed, false otherwise
     */
    function isCommandExecuted(bytes32 commandId) public view override returns (bool) {
        return getBool(_getIsCommandExecutedKey(commandId));
    }

    /**
     * @notice Gets the contract ID of the Axelar Gateway.
     * @return bytes32 The keccak256 hash of the string 'axelar-gateway'
     */
    function contractId() public pure returns (bytes32) {
        return keccak256('axelar-gateway');
    }

    /************************\
    |* Governance Functions *|
    \************************/

    /**
     * @notice Transfers the governance role to a new address.
     * @param newGovernance The address to transfer the governance role to.
     * @dev Only the current governance entity can call this function.
     */
    function transferGovernance(address newGovernance) external override onlyGovernance {
        if (newGovernance == address(0)) revert InvalidGovernance();

        _transferGovernance(newGovernance);
    }

    /**
     * @notice Transfers the mint limiter role to a new address.
     * @param newMintLimiter The address to transfer the mint limiter role to.
     * @dev Only the current mint limiter or the governance address can call this function.
     */
    function transferMintLimiter(address newMintLimiter) external override onlyMintLimiter {
        if (newMintLimiter == address(0)) revert InvalidMintLimiter();

        _transferMintLimiter(newMintLimiter);
    }

    /**
     * @notice Sets the transfer limits for an array of tokens.
     * @param symbols The array of token symbols to set the transfer limits for
     * @param limits The array of transfer limits corresponding to the symbols
     * @dev Only the mint limiter or the governance address can call this function.
     */
    function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external override onlyMintLimiter {
        uint256 length = symbols.length;
        if (length != limits.length) revert InvalidSetMintLimitsParams();

        for (uint256 i; i < length; ++i) {
            string memory symbol = symbols[i];
            uint256 limit = limits[i];

            if (tokenAddresses(symbol) == address(0)) revert TokenDoesNotExist(symbol);

            _setTokenMintLimit(symbol, limit);
        }
    }

    /**
     * @notice Upgrades the contract to a new implementation.
     * @param newImplementation The address of the new implementation
     * @param newImplementationCodeHash The code hash of the new implementation
     * @param setupParams Optional setup params for the new implementation
     * @dev Only the governance address can call this function.
     */
    function upgrade(
        address newImplementation,
        bytes32 newImplementationCodeHash,
        bytes calldata setupParams
    ) external override onlyGovernance {
        if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash();

        if (contractId() != IContractIdentifier(newImplementation).contractId()) revert InvalidImplementation();

        emit Upgraded(newImplementation);

        _setImplementation(newImplementation);

        if (setupParams.length != 0) {
            // slither-disable-next-line controlled-delegatecall
            (bool success, ) = newImplementation.delegatecall(abi.encodeWithSelector(IImplementation.setup.selector, setupParams));

            if (!success) revert SetupFailed();
        }
    }

    /**********************\
    |* External Functions *|
    \**********************/

    /**
     * @notice Sets up the governance and mint limiter roles, and transfers operatorship if necessary.
     * This function is called by the proxy during initial deployment, and optionally called during gateway upgrades.
     * @param params The encoded parameters containing the governance and mint limiter addresses, as well as the new operator data.
     * @dev Not publicly accessible as it's overshadowed in the proxy.
     */
    function setup(bytes calldata params) external override(IImplementation, Implementation) onlyProxy {
        (address governance_, address mintLimiter_, bytes memory newOperatorsData) = abi.decode(params, (address, address, bytes));

        if (governance_ != address(0)) _transferGovernance(governance_);
        if (mintLimiter_ != address(0)) _transferMintLimiter(mintLimiter_);

        if (newOperatorsData.length != 0) {
            emit OperatorshipTransferred(newOperatorsData);

            IAxelarAuth(authModule).transferOperatorship(newOperatorsData);
        }
    }

    /**
     * @notice Executes a batch of commands signed by the Axelar network. There are a finite set of command types that can be executed.
     * @param input The encoded input containing the data for the batch of commands, as well as the proof that verifies the integrity of the data.
     * @dev Each command has a corresponding commandID that is guaranteed to be unique from the Axelar network.
     * @dev This function allows retrying a commandID if the command initially failed to be processed.
     * @dev Ignores unknown commands or duplicate commandIDs.
     * @dev Emits an Executed event for successfully executed commands.
     */
    // slither-disable-next-line cyclomatic-complexity
    function execute(bytes calldata input) external override {
        (bytes memory data, bytes memory proof) = abi.decode(input, (bytes, bytes));

        bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(data));

        // returns true for current operators
        // slither-disable-next-line reentrancy-no-eth
        bool allowOperatorshipTransfer = IAxelarAuth(authModule).validateProof(messageHash, proof);

        uint256 chainId;
        bytes32[] memory commandIds;
        string[] memory commands;
        bytes[] memory params;

        (chainId, commandIds, commands, params) = abi.decode(data, (uint256, bytes32[], string[], bytes[]));

        if (chainId != block.chainid) revert InvalidChainId();

        uint256 commandsLength = commandIds.length;

        if (commandsLength != commands.length || commandsLength != params.length) revert InvalidCommands();

        for (uint256 i; i < commandsLength; ++i) {
            bytes32 commandId = commandIds[i];

            // Ignore if duplicate commandId received
            if (isCommandExecuted(commandId)) continue;

            bytes4 commandSelector;
            bytes32 commandHash = keccak256(abi.encodePacked(commands[i]));

            if (commandHash == SELECTOR_DEPLOY_TOKEN) {
                commandSelector = AxelarGateway.deployToken.selector;
            } else if (commandHash == SELECTOR_MINT_TOKEN) {
                commandSelector = AxelarGateway.mintToken.selector;
            } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL) {
                commandSelector = AxelarGateway.approveContractCall.selector;
            } else if (commandHash == SELECTOR_APPROVE_CONTRACT_CALL_WITH_MINT) {
                commandSelector = AxelarGateway.approveContractCallWithMint.selector;
            } else if (commandHash == SELECTOR_BURN_TOKEN) {
                commandSelector = AxelarGateway.burnToken.selector;
            } else if (commandHash == SELECTOR_TRANSFER_OPERATORSHIP) {
                if (!allowOperatorshipTransfer) continue;

                allowOperatorshipTransfer = false;
                commandSelector = AxelarGateway.transferOperatorship.selector;
            } else {
                // Ignore unknown commands
                continue;
            }

            // Prevent a re-entrancy from executing this command before it can be marked as successful.
            _setCommandExecuted(commandId, true);

            // slither-disable-next-line calls-loop,reentrancy-no-eth
            (bool success, ) = address(this).call(abi.encodeWithSelector(commandSelector, params[i], commandId));

            // slither-disable-next-line reentrancy-events
            if (success) emit Executed(commandId);
            else _setCommandExecuted(commandId, false);
        }
    }

    /******************\
    |* Self Functions *|
    \******************/

    /**
     * @notice Deploys a new token or registers an existing token in the gateway contract itself.
     * @param params Encoded parameters including the token name, symbol, decimals, cap, token address, and mint limit
     * @dev If the token address is not specified, a new token is deployed and registed as InternalBurnableFrom
     * @dev If the token address is specified, the token is marked as External.
     * @dev Emits a TokenDeployed event with the symbol and token address.
     */
    function deployToken(bytes calldata params, bytes32) external onlySelf {
        (string memory name, string memory symbol, uint8 decimals, uint256 cap, address tokenAddress, uint256 mintLimit) = abi.decode(
            params,
            (string, string, uint8, uint256, address, uint256)
        );

        // Ensure that this symbol has not been taken.
        if (tokenAddresses(symbol) != address(0)) revert TokenAlreadyExists(symbol);

        _setTokenMintLimit(symbol, mintLimit);

        if (tokenAddress == address(0)) {
            // If token address is not specified, it indicates a request to deploy one.
            bytes32 salt = keccak256(abi.encodePacked(symbol));

            _setTokenType(symbol, TokenType.InternalBurnableFrom);

            // slither-disable-next-line reentrancy-no-eth,controlled-delegatecall
            (bool success, bytes memory data) = tokenDeployer.delegatecall(
                abi.encodeWithSelector(ITokenDeployer.deployToken.selector, name, symbol, decimals, cap, salt)
            );

            if (!success) revert TokenDeployFailed(symbol);

            tokenAddress = abi.decode(data, (address));
        } else {
            // If token address is specified, ensure that there is a contact at the specified address.
            if (tokenAddress.code.length == uint256(0)) revert TokenContractDoesNotExist(tokenAddress);

            // Mark that this symbol is an external token, which is needed to differentiate between operations on mint and burn.
            _setTokenType(symbol, TokenType.External);
        }

        // slither-disable-next-line reentrancy-events
        emit TokenDeployed(symbol, tokenAddress);

        _setTokenAddress(symbol, tokenAddress);
    }

    /**
     * @notice Transfers a specific amount of tokens to an account, based on the provided symbol.
     * @param params Encoded parameters including the token symbol, recipient address, and amount to mint.
     * @dev This function will revert if the token is not registered with the gatewaty.
     * @dev If the token type is External, a safe transfer is performed to the recipient account.
     * @dev If the token type is Internal (InternalBurnable or InternalBurnableFrom), the mint function is called on the token address.
     */
    function mintToken(bytes calldata params, bytes32) external onlySelf {
        (string memory symbol, address account, uint256 amount) = abi.decode(params, (string, address, uint256));

        _mintToken(symbol, account, amount);
    }

    /**
     * @notice Burns tokens of a given symbol, either through an external deposit handler or a token defined burn method.
     * @param params Encoded parameters including the token symbol and a salt value for the deposit handler
     */
    function burnToken(bytes calldata params, bytes32) external onlySelf {
        (string memory symbol, bytes32 salt) = abi.decode(params, (string, bytes32));

        address tokenAddress = tokenAddresses(symbol);

        if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);

        if (_getTokenType(symbol) == TokenType.External) {
            address depositHandlerAddress = _getCreate2Address(salt, keccak256(abi.encodePacked(type(DepositHandler).creationCode)));

            if (depositHandlerAddress.isContract()) return;

            DepositHandler depositHandler = new DepositHandler{ salt: salt }();

            (bool success, bytes memory returnData) = depositHandler.execute(
                tokenAddress,
                abi.encodeWithSelector(IERC20.transfer.selector, address(this), IERC20(tokenAddress).balanceOf(address(depositHandler)))
            );

            if (!success || (returnData.length != uint256(0) && !abi.decode(returnData, (bool)))) revert BurnFailed(symbol);

            // NOTE: `depositHandler` must always be destroyed in the same runtime context that it is deployed.
            depositHandler.destroy(address(this));
        } else {
            IBurnableMintableCappedERC20(tokenAddress).burn(salt);
        }
    }

    /**
     * @notice Approves a contract call.
     * @param params Encoded parameters including the source chain, source address, contract address, payload hash, transaction hash, and event index
     * @param commandId to associate with the approval
     */
    function approveContractCall(bytes calldata params, bytes32 commandId) external onlySelf {
        (
            string memory sourceChain,
            string memory sourceAddress,
            address contractAddress,
            bytes32 payloadHash,
            bytes32 sourceTxHash,
            uint256 sourceEventIndex
        ) = abi.decode(params, (string, string, address, bytes32, bytes32, uint256));

        _setContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash);
        emit ContractCallApproved(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, sourceTxHash, sourceEventIndex);
    }

    /**
     * @notice Approves a contract call with token transfer.
     * @param params Encoded parameters including the source chain, source address, contract address, payload hash, token symbol,
     * token amount, transaction hash, and event index.
     * @param commandId to associate with the approval
     */
    function approveContractCallWithMint(bytes calldata params, bytes32 commandId) external onlySelf {
        (
            string memory sourceChain,
            string memory sourceAddress,
            address contractAddress,
            bytes32 payloadHash,
            string memory symbol,
            uint256 amount,
            bytes32 sourceTxHash,
            uint256 sourceEventIndex
        ) = abi.decode(params, (string, string, address, bytes32, string, uint256, bytes32, uint256));

        _setContractCallApprovedWithMint(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount);
        emit ContractCallApprovedWithMint(
            commandId,
            sourceChain,
            sourceAddress,
            contractAddress,
            payloadHash,
            symbol,
            amount,
            sourceTxHash,
            sourceEventIndex
        );
    }

    /**
     * @notice Transfers operatorship with the provided data by calling the transferOperatorship function on the auth module.
     * @param newOperatorsData Encoded data for the new operators
     */
    function transferOperatorship(bytes calldata newOperatorsData, bytes32) external onlySelf {
        emit OperatorshipTransferred(newOperatorsData);

        IAxelarAuth(authModule).transferOperatorship(newOperatorsData);
    }

    /********************\
    |* Internal Methods *|
    \********************/

    function _mintToken(
        string memory symbol,
        address account,
        uint256 amount
    ) internal {
        address tokenAddress = tokenAddresses(symbol);

        if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);

        _setTokenMintAmount(symbol, tokenMintAmount(symbol) + amount);

        if (_getTokenType(symbol) == TokenType.External) {
            IERC20(tokenAddress).safeTransfer(account, amount);
        } else {
            IBurnableMintableCappedERC20(tokenAddress).mint(account, amount);
        }
    }

    /**
     * @notice Burns or locks a specific amount of tokens from a sender's account based on the provided symbol.
     * @param sender Address of the account from which to burn the tokens
     * @param symbol Symbol of the token to burn
     * @param amount Amount of tokens to burn
     * @dev Depending on the token type (External, InternalBurnableFrom, or InternalBurnable), the function either
     * transfers the tokens to gateway contract itself or calls a burn function on the token contract.
     */
    function _burnTokenFrom(
        address sender,
        string memory symbol,
        uint256 amount
    ) internal {
        address tokenAddress = tokenAddresses(symbol);

        if (tokenAddress == address(0)) revert TokenDoesNotExist(symbol);
        if (amount == 0) revert InvalidAmount();

        TokenType tokenType = _getTokenType(symbol);

        if (tokenType == TokenType.External) {
            IERC20(tokenAddress).safeTransferFrom(sender, address(this), amount);
        } else if (tokenType == TokenType.InternalBurnableFrom) {
            IERC20(tokenAddress).safeCall(abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount));
        } else {
            IERC20(tokenAddress).safeTransferFrom(sender, IBurnableMintableCappedERC20(tokenAddress).depositAddress(bytes32(0)), amount);
            IBurnableMintableCappedERC20(tokenAddress).burn(bytes32(0));
        }
    }

    /********************\
    |* Pure Key Getters *|
    \********************/

    function _getTokenMintLimitKey(string memory symbol) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(PREFIX_TOKEN_MINT_LIMIT, symbol));
    }

    function _getTokenMintAmountKey(string memory symbol, uint256 day) internal pure returns (bytes32) {
        return keccak256(abi.encode(PREFIX_TOKEN_MINT_AMOUNT, symbol, day));
    }

    function _getTokenTypeKey(string memory symbol) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol));
    }

    function _getTokenAddressKey(string memory symbol) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(PREFIX_TOKEN_ADDRESS, symbol));
    }

    function _getIsCommandExecutedKey(bytes32 commandId) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(PREFIX_COMMAND_EXECUTED, commandId));
    }

    function _getIsContractCallApprovedKey(
        bytes32 commandId,
        string memory sourceChain,
        string memory sourceAddress,
        address contractAddress,
        bytes32 payloadHash
    ) internal pure returns (bytes32) {
        return keccak256(abi.encode(PREFIX_CONTRACT_CALL_APPROVED, commandId, sourceChain, sourceAddress, contractAddress, payloadHash));
    }

    function _getIsContractCallApprovedWithMintKey(
        bytes32 commandId,
        string memory sourceChain,
        string memory sourceAddress,
        address contractAddress,
        bytes32 payloadHash,
        string memory symbol,
        uint256 amount
    ) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    PREFIX_CONTRACT_CALL_APPROVED_WITH_MINT,
                    commandId,
                    sourceChain,
                    sourceAddress,
                    contractAddress,
                    payloadHash,
                    symbol,
                    amount
                )
            );
    }

    /********************\
    |* Internal Getters *|
    \********************/

    function _getCreate2Address(bytes32 salt, bytes32 codeHash) internal view returns (address) {
        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, codeHash)))));
    }

    function _getTokenType(string memory symbol) internal view returns (TokenType) {
        return TokenType(getUint(_getTokenTypeKey(symbol)));
    }

    /********************\
    |* Internal Setters *|
    \********************/

    function _setTokenMintLimit(string memory symbol, uint256 limit) internal {
        emit TokenMintLimitUpdated(symbol, limit);

        _setUint(_getTokenMintLimitKey(symbol), limit);
    }

    function _setTokenMintAmount(string memory symbol, uint256 amount) internal {
        uint256 limit = tokenMintLimit(symbol);
        if (limit > 0 && amount > limit) revert ExceedMintLimit(symbol);

        _setUint(_getTokenMintAmountKey(symbol, block.timestamp / 6 hours), amount);
    }

    function _setTokenType(string memory symbol, TokenType tokenType) internal {
        _setUint(_getTokenTypeKey(symbol), uint256(tokenType));
    }

    function _setTokenAddress(string memory symbol, address tokenAddress) internal {
        _setAddress(_getTokenAddressKey(symbol), tokenAddress);
    }

    function _setCommandExecuted(bytes32 commandId, bool executed) internal {
        _setBool(_getIsCommandExecutedKey(commandId), executed);
    }

    function _setContractCallApproved(
        bytes32 commandId,
        string memory sourceChain,
        string memory sourceAddress,
        address contractAddress,
        bytes32 payloadHash
    ) internal {
        _setBool(_getIsContractCallApprovedKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash), true);
    }

    function _setContractCallApprovedWithMint(
        bytes32 commandId,
        string memory sourceChain,
        string memory sourceAddress,
        address contractAddress,
        bytes32 payloadHash,
        string memory symbol,
        uint256 amount
    ) internal {
        _setBool(
            _getIsContractCallApprovedWithMintKey(commandId, sourceChain, sourceAddress, contractAddress, payloadHash, symbol, amount),
            true
        );
    }

    function _setImplementation(address newImplementation) internal {
        _setAddress(KEY_IMPLEMENTATION, newImplementation);
    }

    function _transferGovernance(address newGovernance) internal {
        emit GovernanceTransferred(getAddress(KEY_GOVERNANCE), newGovernance);

        _setAddress(KEY_GOVERNANCE, newGovernance);
    }

    function _transferMintLimiter(address newMintLimiter) internal {
        emit MintLimiterTransferred(getAddress(KEY_MINT_LIMITER), newMintLimiter);

        _setAddress(KEY_MINT_LIMITER, newMintLimiter);
    }
}

File 2 of 22 : IAxelarGateway.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IGovernable } from './IGovernable.sol';
import { IImplementation } from './IImplementation.sol';

interface IAxelarGateway is IImplementation, IGovernable {
    /**********\
    |* Errors *|
    \**********/

    error NotSelf();
    error InvalidCodeHash();
    error SetupFailed();
    error InvalidAuthModule();
    error InvalidTokenDeployer();
    error InvalidAmount();
    error InvalidChainId();
    error InvalidCommands();
    error TokenDoesNotExist(string symbol);
    error TokenAlreadyExists(string symbol);
    error TokenDeployFailed(string symbol);
    error TokenContractDoesNotExist(address token);
    error BurnFailed(string symbol);
    error MintFailed(string symbol);
    error InvalidSetMintLimitsParams();
    error ExceedMintLimit(string symbol);

    /**********\
    |* Events *|
    \**********/

    event TokenSent(
        address indexed sender,
        string destinationChain,
        string destinationAddress,
        string symbol,
        uint256 amount
    );

    event ContractCall(
        address indexed sender,
        string destinationChain,
        string destinationContractAddress,
        bytes32 indexed payloadHash,
        bytes payload
    );

    event ContractCallWithToken(
        address indexed sender,
        string destinationChain,
        string destinationContractAddress,
        bytes32 indexed payloadHash,
        bytes payload,
        string symbol,
        uint256 amount
    );

    event Executed(bytes32 indexed commandId);

    event TokenDeployed(string symbol, address tokenAddresses);

    event ContractCallApproved(
        bytes32 indexed commandId,
        string sourceChain,
        string sourceAddress,
        address indexed contractAddress,
        bytes32 indexed payloadHash,
        bytes32 sourceTxHash,
        uint256 sourceEventIndex
    );

    event ContractCallApprovedWithMint(
        bytes32 indexed commandId,
        string sourceChain,
        string sourceAddress,
        address indexed contractAddress,
        bytes32 indexed payloadHash,
        string symbol,
        uint256 amount,
        bytes32 sourceTxHash,
        uint256 sourceEventIndex
    );

    event ContractCallExecuted(bytes32 indexed commandId);

    event TokenMintLimitUpdated(string symbol, uint256 limit);

    event OperatorshipTransferred(bytes newOperatorsData);

    event Upgraded(address indexed implementation);

    /********************\
    |* Public Functions *|
    \********************/

    function sendToken(
        string calldata destinationChain,
        string calldata destinationAddress,
        string calldata symbol,
        uint256 amount
    ) external;

    function callContract(
        string calldata destinationChain,
        string calldata contractAddress,
        bytes calldata payload
    ) external;

    function callContractWithToken(
        string calldata destinationChain,
        string calldata contractAddress,
        bytes calldata payload,
        string calldata symbol,
        uint256 amount
    ) external;

    function isContractCallApproved(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        address contractAddress,
        bytes32 payloadHash
    ) external view returns (bool);

    function isContractCallAndMintApproved(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        address contractAddress,
        bytes32 payloadHash,
        string calldata symbol,
        uint256 amount
    ) external view returns (bool);

    function validateContractCall(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes32 payloadHash
    ) external returns (bool);

    function validateContractCallAndMint(
        bytes32 commandId,
        string calldata sourceChain,
        string calldata sourceAddress,
        bytes32 payloadHash,
        string calldata symbol,
        uint256 amount
    ) external returns (bool);

    /***********\
    |* Getters *|
    \***********/

    function authModule() external view returns (address);

    function tokenDeployer() external view returns (address);

    function tokenMintLimit(string memory symbol) external view returns (uint256);

    function tokenMintAmount(string memory symbol) external view returns (uint256);

    function allTokensFrozen() external view returns (bool);

    function implementation() external view returns (address);

    function tokenAddresses(string memory symbol) external view returns (address);

    function tokenFrozen(string memory symbol) external view returns (bool);

    function isCommandExecuted(bytes32 commandId) external view returns (bool);

    /************************\
    |* Governance Functions *|
    \************************/

    function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external;

    function upgrade(
        address newImplementation,
        bytes32 newImplementationCodeHash,
        bytes calldata setupParams
    ) external;

    /**********************\
    |* External Functions *|
    \**********************/

    function execute(bytes calldata input) external;
}

File 3 of 22 : IContractIdentifier.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// General interface for upgradable contracts
interface IContractIdentifier {
    /**
     * @notice Returns the contract ID. It can be used as a check during upgrades.
     * @dev Meant to be overridden in derived contracts.
     * @return bytes32 The contract ID
     */
    function contractId() external pure returns (bytes32);
}

File 4 of 22 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    error InvalidAccount();

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

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 5 of 22 : IGovernable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title IGovernable Interface
 * @notice This is an interface used by the AxelarGateway contract to manage governance and mint limiter roles.
 */
interface IGovernable {
    error NotGovernance();
    error NotMintLimiter();
    error InvalidGovernance();
    error InvalidMintLimiter();

    event GovernanceTransferred(address indexed previousGovernance, address indexed newGovernance);
    event MintLimiterTransferred(address indexed previousGovernance, address indexed newGovernance);

    /**
     * @notice Returns the governance address.
     * @return address of the governance
     */
    function governance() external view returns (address);

    /**
     * @notice Returns the mint limiter address.
     * @return address of the mint limiter
     */
    function mintLimiter() external view returns (address);

    /**
     * @notice Transfer the governance role to another address.
     * @param newGovernance The new governance address
     */
    function transferGovernance(address newGovernance) external;

    /**
     * @notice Transfer the mint limiter role to another address.
     * @param newGovernance The new mint limiter address
     */
    function transferMintLimiter(address newGovernance) external;
}

File 6 of 22 : IImplementation.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

interface IImplementation is IContractIdentifier {
    error NotProxy();

    function setup(bytes calldata data) external;
}

File 7 of 22 : IOwnable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @title IOwnable Interface
 * @notice IOwnable is an interface that abstracts the implementation of a
 * contract with ownership control features. It's commonly used in upgradable
 * contracts and includes the functionality to get current owner, transfer
 * ownership, and propose and accept ownership.
 */
interface IOwnable {
    error NotOwner();
    error InvalidOwner();
    error InvalidOwnerAddress();

    event OwnershipTransferStarted(address indexed newOwner);
    event OwnershipTransferred(address indexed newOwner);

    /**
     * @notice Returns the current owner of the contract.
     * @return address The address of the current owner
     */
    function owner() external view returns (address);

    /**
     * @notice Returns the address of the pending owner of the contract.
     * @return address The address of the pending owner
     */
    function pendingOwner() external view returns (address);

    /**
     * @notice Transfers ownership of the contract to a new address
     * @param newOwner The address to transfer ownership to
     */
    function transferOwnership(address newOwner) external;

    /**
     * @notice Proposes to transfer the contract's ownership to a new address.
     * The new owner needs to accept the ownership explicitly.
     * @param newOwner The address to transfer ownership to
     */
    function proposeOwnership(address newOwner) external;

    /**
     * @notice Transfers ownership to the pending owner.
     * @dev Can only be called by the pending owner
     */
    function acceptOwnership() external;
}

File 8 of 22 : ContractAddress.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

library ContractAddress {
    function isContract(address contractAddress) internal view returns (bool) {
        bytes32 existingCodeHash = contractAddress.codehash;

        // https://eips.ethereum.org/EIPS/eip-1052
        // keccak256('') == 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
        return
            existingCodeHash != bytes32(0) &&
            existingCodeHash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
    }
}

File 9 of 22 : SafeTransfer.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

error TokenTransferFailed();

/*
 * @title SafeTokenCall
 * @dev This library is used for performing safe token transfers.
 */
library SafeTokenCall {
    /*
     * @notice Make a safe call to a token contract.
     * @param token The token contract to interact with.
     * @param callData The function call data.
     * @throws TokenTransferFailed error if transfer of token is not successful.
     */
    function safeCall(IERC20 token, bytes memory callData) internal {
        (bool success, bytes memory returnData) = address(token).call(callData);
        bool transferred = success && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));

        if (!transferred || address(token).code.length == 0) revert TokenTransferFailed();
    }
}

/*
 * @title SafeTokenTransfer
 * @dev This library safely transfers tokens from the contract to a recipient.
 */
library SafeTokenTransfer {
    /*
     * @notice Transfer tokens to a recipient.
     * @param token The token contract.
     * @param receiver The recipient of the tokens.
     * @param amount The amount of tokens to transfer.
     */
    function safeTransfer(
        IERC20 token,
        address receiver,
        uint256 amount
    ) internal {
        SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transfer.selector, receiver, amount));
    }
}

/*
 * @title SafeTokenTransferFrom
 * @dev This library helps to safely transfer tokens on behalf of a token holder.
 */
library SafeTokenTransferFrom {
    /*
     * @notice Transfer tokens on behalf of a token holder.
     * @param token The token contract.
     * @param from The address of the token holder.
     * @param to The address the tokens are to be sent to.
     * @param amount The amount of tokens to be transferred.
     */
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        SafeTokenCall.safeCall(token, abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, amount));
    }
}

File 10 of 22 : Implementation.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

/**
 * @title Implementation
 * @notice This contract serves as a base for other contracts and enforces a proxy-first access restriction.
 * @dev Derived contracts must implement the setup function.
 */
abstract contract Implementation is IImplementation {
    address private immutable implementationAddress;

    /**
     * @dev Contract constructor that sets the implementation address to the address of this contract.
     */
    constructor() {
        implementationAddress = address(this);
    }

    /**
     * @dev Modifier to require the caller to be the proxy contract.
     * Reverts if the caller is the current contract (i.e., the implementation contract itself).
     */
    modifier onlyProxy() {
        if (implementationAddress == address(this)) revert NotProxy();
        _;
    }

    /**
     * @notice Initializes contract parameters.
     * This function is intended to be overridden by derived contracts.
     * The overriding function must have the onlyProxy modifier.
     * @param params The parameters to be used for initialization
     */
    function setup(bytes calldata params) external virtual;
}

File 11 of 22 : DepositHandler.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

contract DepositHandler {
    error IsLocked();
    error NotContract();

    uint256 internal constant IS_NOT_LOCKED = uint256(1);
    uint256 internal constant IS_LOCKED = uint256(2);

    uint256 internal _lockedStatus = IS_NOT_LOCKED;

    modifier noReenter() {
        if (_lockedStatus == IS_LOCKED) revert IsLocked();

        _lockedStatus = IS_LOCKED;
        _;
        _lockedStatus = IS_NOT_LOCKED;
    }

    function execute(address callee, bytes calldata data) external noReenter returns (bool success, bytes memory returnData) {
        if (callee.code.length == 0) revert NotContract();
        (success, returnData) = callee.call(data);
    }

    // NOTE: The gateway should always destroy the `DepositHandler` in the same runtime context that deploys it.
    function destroy(address etherDestination) external noReenter {
        selfdestruct(payable(etherDestination));
    }
}

File 12 of 22 : ECDSA.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    error InvalidSignatureLength();
    error InvalidS();
    error InvalidV();
    error InvalidSignature();

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

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) revert InvalidS();

        if (v != 27 && v != 28) revert InvalidV();

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

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
     * JSON-RPC method.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked('\x19Ethereum Signed Message:\n32', hash));
    }
}

File 13 of 22 : EternalStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @title EternalStorage
 * @dev This contract holds all the necessary state variables to carry out the storage of any contract.
 */
contract EternalStorage {
    mapping(bytes32 => uint256) private _uintStorage;
    mapping(bytes32 => string) private _stringStorage;
    mapping(bytes32 => address) private _addressStorage;
    mapping(bytes32 => bytes) private _bytesStorage;
    mapping(bytes32 => bool) private _boolStorage;
    mapping(bytes32 => int256) private _intStorage;

    // *** Getter Methods ***
    function getUint(bytes32 key) public view returns (uint256) {
        return _uintStorage[key];
    }

    function getString(bytes32 key) public view returns (string memory) {
        return _stringStorage[key];
    }

    function getAddress(bytes32 key) public view returns (address) {
        return _addressStorage[key];
    }

    function getBytes(bytes32 key) public view returns (bytes memory) {
        return _bytesStorage[key];
    }

    function getBool(bytes32 key) public view returns (bool) {
        return _boolStorage[key];
    }

    function getInt(bytes32 key) public view returns (int256) {
        return _intStorage[key];
    }

    // *** Setter Methods ***
    function _setUint(bytes32 key, uint256 value) internal {
        _uintStorage[key] = value;
    }

    function _setString(bytes32 key, string memory value) internal {
        _stringStorage[key] = value;
    }

    function _setAddress(bytes32 key, address value) internal {
        _addressStorage[key] = value;
    }

    function _setBytes(bytes32 key, bytes memory value) internal {
        _bytesStorage[key] = value;
    }

    function _setBool(bytes32 key, bool value) internal {
        _boolStorage[key] = value;
    }

    function _setInt(bytes32 key, int256 value) internal {
        _intStorage[key] = value;
    }

    // *** Delete Methods ***
    function _deleteUint(bytes32 key) internal {
        delete _uintStorage[key];
    }

    function _deleteString(bytes32 key) internal {
        delete _stringStorage[key];
    }

    function _deleteAddress(bytes32 key) internal {
        delete _addressStorage[key];
    }

    function _deleteBytes(bytes32 key) internal {
        delete _bytesStorage[key];
    }

    function _deleteBool(bytes32 key) internal {
        delete _boolStorage[key];
    }

    function _deleteInt(bytes32 key) internal {
        delete _intStorage[key];
    }
}

File 14 of 22 : IAxelarAuth.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IOwnable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IOwnable.sol';

interface IAxelarAuth is IOwnable {
    function validateProof(bytes32 messageHash, bytes calldata proof) external returns (bool currentOperators);

    function transferOperatorship(bytes calldata params) external;
}

File 15 of 22 : IBurnableMintableCappedERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

import { IERC20Burn } from './IERC20Burn.sol';
import { IERC20BurnFrom } from './IERC20BurnFrom.sol';
import { IMintableCappedERC20 } from './IMintableCappedERC20.sol';

interface IBurnableMintableCappedERC20 is IERC20Burn, IERC20BurnFrom, IMintableCappedERC20 {
    function depositAddress(bytes32 salt) external view returns (address);

    function burn(bytes32 salt) external;

    function burnFrom(address account, uint256 amount) external;
}

File 16 of 22 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    error InvalidAccount();

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

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

File 17 of 22 : IERC20Burn.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

interface IERC20Burn {
    function burn(bytes32 salt) external;
}

File 18 of 22 : IERC20BurnFrom.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

interface IERC20BurnFrom {
    function burnFrom(address account, uint256 amount) external;
}

File 19 of 22 : IERC20Permit.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

interface IERC20Permit {
    function DOMAIN_SEPARATOR() external view returns (bytes32);

    function nonces(address account) external view returns (uint256);

    function permit(
        address issuer,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 20 of 22 : IMintableCappedERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

import { IERC20 } from './IERC20.sol';
import { IERC20Permit } from './IERC20Permit.sol';
import { IOwnable } from './IOwnable.sol';

interface IMintableCappedERC20 is IERC20, IERC20Permit, IOwnable {
    error CapExceeded();

    function cap() external view returns (uint256);

    function mint(address account, uint256 amount) external;
}

File 21 of 22 : IOwnable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

interface IOwnable {
    error NotOwner();
    error InvalidOwner();

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

    function owner() external view returns (address);

    function transferOwnership(address newOwner) external;
}

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

pragma solidity ^0.8.0;

interface ITokenDeployer {
    function deployToken(
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        uint256 cap,
        bytes32 salt
    ) external returns (address tokenAddress);
}

Settings
{
  "evmVersion": "london",
  "optimizer": {
    "enabled": true,
    "runs": 1000,
    "details": {
      "peephole": true,
      "inliner": true,
      "jumpdestRemover": true,
      "orderLiterals": true,
      "deduplicate": true,
      "cse": true,
      "constantOptimizer": true,
      "yul": true,
      "yulDetails": {
        "stackAllocation": true
      }
    }
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"authModule_","type":"address"},{"internalType":"address","name":"tokenDeployer_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"BurnFailed","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"ExceedMintLimit","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidAuthModule","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidCodeHash","type":"error"},{"inputs":[],"name":"InvalidCommands","type":"error"},{"inputs":[],"name":"InvalidGovernance","type":"error"},{"inputs":[],"name":"InvalidImplementation","type":"error"},{"inputs":[],"name":"InvalidMintLimiter","type":"error"},{"inputs":[],"name":"InvalidSetMintLimitsParams","type":"error"},{"inputs":[],"name":"InvalidTokenDeployer","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"MintFailed","type":"error"},{"inputs":[],"name":"NotGovernance","type":"error"},{"inputs":[],"name":"NotMintLimiter","type":"error"},{"inputs":[],"name":"NotProxy","type":"error"},{"inputs":[],"name":"NotSelf","type":"error"},{"inputs":[],"name":"SetupFailed","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"TokenAlreadyExists","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TokenContractDoesNotExist","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"TokenDeployFailed","type":"error"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenTransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"string","name":"destinationContractAddress","type":"string"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"}],"name":"ContractCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"sourceChain","type":"string"},{"indexed":false,"internalType":"string","name":"sourceAddress","type":"string"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"sourceTxHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"sourceEventIndex","type":"uint256"}],"name":"ContractCallApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"},{"indexed":false,"internalType":"string","name":"sourceChain","type":"string"},{"indexed":false,"internalType":"string","name":"sourceAddress","type":"string"},{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"sourceTxHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"sourceEventIndex","type":"uint256"}],"name":"ContractCallApprovedWithMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"ContractCallExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"string","name":"destinationContractAddress","type":"string"},{"indexed":true,"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ContractCallWithToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"GovernanceTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"}],"name":"MintLimiterTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"newOperatorsData","type":"bytes"}],"name":"OperatorshipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"address","name":"tokenAddresses","type":"address"}],"name":"TokenDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"TokenMintLimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"string","name":"destinationChain","type":"string"},{"indexed":false,"internalType":"string","name":"destinationAddress","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"allTokensFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"approveContractCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"approveContractCallWithMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authModule","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"burnToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationContractAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"callContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationContractAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"callContractWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"deployToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"input","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getBytes","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getInt","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getString","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getUint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"}],"name":"isCommandExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"isContractCallAndMintApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"name":"isContractCallApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintLimiter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"mintToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"destinationChain","type":"string"},{"internalType":"string","name":"destinationAddress","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"symbols","type":"string[]"},{"internalType":"uint256[]","name":"limits","type":"uint256[]"}],"name":"setTokenMintLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"params","type":"bytes"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"tokenAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenDeployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"tokenFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"tokenMintAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"symbol","type":"string"}],"name":"tokenMintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernance","type":"address"}],"name":"transferGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newMintLimiter","type":"address"}],"name":"transferMintLimiter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"newOperatorsData","type":"bytes"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"transferOperatorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes32","name":"newImplementationCodeHash","type":"bytes32"},{"internalType":"bytes","name":"setupParams","type":"bytes"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"}],"name":"validateContractCall","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes32","name":"payloadHash","type":"bytes32"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"validateContractCallAndMint","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b506040516200474b3803806200474b8339810160408190526200003491620000bf565b306080526001600160a01b0382163b620000615760405163735326ab60e01b815260040160405180910390fd5b6001600160a01b0381163b6200008a57604051630c84dabf60e31b815260040160405180910390fd5b6001600160a01b0391821660a0521660c052620000f7565b80516001600160a01b0381168114620000ba57600080fd5b919050565b60008060408385031215620000d357600080fd5b620000de83620000a2565b9150620000ee60208401620000a2565b90509250929050565b60805160a05160c0516146086200014360003960008181610359015261186701526000818161047e015281816106f201528181611aad0152611cbc01526000611bbf01526146086000f3fe608060405234801561001057600080fd5b50600436106102775760003560e01c80638291286c11610160578063bc00c216116100d8578063d26ff2101161008c578063dc97d96211610071578063dc97d96214610681578063f6a5f9f5146106a1578063fbe0a31b146106b457600080fd5b8063d26ff2101461065b578063d38bfff41461066e57600080fd5b8063c031a180116100bd578063c031a180146105dc578063c82fe87a146105ef578063cec7b3591461064857600080fd5b8063bc00c216146105a9578063bd02d0f5146105bc57600080fd5b8063986e791a1161012f578063a3499c7311610114578063a3499c731461057c578063aa1e1f0a1461058f578063b54170841461059657600080fd5b8063986e791a146105495780639ded06df1461056957600080fd5b80638291286c146104ea578063886a625d14610510578063935b13f61461052357806397b87ba61461053657600080fd5b80634656ae2e116101f35780635f6970c3116101c257806367ace8eb116101a757806367ace8eb146104a05780637ae1cfca146104b35780637b1b769e146104d657600080fd5b80635f6970c31461046657806364940c561461047957600080fd5b80634656ae2e1461038e578063585a9fd4146103a15780635aa6e675146103b45780635c60da1b1461040d57600080fd5b806321f8a7211161024a57806326ef699d1161022f57806326ef699d146103415780632a2dae0a1461035457806341d8f26b1461037b57600080fd5b806321f8a721146102df578063269eb65e1461032057600080fd5b806309c5eabe1461027c578063146e2d78146102915780631876eed9146102a45780631c92115f146102cc575b600080fd5b61028f61028a366004612f28565b6106c7565b005b61028f61029f366004612f6a565b610be1565b6102b76102b2366004612fb6565b610c2a565b60405190151581526020015b60405180910390f35b61028f6102da36600461306b565b610d85565b6103086102ed366004613105565b6000908152600260205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016102c3565b61033361032e3660046131e3565b610df0565b6040519081526020016102c3565b61028f61034f366004613220565b610e04565b6103087f000000000000000000000000000000000000000000000000000000000000000081565b61028f6103893660046132d8565b610e9c565b61028f61039c366004612f6a565b610fbc565b61028f6103af366004612f6a565b611403565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316610308565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3546001600160a01b0316610308565b6102b76104743660046132f5565b6114b1565b6103087f000000000000000000000000000000000000000000000000000000000000000081565b61028f6104ae3660046133bc565b611591565b6102b76104c1366004613105565b60009081526004602052604090205460ff1690565b6102b76104e43660046131e3565b50600090565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b3625610333565b61028f61051e366004612f6a565b61177f565b6103086105313660046131e3565b611a2f565b61028f610544366004612f6a565b611a3d565b61055c610557366004613105565b611b1b565b6040516102c39190613480565b61028f610577366004612f28565b611bbd565b61028f61058a366004613493565b611d26565b60006102b7565b61028f6105a43660046134e3565b61203c565b6102b76105b73660046135af565b6120f2565b6103336105ca366004613105565b60009081526020819052604090205490565b61055c6105ea366004613105565b6121c5565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316610308565b6103336106563660046131e3565b6121e2565b6102b7610669366004613105565b6121fc565b61028f61067c3660046132d8565b61220a565b61033361068f366004613105565b60009081526005602052604090205490565b6102b76106af36600461367d565b6122c5565b61028f6106c2366004612f6a565b61234e565b6000806106d683850185613714565b9150915060006106ec83805190602001206123ee565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166373e3d66a83856040518363ffffffff1660e01b815260040161073e929190613778565b602060405180830381600087803b15801561075857600080fd5b505af115801561076c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079091906137a6565b905060006060806060878060200190518101906107ad919061394a565b929650909450925090504684146107f0576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251825181141580610803575081518114155b1561083a576040517fca9a28f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610bd357600085828151811061085957610859613a34565b6020026020010151905061086c816121fc565b156108775750610bc3565b60008086848151811061088c5761088c613a34565b60200260200101516040516020016108a49190613a4a565b6040516020818303038152906040528051906020012090507f5763814b98a3aa86f212797af3273868b5dd6e2a532d764a79b98ca859e7bbad81141561090c577f886a625d000000000000000000000000000000000000000000000000000000009150610ab5565b7fec78d9c22c08bb9f0ecd5d95571ae83e3f22219c5a9278c3270691d50abfd91b81141561095c577f146e2d78000000000000000000000000000000000000000000000000000000009150610ab5565b7f37ac16aabc4d87540e53151b2b716265cfd6b195db96a9daf8e893c829bbd2338114156109ac577ffbe0a31b000000000000000000000000000000000000000000000000000000009150610ab5565b7ff41504255b911b3042ee4f8786fdf7cf4bcf24ace033fa16af3c8574e025e4368114156109fc577f585a9fd4000000000000000000000000000000000000000000000000000000009150610ab5565b7fda199c0e76f665e0450020791c7f8eacc75f3cdbace313272c28f93e5390b62c811415610a4c577f4656ae2e000000000000000000000000000000000000000000000000000000009150610ab5565b7fb460dcb6fd5797fc0e7ea0f13406c80d30702ba7f73a42bd91394775dcbca718811415610aad5789610a8157505050610bc3565b600099507f97b87ba6000000000000000000000000000000000000000000000000000000009150610ab5565b505050610bc3565b610ac0836001612442565b6000306001600160a01b031683888781518110610adf57610adf613a34565b602002602001015186604051602401610af9929190613a66565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610b379190613a4a565b6000604051808303816000865af19150503d8060008114610b74576040519150601f19603f3d011682016040523d82523d6000602084013e610b79565b606091505b505090508015610bb35760405184907fa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca90600090a2610bbe565b610bbe846000612442565b505050505b610bcc81613a9e565b905061083d565b505050505050505050505050565b333014610c01576040516314e1dbf760e11b815260040160405180910390fd5b60008080610c1185870187613ac4565b925092509250610c2283838361246e565b505050505050565b600080610cdb8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c908190840183828082843760009201919091525050604080516020601f8d018190048102820181019092528b81523393508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b60008181526004602052604090205460ff16925090508115610d7757600081815260046020526040808220805460ff19169055518c917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a2610d7785858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525033925087915061246e9050565b509998505050505050505050565b8181604051610d95929190613b1e565b6040518091039020336001600160a01b03167f30ae6cc78c27e651745bf2ad08a11de83910ac1e347a52f7ac898c0fbef94dae888888888888604051610de096959493929190613b57565b60405180910390a3505050505050565b6000610dfe6105ca836125e1565b92915050565b610e463384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b336001600160a01b03167f651d93f66c4329630e8d0f62488eff599e3be484da587335e8dc0fcf4606272688888888888888604051610e8b9796959493929190613ba0565b60405180910390a250505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b03163314801590610f5257507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b15610f705760405163223aa83d60e11b815260040160405180910390fd5b6001600160a01b038116610fb0576040517fd79d772c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612821565b50565b333014610fdc576040516314e1dbf760e11b815260040160405180910390fd5b600080610feb84860186613bf1565b915091506000610ffa83611a2f565b90506001600160a01b03811661102e578260405163395d09bf60e11b81526004016110259190613480565b60405180910390fd5b600261103984612916565b600281111561104a5761104a613c36565b14156113a0576000611107836040518060200161106690612ed2565b601f1982820381018352601f9091011660408190526110889190602001613a4a565b60408051601f1981840301815282825280516020918201207fff00000000000000000000000000000000000000000000000000000000000000848301526bffffffffffffffffffffffff193060601b16602185015260358401949094526055808401949094528151808403909401845260759092019052815191012090565b905061111b816001600160a01b0316612935565b156111295750505050505050565b60008360405161113890612ed2565b8190604051809103906000f5905080158015611158573d6000803e3d6000fd5b506040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830181905292935060009283929091631cff79cd91889163a9059cbb60e01b9130918416906370a082319060240160206040518083038186803b1580156111d257600080fd5b505afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a9190613c4c565b6040516001600160a01b039092166024830152604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b909216825261126b9291600401613c65565b600060405180830381600087803b15801561128557600080fd5b505af1158015611299573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c19190810190613c87565b915091508115806112ee57508051158015906112ee5750808060200190518101906112ec91906137a6565b155b1561132757866040517fe217b0ad0000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6040517ef55d9d0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384169062f55d9d90602401600060405180830381600087803b15801561137f57600080fd5b505af1158015611393573d6000803e3d6000fd5b5050505050505050610c22565b6040516308a1eee160e01b8152600481018390526001600160a01b038216906308a1eee190602401600060405180830381600087803b1580156113e257600080fd5b505af11580156113f6573d6000803e3d6000fd5b505050505050505b505050565b333014611423576040516314e1dbf760e11b815260040160405180910390fd5b6000808080808080806114388a8c018c613ccb565b9750975097509750975097509750975061145789898989898989612978565b84866001600160a01b03168a7f9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e08b8b8989898960405161149c96959493929190613d89565b60405180910390a45050505050505050505050565b60008061152c8888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152503392508991506129a59050565b60008181526004602052604090205460ff1692509050811561158657600081815260046020526040808220805460ff191690555189917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a25b509695505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316331480159061164757507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b156116655760405163223aa83d60e11b815260040160405180910390fd5b8281811461169f576040517f14a2275f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610c225760008686838181106116be576116be613a34565b90506020028101906116d09190613de1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945088925087915085905081811061171b5761171b613a34565b90506020020135905060006001600160a01b031661173883611a2f565b6001600160a01b03161415611762578160405163395d09bf60e11b81526004016110259190613480565b61176c8282612a03565b50508061177890613a9e565b90506116a2565b33301461179f576040516314e1dbf760e11b815260040160405180910390fd5b600080808080806117b2888a018a613e28565b95509550955095509550955060006001600160a01b03166117d286611a2f565b6001600160a01b03161461181457846040517faa7e8b320000000000000000000000000000000000000000000000000000000081526004016110259190613480565b61181e8582612a03565b6001600160a01b03821661198a5760008560405160200161183f9190613a4a565b604051602081830303815290604052805190602001209050611862866001612a5b565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636fc95b3460e01b8a8a8a8a886040516024016118b0959493929190613ecb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516118ee9190613a4a565b600060405180830381855af49150503d8060008114611929576040519150601f19603f3d011682016040523d82523d6000602084013e61192e565b606091505b50915091508161196c57876040517f86d527430000000000000000000000000000000000000000000000000000000081526004016110259190613480565b808060200190518101906119809190613f11565b94505050506119e1565b6001600160a01b0382163b6119d6576040517fc5ccddde0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611025565b6119e1856002612a5b565b7fbf90b5a1ec9763e8bf4b9245cef0c28db92bab309fc2c5177f17814f382469388583604051611a12929190613f2e565b60405180910390a1611a248583612a8b565b505050505050505050565b6000610dfe6102ed83612acd565b333014611a5d576040516314e1dbf760e11b815260040160405180910390fd5b7f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a5218728383604051611a8e929190613f59565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d289d1cb90611ae49086908690600401613f59565b600060405180830381600087803b158015611afe57600080fd5b505af1158015611b12573d6000803e3d6000fd5b50505050505050565b6000818152600160205260409020805460609190611b3890613f6d565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6490613f6d565b8015611bb15780601f10611b8657610100808354040283529160200191611bb1565b820191906000526020600020905b815481529060010190602001808311611b9457829003601f168201915b50505050509050919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316301415611c20576040517fbf10dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080611c3084860186613fa8565b919450925090506001600160a01b03831615611c4f57611c4f83612b02565b6001600160a01b03821615611c6757611c6782612821565b805115611d1f577f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a52187281604051611c9d9190613480565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063d289d1cb90611cf1908490600401613480565b600060405180830381600087803b158015611d0b57600080fd5b505af1158015611a24573d6000803e3d6000fd5b5050505050565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314611d9957604051632d5be4cb60e21b815260040160405180910390fd5b836001600160a01b03163f8314611ddc576040517f8f84fb2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836001600160a01b0316638291286c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1557600080fd5b505afa158015611e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4d9190613c4c565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b362514611ea5576040517f68155f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038516907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2611f50847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b8015612036576000846001600160a01b0316639ded06df60e01b8484604051602401611f7d929190613f59565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611fbb9190613a4a565b600060405180830381855af49150503d8060008114611ff6576040519150601f19603f3d011682016040523d82523d6000602084013e611ffb565b606091505b5050905080611d1f576040517f97905dfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61207e3384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b848460405161208e929190613b1e565b6040518091039020336001600160a01b03167f7e50569d26be643bda7757722291ec66b1be66d8283474ae3fab5a98f878a7a28b8b8b8b8b8b8b8b8b6040516120df9998979695949392919061400a565b60405180910390a3505050505050505050565b60006121b66104c18c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b81528e93508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b9b9a5050505050505050505050565b6000818152600360205260409020805460609190611b3890613f6d565b6000610dfe6105ca836121f761546042614072565b612bf7565b6000610dfe6104c183612c4c565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316331461227d57604051632d5be4cb60e21b815260040160405180910390fd5b6001600160a01b0381166122bc576040517e63186c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612b02565b60006123426104c18989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a90819084018382808284376000920191909152508a92508991506129a59050565b98975050505050505050565b33301461236e576040516314e1dbf760e11b815260040160405180910390fd5b60008080808080612381888a018a614094565b95509550955095509550955061239a8787878787612c87565b82846001600160a01b0316887f44e4f8f6bd682c5a3aeba93601ab07cb4d1f21b2aab1ae4880d9577919309aa4898987876040516123db9493929190614126565b60405180910390a4505050505050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c015b604051602081830303815290604052805190602001209050919050565b61246a61244e83612c4c565b6000908152600460205260409020805460ff1916831515179055565b5050565b600061247984611a2f565b90506001600160a01b0381166124a4578360405163395d09bf60e11b81526004016110259190613480565b6124c184836124b2876121e2565b6124bc919061415f565b612c97565b60026124cc85612916565b60028111156124dd576124dd613c36565b14156124fc576124f76001600160a01b0382168484612d12565b612036565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906340c10f1990604401600060405180830381600087803b15801561255f57600080fd5b505af1158015612573573d6000803e3d6000fd5b5050505050505050565b60007fb7ad972b71475860613db3ba1fe699b886c878f9002a09250dc25e769eb19a10888888888888886040516020016125be989796959493929190614177565b604051602081830303815290604052805190602001209050979650505050505050565b60007feee9348b4aaba3647b1612b2724f18e93b9299da26fb321c7b3fda135d7dea87826040516020016124259291906141ea565b600061262183611a2f565b90506001600160a01b03811661264c578260405163395d09bf60e11b81526004016110259190613480565b81612683576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061268e84612916565b905060028160028111156126a4576126a4613c36565b14156126c4576126bf6001600160a01b038316863086612d75565b611d1f565b60018160028111156126d8576126d8613c36565b141561274b57604080516001600160a01b03878116602483015260448083018790528351808403909101815260649092019092526020810180516001600160e01b03167f79cc6790000000000000000000000000000000000000000000000000000000001790526126bf91841690612dc6565b6040517f31eecaf4000000000000000000000000000000000000000000000000000000008152600060048201526127f49086906001600160a01b038516906331eecaf49060240160206040518083038186803b1580156127aa57600080fd5b505afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e29190613f11565b6001600160a01b038516919086612d75565b6040516308a1eee160e01b8152600060048201526001600160a01b038316906308a1eee190602401611cf1565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92600090815260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546040516001600160a01b03848116939216917fa9303c860c5de3c0c866c354d281785c89778ac5ca2dffdf12841c45cd4e1e6e91a37f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60006129246105ca83612e9d565b6002811115610dfe57610dfe613c36565b60006001600160a01b0382163f801580159061297157507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708114155b9392505050565b611b1261298a8888888888888861257d565b6000908152600460205260409020805460ff19166001179055565b60007f07b0d4304f82012bd3b70b1d531c160e326067c90829e2a3d386722ad10b89c386868686866040516020016129e296959493929190614210565b60405160208183030381529060405280519060200120905095945050505050565b7fd99446c1d76385bb5519ccfb5274abcfd5896dfc22405e40010fde217f018a188282604051612a34929190613a66565b60405180910390a161246a612a48836125e1565b8260009182526020829052604090912055565b61246a612a6783612e9d565b826002811115612a7957612a79613c36565b60009182526020829052604090912055565b61246a612a9783612acd565b6000908152600260205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055565b60007fc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42bb826040516020016124259291906141ea565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909600090815260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546040516001600160a01b03848116939216917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8091a37fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60007f2f8851fe0d6d537e552a4f25b7a3167d48eb1292622c71d84630a2a44757bced8383604051602001612c2e93929190614260565b60405160208183030381529060405280519060200120905092915050565b604080517f957705a374326b30f4a1069c936d736cc9993ed6c820b4e0e2fd94a8beca0d1d6020820152908101829052600090606001612425565b611d1f61298a86868686866129a5565b6000612ca283610df0565b9050600081118015612cb357508082115b15612cec57826040517f037f60e50000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6113fe612cff846121f761546042614072565b8360009182526020829052604090912055565b6040516001600160a01b0383166024820152604481018290526113fe90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612dc6565b6040516001600160a01b03808516602483015283166044820152606481018290526120369085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d3e565b600080836001600160a01b031683604051612de19190613a4a565b6000604051808303816000865af19150503d8060008114612e1e576040519150601f19603f3d011682016040523d82523d6000602084013e612e23565b606091505b50915091506000828015612e4f575081511580612e4f575081806020019051810190612e4f91906137a6565b9050801580612e6657506001600160a01b0385163b155b15611d1f576040517f045c4b0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fa80d2259af55890618ec2eeb3ac72de4bdba22529bb14845d8a3d712d1c3f621826040516020016124259291906141ea565b6103498061428a83390190565b60008083601f840112612ef157600080fd5b50813567ffffffffffffffff811115612f0957600080fd5b602083019150836020828501011115612f2157600080fd5b9250929050565b60008060208385031215612f3b57600080fd5b823567ffffffffffffffff811115612f5257600080fd5b612f5e85828601612edf565b90969095509350505050565b600080600060408486031215612f7f57600080fd5b833567ffffffffffffffff811115612f9657600080fd5b612fa286828701612edf565b909790965060209590950135949350505050565b600080600080600080600080600060c08a8c031215612fd457600080fd5b8935985060208a013567ffffffffffffffff80821115612ff357600080fd5b612fff8d838e01612edf565b909a50985060408c013591508082111561301857600080fd5b6130248d838e01612edf565b909850965060608c0135955060808c013591508082111561304457600080fd5b506130518c828d01612edf565b9a9d999c50979a9699959894979660a00135949350505050565b6000806000806000806060878903121561308457600080fd5b863567ffffffffffffffff8082111561309c57600080fd5b6130a88a838b01612edf565b909850965060208901359150808211156130c157600080fd5b6130cd8a838b01612edf565b909650945060408901359150808211156130e657600080fd5b506130f389828a01612edf565b979a9699509497509295939492505050565b60006020828403121561311757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561315d5761315d61311e565b604052919050565b600067ffffffffffffffff82111561317f5761317f61311e565b50601f01601f191660200190565b600082601f83011261319e57600080fd5b81356131b16131ac82613165565b613134565b8181528460208386010111156131c657600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156131f557600080fd5b813567ffffffffffffffff81111561320c57600080fd5b6132188482850161318d565b949350505050565b60008060008060008060006080888a03121561323b57600080fd5b873567ffffffffffffffff8082111561325357600080fd5b61325f8b838c01612edf565b909950975060208a013591508082111561327857600080fd5b6132848b838c01612edf565b909750955060408a013591508082111561329d57600080fd5b506132aa8a828b01612edf565b989b979a50959894979596606090950135949350505050565b6001600160a01b0381168114610fb957600080fd5b6000602082840312156132ea57600080fd5b8135612971816132c3565b6000806000806000806080878903121561330e57600080fd5b86359550602087013567ffffffffffffffff8082111561332d57600080fd5b6133398a838b01612edf565b9097509550604089013591508082111561335257600080fd5b5061335f89828a01612edf565b979a9699509497949695606090950135949350505050565b60008083601f84011261338957600080fd5b50813567ffffffffffffffff8111156133a157600080fd5b6020830191508360208260051b8501011115612f2157600080fd5b600080600080604085870312156133d257600080fd5b843567ffffffffffffffff808211156133ea57600080fd5b6133f688838901613377565b9096509450602087013591508082111561340f57600080fd5b5061341c87828801613377565b95989497509550505050565b60005b8381101561344357818101518382015260200161342b565b838111156120365750506000910152565b6000815180845261346c816020860160208601613428565b601f01601f19169290920160200192915050565b6020815260006129716020830184613454565b600080600080606085870312156134a957600080fd5b84356134b4816132c3565b935060208501359250604085013567ffffffffffffffff8111156134d757600080fd5b61341c87828801612edf565b600080600080600080600080600060a08a8c03121561350157600080fd5b893567ffffffffffffffff8082111561351957600080fd5b6135258d838e01612edf565b909b50995060208c013591508082111561353e57600080fd5b61354a8d838e01612edf565b909950975060408c013591508082111561356357600080fd5b61356f8d838e01612edf565b909750955060608c013591508082111561358857600080fd5b506135958c828d01612edf565b9a9d999c50979a9699959894979660800135949350505050565b60008060008060008060008060008060e08b8d0312156135ce57600080fd5b8a35995060208b013567ffffffffffffffff808211156135ed57600080fd5b6135f98e838f01612edf565b909b50995060408d013591508082111561361257600080fd5b61361e8e838f01612edf565b909950975060608d01359150613633826132c3565b90955060808c0135945060a08c0135908082111561365057600080fd5b5061365d8d828e01612edf565b9150809450508092505060c08b013590509295989b9194979a5092959850565b600080600080600080600060a0888a03121561369857600080fd5b87359650602088013567ffffffffffffffff808211156136b757600080fd5b6136c38b838c01612edf565b909850965060408a01359150808211156136dc57600080fd5b506136e98a828b01612edf565b90955093505060608801356136fd816132c3565b809250506080880135905092959891949750929550565b6000806040838503121561372757600080fd5b823567ffffffffffffffff8082111561373f57600080fd5b61374b8683870161318d565b9350602085013591508082111561376157600080fd5b5061376e8582860161318d565b9150509250929050565b8281526040602082015260006132186040830184613454565b805180151581146137a157600080fd5b919050565b6000602082840312156137b857600080fd5b61297182613791565b600067ffffffffffffffff8211156137db576137db61311e565b5060051b60200190565b60006137f36131ac84613165565b905082815283838301111561380757600080fd5b612971836020830184613428565b600082601f83011261382657600080fd5b815160206138366131ac836137c1565b82815260059290921b8401810191818101908684111561385557600080fd5b8286015b8481101561158657805167ffffffffffffffff8111156138795760008081fd5b8701603f8101891361388b5760008081fd5b61389c8986830151604084016137e5565b845250918301918301613859565b600082601f8301126138bb57600080fd5b612971838351602085016137e5565b600082601f8301126138db57600080fd5b815160206138eb6131ac836137c1565b82815260059290921b8401810191818101908684111561390a57600080fd5b8286015b8481101561158657805167ffffffffffffffff81111561392e5760008081fd5b61393c8986838b01016138aa565b84525091830191830161390e565b6000806000806080858703121561396057600080fd5b8451935060208086015167ffffffffffffffff8082111561398057600080fd5b818801915088601f83011261399457600080fd5b81516139a26131ac826137c1565b81815260059190911b8301840190848101908b8311156139c157600080fd5b938501935b828510156139df578451825293850193908501906139c6565b60408b015190985094505050808311156139f857600080fd5b613a0489848a01613815565b94506060880151925080831115613a1a57600080fd5b5050613a28878288016138ca565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60008251613a5c818460208701613428565b9190910192915050565b604081526000613a796040830185613454565b90508260208301529392505050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415613ab257613ab2613a88565b5060010190565b80356137a1816132c3565b600080600060608486031215613ad957600080fd5b833567ffffffffffffffff811115613af057600080fd5b613afc8682870161318d565b9350506020840135613b0d816132c3565b929592945050506040919091013590565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000613b6b60608301888a613b2e565b8281036020840152613b7e818789613b2e565b90508281036040840152613b93818587613b2e565b9998505050505050505050565b608081526000613bb460808301898b613b2e565b8281036020840152613bc781888a613b2e565b90508281036040840152613bdc818688613b2e565b91505082606083015298975050505050505050565b60008060408385031215613c0457600080fd5b823567ffffffffffffffff811115613c1b57600080fd5b613c278582860161318d565b95602094909401359450505050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215613c5e57600080fd5b5051919050565b6001600160a01b03831681526040602082015260006132186040830184613454565b60008060408385031215613c9a57600080fd5b613ca383613791565b9150602083015167ffffffffffffffff811115613cbf57600080fd5b61376e858286016138aa565b600080600080600080600080610100898b031215613ce857600080fd5b883567ffffffffffffffff80821115613d0057600080fd5b613d0c8c838d0161318d565b995060208b0135915080821115613d2257600080fd5b613d2e8c838d0161318d565b9850613d3c60408c01613ab9565b975060608b0135965060808b0135915080821115613d5957600080fd5b50613d668b828c0161318d565b989b979a50959894979660a0860135965060c08601359560e00135945092505050565b60c081526000613d9c60c0830189613454565b8281036020840152613dae8189613454565b90508281036040840152613dc28188613454565b60608401969096525050608081019290925260a0909101529392505050565b6000808335601e19843603018112613df857600080fd5b83018035915067ffffffffffffffff821115613e1357600080fd5b602001915036819003821315612f2157600080fd5b60008060008060008060c08789031215613e4157600080fd5b863567ffffffffffffffff80821115613e5957600080fd5b613e658a838b0161318d565b97506020890135915080821115613e7b57600080fd5b50613e8889828a0161318d565b955050604087013560ff81168114613e9f57600080fd5b9350606087013592506080870135613eb6816132c3565b8092505060a087013590509295509295509295565b60a081526000613ede60a0830188613454565b8281036020840152613ef08188613454565b60ff9690961660408401525050606081019290925260809091015292915050565b600060208284031215613f2357600080fd5b8151612971816132c3565b604081526000613f416040830185613454565b90506001600160a01b03831660208301529392505050565b602081526000613218602083018486613b2e565b600181811c90821680613f8157607f821691505b60208210811415613fa257634e487b7160e01b600052602260045260246000fd5b50919050565b600080600060608486031215613fbd57600080fd5b8335613fc8816132c3565b92506020840135613fd8816132c3565b9150604084013567ffffffffffffffff811115613ff457600080fd5b6140008682870161318d565b9150509250925092565b60a08152600061401e60a083018b8d613b2e565b8281036020840152614031818a8c613b2e565b9050828103604084015261404681888a613b2e565b9050828103606084015261405b818688613b2e565b9150508260808301529a9950505050505050505050565b60008261408f57634e487b7160e01b600052601260045260246000fd5b500490565b60008060008060008060c087890312156140ad57600080fd5b863567ffffffffffffffff808211156140c557600080fd5b6140d18a838b0161318d565b975060208901359150808211156140e757600080fd5b506140f489828a0161318d565b9550506040870135614105816132c3565b959894975094956060810135955060808101359460a0909101359350915050565b6080815260006141396080830187613454565b828103602084015261414b8187613454565b604084019590955250506060015292915050565b6000821982111561417257614172613a88565b500190565b60006101008a83528960208401528060408401526141978184018a613454565b905082810360608401526141ab8189613454565b90506001600160a01b03871660808401528560a084015282810360c08401526141d48186613454565b9150508260e08301529998505050505050505050565b82815260008251614202816020850160208701613428565b919091016020019392505050565b86815285602082015260c06040820152600061422f60c0830187613454565b82810360608401526142418187613454565b6001600160a01b03959095166080840152505060a00152949350505050565b8381526060602082015260006142796060830185613454565b905082604083015294935050505056fe6080604052600160005534801561001557600080fd5b50610324806100256000396000f3fe608060405234801561001057600080fd5b50600436106100355760003560e01c8062f55d9d1461003a5780631cff79cd1461004f575b600080fd5b61004d6100483660046101da565b610079565b005b61006261005d3660046101fc565b6100bb565b60405161007092919061027f565b60405180910390f35b6002600054141561009d5760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff8116ff5b60006060600260005414156100e35760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff85163b610136576040517f6f7c43f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff16848460405161015d9291906102de565b6000604051808303816000865af19150503d806000811461019a576040519150601f19603f3d011682016040523d82523d6000602084013e61019f565b606091505b50600160005590969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101d557600080fd5b919050565b6000602082840312156101ec57600080fd5b6101f5826101b1565b9392505050565b60008060006040848603121561021157600080fd5b61021a846101b1565b9250602084013567ffffffffffffffff8082111561023757600080fd5b818601915086601f83011261024b57600080fd5b81358181111561025a57600080fd5b87602082850101111561026c57600080fd5b6020830194508093505050509250925092565b821515815260006020604081840152835180604085015260005b818110156102b557858101830151858201606001528201610299565b818111156102c7576000606083870101525b50601f01601f191692909201606001949350505050565b818382376000910190815291905056fea264697066735822122032cb5e746816b7fac95205c068b30da37bd40119a57265be331c162cae74712464736f6c63430008090033a26469706673582212207a2dbc57a1c98fee8c2369d9cf383e7218fef232e89a2c6ccc8240252688875764736f6c63430008090033000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102775760003560e01c80638291286c11610160578063bc00c216116100d8578063d26ff2101161008c578063dc97d96211610071578063dc97d96214610681578063f6a5f9f5146106a1578063fbe0a31b146106b457600080fd5b8063d26ff2101461065b578063d38bfff41461066e57600080fd5b8063c031a180116100bd578063c031a180146105dc578063c82fe87a146105ef578063cec7b3591461064857600080fd5b8063bc00c216146105a9578063bd02d0f5146105bc57600080fd5b8063986e791a1161012f578063a3499c7311610114578063a3499c731461057c578063aa1e1f0a1461058f578063b54170841461059657600080fd5b8063986e791a146105495780639ded06df1461056957600080fd5b80638291286c146104ea578063886a625d14610510578063935b13f61461052357806397b87ba61461053657600080fd5b80634656ae2e116101f35780635f6970c3116101c257806367ace8eb116101a757806367ace8eb146104a05780637ae1cfca146104b35780637b1b769e146104d657600080fd5b80635f6970c31461046657806364940c561461047957600080fd5b80634656ae2e1461038e578063585a9fd4146103a15780635aa6e675146103b45780635c60da1b1461040d57600080fd5b806321f8a7211161024a57806326ef699d1161022f57806326ef699d146103415780632a2dae0a1461035457806341d8f26b1461037b57600080fd5b806321f8a721146102df578063269eb65e1461032057600080fd5b806309c5eabe1461027c578063146e2d78146102915780631876eed9146102a45780631c92115f146102cc575b600080fd5b61028f61028a366004612f28565b6106c7565b005b61028f61029f366004612f6a565b610be1565b6102b76102b2366004612fb6565b610c2a565b60405190151581526020015b60405180910390f35b61028f6102da36600461306b565b610d85565b6103086102ed366004613105565b6000908152600260205260409020546001600160a01b031690565b6040516001600160a01b0390911681526020016102c3565b61033361032e3660046131e3565b610df0565b6040519081526020016102c3565b61028f61034f366004613220565b610e04565b6103087f000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f81565b61028f6103893660046132d8565b610e9c565b61028f61039c366004612f6a565b610fbc565b61028f6103af366004612f6a565b611403565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316610308565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3546001600160a01b0316610308565b6102b76104743660046132f5565b6114b1565b6103087f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad081565b61028f6104ae3660046133bc565b611591565b6102b76104c1366004613105565b60009081526004602052604090205460ff1690565b6102b76104e43660046131e3565b50600090565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b3625610333565b61028f61051e366004612f6a565b61177f565b6103086105313660046131e3565b611a2f565b61028f610544366004612f6a565b611a3d565b61055c610557366004613105565b611b1b565b6040516102c39190613480565b61028f610577366004612f28565b611bbd565b61028f61058a366004613493565b611d26565b60006102b7565b61028f6105a43660046134e3565b61203c565b6102b76105b73660046135af565b6120f2565b6103336105ca366004613105565b60009081526020819052604090205490565b61055c6105ea366004613105565b6121c5565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316610308565b6103336106563660046131e3565b6121e2565b6102b7610669366004613105565b6121fc565b61028f61067c3660046132d8565b61220a565b61033361068f366004613105565b60009081526005602052604090205490565b6102b76106af36600461367d565b6122c5565b61028f6106c2366004612f6a565b61234e565b6000806106d683850185613714565b9150915060006106ec83805190602001206123ee565b905060007f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad06001600160a01b03166373e3d66a83856040518363ffffffff1660e01b815260040161073e929190613778565b602060405180830381600087803b15801561075857600080fd5b505af115801561076c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079091906137a6565b905060006060806060878060200190518101906107ad919061394a565b929650909450925090504684146107f0576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8251825181141580610803575081518114155b1561083a576040517fca9a28f500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610bd357600085828151811061085957610859613a34565b6020026020010151905061086c816121fc565b156108775750610bc3565b60008086848151811061088c5761088c613a34565b60200260200101516040516020016108a49190613a4a565b6040516020818303038152906040528051906020012090507f5763814b98a3aa86f212797af3273868b5dd6e2a532d764a79b98ca859e7bbad81141561090c577f886a625d000000000000000000000000000000000000000000000000000000009150610ab5565b7fec78d9c22c08bb9f0ecd5d95571ae83e3f22219c5a9278c3270691d50abfd91b81141561095c577f146e2d78000000000000000000000000000000000000000000000000000000009150610ab5565b7f37ac16aabc4d87540e53151b2b716265cfd6b195db96a9daf8e893c829bbd2338114156109ac577ffbe0a31b000000000000000000000000000000000000000000000000000000009150610ab5565b7ff41504255b911b3042ee4f8786fdf7cf4bcf24ace033fa16af3c8574e025e4368114156109fc577f585a9fd4000000000000000000000000000000000000000000000000000000009150610ab5565b7fda199c0e76f665e0450020791c7f8eacc75f3cdbace313272c28f93e5390b62c811415610a4c577f4656ae2e000000000000000000000000000000000000000000000000000000009150610ab5565b7fb460dcb6fd5797fc0e7ea0f13406c80d30702ba7f73a42bd91394775dcbca718811415610aad5789610a8157505050610bc3565b600099507f97b87ba6000000000000000000000000000000000000000000000000000000009150610ab5565b505050610bc3565b610ac0836001612442565b6000306001600160a01b031683888781518110610adf57610adf613a34565b602002602001015186604051602401610af9929190613a66565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610b379190613a4a565b6000604051808303816000865af19150503d8060008114610b74576040519150601f19603f3d011682016040523d82523d6000602084013e610b79565b606091505b505090508015610bb35760405184907fa74c8847d513feba22a0f0cb38d53081abf97562cdb293926ba243689e7c41ca90600090a2610bbe565b610bbe846000612442565b505050505b610bcc81613a9e565b905061083d565b505050505050505050505050565b333014610c01576040516314e1dbf760e11b815260040160405180910390fd5b60008080610c1185870187613ac4565b925092509250610c2283838361246e565b505050505050565b600080610cdb8b8b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8f018190048102820181019092528d815292508d91508c908190840183828082843760009201919091525050604080516020601f8d018190048102820181019092528b81523393508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b60008181526004602052604090205460ff16925090508115610d7757600081815260046020526040808220805460ff19169055518c917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a2610d7785858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525033925087915061246e9050565b509998505050505050505050565b8181604051610d95929190613b1e565b6040518091039020336001600160a01b03167f30ae6cc78c27e651745bf2ad08a11de83910ac1e347a52f7ac898c0fbef94dae888888888888604051610de096959493929190613b57565b60405180910390a3505050505050565b6000610dfe6105ca836125e1565b92915050565b610e463384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b336001600160a01b03167f651d93f66c4329630e8d0f62488eff599e3be484da587335e8dc0fcf4606272688888888888888604051610e8b9796959493929190613ba0565b60405180910390a250505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b03163314801590610f5257507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b15610f705760405163223aa83d60e11b815260040160405180910390fd5b6001600160a01b038116610fb0576040517fd79d772c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612821565b50565b333014610fdc576040516314e1dbf760e11b815260040160405180910390fd5b600080610feb84860186613bf1565b915091506000610ffa83611a2f565b90506001600160a01b03811661102e578260405163395d09bf60e11b81526004016110259190613480565b60405180910390fd5b600261103984612916565b600281111561104a5761104a613c36565b14156113a0576000611107836040518060200161106690612ed2565b601f1982820381018352601f9091011660408190526110889190602001613a4a565b60408051601f1981840301815282825280516020918201207fff00000000000000000000000000000000000000000000000000000000000000848301526bffffffffffffffffffffffff193060601b16602185015260358401949094526055808401949094528151808403909401845260759092019052815191012090565b905061111b816001600160a01b0316612935565b156111295750505050505050565b60008360405161113890612ed2565b8190604051809103906000f5905080158015611158573d6000803e3d6000fd5b506040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038083166004830181905292935060009283929091631cff79cd91889163a9059cbb60e01b9130918416906370a082319060240160206040518083038186803b1580156111d257600080fd5b505afa1580156111e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061120a9190613c4c565b6040516001600160a01b039092166024830152604482015260640160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199485161790525160e085901b909216825261126b9291600401613c65565b600060405180830381600087803b15801561128557600080fd5b505af1158015611299573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526112c19190810190613c87565b915091508115806112ee57508051158015906112ee5750808060200190518101906112ec91906137a6565b155b1561132757866040517fe217b0ad0000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6040517ef55d9d0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b0384169062f55d9d90602401600060405180830381600087803b15801561137f57600080fd5b505af1158015611393573d6000803e3d6000fd5b5050505050505050610c22565b6040516308a1eee160e01b8152600481018390526001600160a01b038216906308a1eee190602401600060405180830381600087803b1580156113e257600080fd5b505af11580156113f6573d6000803e3d6000fd5b505050505050505b505050565b333014611423576040516314e1dbf760e11b815260040160405180910390fd5b6000808080808080806114388a8c018c613ccb565b9750975097509750975097509750975061145789898989898989612978565b84866001600160a01b03168a7f9991faa1f435675159ffae64b66d7ecfdb55c29755869a18db8497b4392347e08b8b8989898960405161149c96959493929190613d89565b60405180910390a45050505050505050505050565b60008061152c8888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152503392508991506129a59050565b60008181526004602052604090205460ff1692509050811561158657600081815260046020526040808220805460ff191690555189917f91057b069763121972ce22b18b2f319b1520dd4c72f1f94a6395e81ceaf63f4191a25b509695505050505050565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546001600160a01b0316331480159061164757507fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314155b156116655760405163223aa83d60e11b815260040160405180910390fd5b8281811461169f576040517f14a2275f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610c225760008686838181106116be576116be613a34565b90506020028101906116d09190613de1565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525093945088925087915085905081811061171b5761171b613a34565b90506020020135905060006001600160a01b031661173883611a2f565b6001600160a01b03161415611762578160405163395d09bf60e11b81526004016110259190613480565b61176c8282612a03565b50508061177890613a9e565b90506116a2565b33301461179f576040516314e1dbf760e11b815260040160405180910390fd5b600080808080806117b2888a018a613e28565b95509550955095509550955060006001600160a01b03166117d286611a2f565b6001600160a01b03161461181457846040517faa7e8b320000000000000000000000000000000000000000000000000000000081526004016110259190613480565b61181e8582612a03565b6001600160a01b03821661198a5760008560405160200161183f9190613a4a565b604051602081830303815290604052805190602001209050611862866001612a5b565b6000807f000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f6001600160a01b0316636fc95b3460e01b8a8a8a8a886040516024016118b0959493929190613ecb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516118ee9190613a4a565b600060405180830381855af49150503d8060008114611929576040519150601f19603f3d011682016040523d82523d6000602084013e61192e565b606091505b50915091508161196c57876040517f86d527430000000000000000000000000000000000000000000000000000000081526004016110259190613480565b808060200190518101906119809190613f11565b94505050506119e1565b6001600160a01b0382163b6119d6576040517fc5ccddde0000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401611025565b6119e1856002612a5b565b7fbf90b5a1ec9763e8bf4b9245cef0c28db92bab309fc2c5177f17814f382469388583604051611a12929190613f2e565b60405180910390a1611a248583612a8b565b505050505050505050565b6000610dfe6102ed83612acd565b333014611a5d576040516314e1dbf760e11b815260040160405180910390fd5b7f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a5218728383604051611a8e929190613f59565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0169063d289d1cb90611ae49086908690600401613f59565b600060405180830381600087803b158015611afe57600080fd5b505af1158015611b12573d6000803e3d6000fd5b50505050505050565b6000818152600160205260409020805460609190611b3890613f6d565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6490613f6d565b8015611bb15780601f10611b8657610100808354040283529160200191611bb1565b820191906000526020600020905b815481529060010190602001808311611b9457829003601f168201915b50505050509050919050565b7f00000000000000000000000099b5fa03a5ea4315725c43346e55a6a6fbd940986001600160a01b0316301415611c20576040517fbf10dd3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080611c3084860186613fa8565b919450925090506001600160a01b03831615611c4f57611c4f83612b02565b6001600160a01b03821615611c6757611c6782612821565b805115611d1f577f192e759e55f359cd9832b5c0c6e38e4b6df5c5ca33f3bd5c90738e865a52187281604051611c9d9190613480565b60405180910390a160405163d289d1cb60e01b81526001600160a01b037f000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0169063d289d1cb90611cf1908490600401613480565b600060405180830381600087803b158015611d0b57600080fd5b505af1158015611a24573d6000803e3d6000fd5b5050505050565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b03163314611d9957604051632d5be4cb60e21b815260040160405180910390fd5b836001600160a01b03163f8314611ddc576040517f8f84fb2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836001600160a01b0316638291286c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1557600080fd5b505afa158015611e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4d9190613c4c565b7fad2ae48b4d93c587cd1f0f8f269b84f57dbe98bbe5c61c4b6d324e6a667b362514611ea5576040517f68155f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038516907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2611f50847f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60005260026020527f11141f466c69fd409e1990e063b49cd6d61ed2ecff27a2e402e259ca6b9a01a3805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b8015612036576000846001600160a01b0316639ded06df60e01b8484604051602401611f7d929190613f59565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051611fbb9190613a4a565b600060405180830381855af49150503d8060008114611ff6576040519150601f19603f3d011682016040523d82523d6000602084013e611ffb565b606091505b5050905080611d1f576040517f97905dfb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b61207e3384848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250612616915050565b848460405161208e929190613b1e565b6040518091039020336001600160a01b03167f7e50569d26be643bda7757722291ec66b1be66d8283474ae3fab5a98f878a7a28b8b8b8b8b8b8b8b8b6040516120df9998979695949392919061400a565b60405180910390a3505050505050505050565b60006121b66104c18c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b81528e93508d9250908c908c90819084018382808284376000920191909152508c925061257d915050565b9b9a5050505050505050505050565b6000818152600360205260409020805460609190611b3890613f6d565b6000610dfe6105ca836121f761546042614072565b612bf7565b6000610dfe6104c183612c4c565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546001600160a01b0316331461227d57604051632d5be4cb60e21b815260040160405180910390fd5b6001600160a01b0381166122bc576040517e63186c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fb981612b02565b60006123426104c18989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a90819084018382808284376000920191909152508a92508991506129a59050565b98975050505050505050565b33301461236e576040516314e1dbf760e11b815260040160405180910390fd5b60008080808080612381888a018a614094565b95509550955095509550955061239a8787878787612c87565b82846001600160a01b0316887f44e4f8f6bd682c5a3aeba93601ab07cb4d1f21b2aab1ae4880d9577919309aa4898987876040516123db9493929190614126565b60405180910390a4505050505050505050565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c015b604051602081830303815290604052805190602001209050919050565b61246a61244e83612c4c565b6000908152600460205260409020805460ff1916831515179055565b5050565b600061247984611a2f565b90506001600160a01b0381166124a4578360405163395d09bf60e11b81526004016110259190613480565b6124c184836124b2876121e2565b6124bc919061415f565b612c97565b60026124cc85612916565b60028111156124dd576124dd613c36565b14156124fc576124f76001600160a01b0382168484612d12565b612036565b6040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152602482018490528216906340c10f1990604401600060405180830381600087803b15801561255f57600080fd5b505af1158015612573573d6000803e3d6000fd5b5050505050505050565b60007fb7ad972b71475860613db3ba1fe699b886c878f9002a09250dc25e769eb19a10888888888888886040516020016125be989796959493929190614177565b604051602081830303815290604052805190602001209050979650505050505050565b60007feee9348b4aaba3647b1612b2724f18e93b9299da26fb321c7b3fda135d7dea87826040516020016124259291906141ea565b600061262183611a2f565b90506001600160a01b03811661264c578260405163395d09bf60e11b81526004016110259190613480565b81612683576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061268e84612916565b905060028160028111156126a4576126a4613c36565b14156126c4576126bf6001600160a01b038316863086612d75565b611d1f565b60018160028111156126d8576126d8613c36565b141561274b57604080516001600160a01b03878116602483015260448083018790528351808403909101815260649092019092526020810180516001600160e01b03167f79cc6790000000000000000000000000000000000000000000000000000000001790526126bf91841690612dc6565b6040517f31eecaf4000000000000000000000000000000000000000000000000000000008152600060048201526127f49086906001600160a01b038516906331eecaf49060240160206040518083038186803b1580156127aa57600080fd5b505afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e29190613f11565b6001600160a01b038516919086612d75565b6040516308a1eee160e01b8152600060048201526001600160a01b038316906308a1eee190602401611cf1565b7f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d92600090815260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b546040516001600160a01b03848116939216917fa9303c860c5de3c0c866c354d281785c89778ac5ca2dffdf12841c45cd4e1e6e91a37f627f0c11732837b3240a2de89c0b6343512886dd50978b99c76a68c6416a4d9260005260026020527f5481d72119428687fe3dcb3fa9e7cd30ab3806d148eeeb57edec06ebe9140c8b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60006129246105ca83612e9d565b6002811115610dfe57610dfe613c36565b60006001600160a01b0382163f801580159061297157507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708114155b9392505050565b611b1261298a8888888888888861257d565b6000908152600460205260409020805460ff19166001179055565b60007f07b0d4304f82012bd3b70b1d531c160e326067c90829e2a3d386722ad10b89c386868686866040516020016129e296959493929190614210565b60405160208183030381529060405280519060200120905095945050505050565b7fd99446c1d76385bb5519ccfb5274abcfd5896dfc22405e40010fde217f018a188282604051612a34929190613a66565b60405180910390a161246a612a48836125e1565b8260009182526020829052604090912055565b61246a612a6783612e9d565b826002811115612a7957612a79613c36565b60009182526020829052604090912055565b61246a612a9783612acd565b6000908152600260205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055565b60007fc4e632779a6a7838736dd7e5e6a0eadf171dd37dfb6230720e265576dfcf42bb826040516020016124259291906141ea565b7fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f909600090815260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561546040516001600160a01b03848116939216917f5f56bee8cffbe9a78652a74a60705edede02af10b0bbb888ca44b79a0d42ce8091a37fabea6fd3db56a6e6d0242111b43ebb13d1c42709651c032c7894962023a1f90960005260026020527f50ebfbbf514da209fd9183952fc61a8193cdfd37e05a2948db24990e264a4561805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03831617905550565b60007f2f8851fe0d6d537e552a4f25b7a3167d48eb1292622c71d84630a2a44757bced8383604051602001612c2e93929190614260565b60405160208183030381529060405280519060200120905092915050565b604080517f957705a374326b30f4a1069c936d736cc9993ed6c820b4e0e2fd94a8beca0d1d6020820152908101829052600090606001612425565b611d1f61298a86868686866129a5565b6000612ca283610df0565b9050600081118015612cb357508082115b15612cec57826040517f037f60e50000000000000000000000000000000000000000000000000000000081526004016110259190613480565b6113fe612cff846121f761546042614072565b8360009182526020829052604090912055565b6040516001600160a01b0383166024820152604481018290526113fe90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612dc6565b6040516001600160a01b03808516602483015283166044820152606481018290526120369085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401612d3e565b600080836001600160a01b031683604051612de19190613a4a565b6000604051808303816000865af19150503d8060008114612e1e576040519150601f19603f3d011682016040523d82523d6000602084013e612e23565b606091505b50915091506000828015612e4f575081511580612e4f575081806020019051810190612e4f91906137a6565b9050801580612e6657506001600160a01b0385163b155b15611d1f576040517f045c4b0200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60007fa80d2259af55890618ec2eeb3ac72de4bdba22529bb14845d8a3d712d1c3f621826040516020016124259291906141ea565b6103498061428a83390190565b60008083601f840112612ef157600080fd5b50813567ffffffffffffffff811115612f0957600080fd5b602083019150836020828501011115612f2157600080fd5b9250929050565b60008060208385031215612f3b57600080fd5b823567ffffffffffffffff811115612f5257600080fd5b612f5e85828601612edf565b90969095509350505050565b600080600060408486031215612f7f57600080fd5b833567ffffffffffffffff811115612f9657600080fd5b612fa286828701612edf565b909790965060209590950135949350505050565b600080600080600080600080600060c08a8c031215612fd457600080fd5b8935985060208a013567ffffffffffffffff80821115612ff357600080fd5b612fff8d838e01612edf565b909a50985060408c013591508082111561301857600080fd5b6130248d838e01612edf565b909850965060608c0135955060808c013591508082111561304457600080fd5b506130518c828d01612edf565b9a9d999c50979a9699959894979660a00135949350505050565b6000806000806000806060878903121561308457600080fd5b863567ffffffffffffffff8082111561309c57600080fd5b6130a88a838b01612edf565b909850965060208901359150808211156130c157600080fd5b6130cd8a838b01612edf565b909650945060408901359150808211156130e657600080fd5b506130f389828a01612edf565b979a9699509497509295939492505050565b60006020828403121561311757600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561315d5761315d61311e565b604052919050565b600067ffffffffffffffff82111561317f5761317f61311e565b50601f01601f191660200190565b600082601f83011261319e57600080fd5b81356131b16131ac82613165565b613134565b8181528460208386010111156131c657600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156131f557600080fd5b813567ffffffffffffffff81111561320c57600080fd5b6132188482850161318d565b949350505050565b60008060008060008060006080888a03121561323b57600080fd5b873567ffffffffffffffff8082111561325357600080fd5b61325f8b838c01612edf565b909950975060208a013591508082111561327857600080fd5b6132848b838c01612edf565b909750955060408a013591508082111561329d57600080fd5b506132aa8a828b01612edf565b989b979a50959894979596606090950135949350505050565b6001600160a01b0381168114610fb957600080fd5b6000602082840312156132ea57600080fd5b8135612971816132c3565b6000806000806000806080878903121561330e57600080fd5b86359550602087013567ffffffffffffffff8082111561332d57600080fd5b6133398a838b01612edf565b9097509550604089013591508082111561335257600080fd5b5061335f89828a01612edf565b979a9699509497949695606090950135949350505050565b60008083601f84011261338957600080fd5b50813567ffffffffffffffff8111156133a157600080fd5b6020830191508360208260051b8501011115612f2157600080fd5b600080600080604085870312156133d257600080fd5b843567ffffffffffffffff808211156133ea57600080fd5b6133f688838901613377565b9096509450602087013591508082111561340f57600080fd5b5061341c87828801613377565b95989497509550505050565b60005b8381101561344357818101518382015260200161342b565b838111156120365750506000910152565b6000815180845261346c816020860160208601613428565b601f01601f19169290920160200192915050565b6020815260006129716020830184613454565b600080600080606085870312156134a957600080fd5b84356134b4816132c3565b935060208501359250604085013567ffffffffffffffff8111156134d757600080fd5b61341c87828801612edf565b600080600080600080600080600060a08a8c03121561350157600080fd5b893567ffffffffffffffff8082111561351957600080fd5b6135258d838e01612edf565b909b50995060208c013591508082111561353e57600080fd5b61354a8d838e01612edf565b909950975060408c013591508082111561356357600080fd5b61356f8d838e01612edf565b909750955060608c013591508082111561358857600080fd5b506135958c828d01612edf565b9a9d999c50979a9699959894979660800135949350505050565b60008060008060008060008060008060e08b8d0312156135ce57600080fd5b8a35995060208b013567ffffffffffffffff808211156135ed57600080fd5b6135f98e838f01612edf565b909b50995060408d013591508082111561361257600080fd5b61361e8e838f01612edf565b909950975060608d01359150613633826132c3565b90955060808c0135945060a08c0135908082111561365057600080fd5b5061365d8d828e01612edf565b9150809450508092505060c08b013590509295989b9194979a5092959850565b600080600080600080600060a0888a03121561369857600080fd5b87359650602088013567ffffffffffffffff808211156136b757600080fd5b6136c38b838c01612edf565b909850965060408a01359150808211156136dc57600080fd5b506136e98a828b01612edf565b90955093505060608801356136fd816132c3565b809250506080880135905092959891949750929550565b6000806040838503121561372757600080fd5b823567ffffffffffffffff8082111561373f57600080fd5b61374b8683870161318d565b9350602085013591508082111561376157600080fd5b5061376e8582860161318d565b9150509250929050565b8281526040602082015260006132186040830184613454565b805180151581146137a157600080fd5b919050565b6000602082840312156137b857600080fd5b61297182613791565b600067ffffffffffffffff8211156137db576137db61311e565b5060051b60200190565b60006137f36131ac84613165565b905082815283838301111561380757600080fd5b612971836020830184613428565b600082601f83011261382657600080fd5b815160206138366131ac836137c1565b82815260059290921b8401810191818101908684111561385557600080fd5b8286015b8481101561158657805167ffffffffffffffff8111156138795760008081fd5b8701603f8101891361388b5760008081fd5b61389c8986830151604084016137e5565b845250918301918301613859565b600082601f8301126138bb57600080fd5b612971838351602085016137e5565b600082601f8301126138db57600080fd5b815160206138eb6131ac836137c1565b82815260059290921b8401810191818101908684111561390a57600080fd5b8286015b8481101561158657805167ffffffffffffffff81111561392e5760008081fd5b61393c8986838b01016138aa565b84525091830191830161390e565b6000806000806080858703121561396057600080fd5b8451935060208086015167ffffffffffffffff8082111561398057600080fd5b818801915088601f83011261399457600080fd5b81516139a26131ac826137c1565b81815260059190911b8301840190848101908b8311156139c157600080fd5b938501935b828510156139df578451825293850193908501906139c6565b60408b015190985094505050808311156139f857600080fd5b613a0489848a01613815565b94506060880151925080831115613a1a57600080fd5b5050613a28878288016138ca565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60008251613a5c818460208701613428565b9190910192915050565b604081526000613a796040830185613454565b90508260208301529392505050565b634e487b7160e01b600052601160045260246000fd5b6000600019821415613ab257613ab2613a88565b5060010190565b80356137a1816132c3565b600080600060608486031215613ad957600080fd5b833567ffffffffffffffff811115613af057600080fd5b613afc8682870161318d565b9350506020840135613b0d816132c3565b929592945050506040919091013590565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b606081526000613b6b60608301888a613b2e565b8281036020840152613b7e818789613b2e565b90508281036040840152613b93818587613b2e565b9998505050505050505050565b608081526000613bb460808301898b613b2e565b8281036020840152613bc781888a613b2e565b90508281036040840152613bdc818688613b2e565b91505082606083015298975050505050505050565b60008060408385031215613c0457600080fd5b823567ffffffffffffffff811115613c1b57600080fd5b613c278582860161318d565b95602094909401359450505050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215613c5e57600080fd5b5051919050565b6001600160a01b03831681526040602082015260006132186040830184613454565b60008060408385031215613c9a57600080fd5b613ca383613791565b9150602083015167ffffffffffffffff811115613cbf57600080fd5b61376e858286016138aa565b600080600080600080600080610100898b031215613ce857600080fd5b883567ffffffffffffffff80821115613d0057600080fd5b613d0c8c838d0161318d565b995060208b0135915080821115613d2257600080fd5b613d2e8c838d0161318d565b9850613d3c60408c01613ab9565b975060608b0135965060808b0135915080821115613d5957600080fd5b50613d668b828c0161318d565b989b979a50959894979660a0860135965060c08601359560e00135945092505050565b60c081526000613d9c60c0830189613454565b8281036020840152613dae8189613454565b90508281036040840152613dc28188613454565b60608401969096525050608081019290925260a0909101529392505050565b6000808335601e19843603018112613df857600080fd5b83018035915067ffffffffffffffff821115613e1357600080fd5b602001915036819003821315612f2157600080fd5b60008060008060008060c08789031215613e4157600080fd5b863567ffffffffffffffff80821115613e5957600080fd5b613e658a838b0161318d565b97506020890135915080821115613e7b57600080fd5b50613e8889828a0161318d565b955050604087013560ff81168114613e9f57600080fd5b9350606087013592506080870135613eb6816132c3565b8092505060a087013590509295509295509295565b60a081526000613ede60a0830188613454565b8281036020840152613ef08188613454565b60ff9690961660408401525050606081019290925260809091015292915050565b600060208284031215613f2357600080fd5b8151612971816132c3565b604081526000613f416040830185613454565b90506001600160a01b03831660208301529392505050565b602081526000613218602083018486613b2e565b600181811c90821680613f8157607f821691505b60208210811415613fa257634e487b7160e01b600052602260045260246000fd5b50919050565b600080600060608486031215613fbd57600080fd5b8335613fc8816132c3565b92506020840135613fd8816132c3565b9150604084013567ffffffffffffffff811115613ff457600080fd5b6140008682870161318d565b9150509250925092565b60a08152600061401e60a083018b8d613b2e565b8281036020840152614031818a8c613b2e565b9050828103604084015261404681888a613b2e565b9050828103606084015261405b818688613b2e565b9150508260808301529a9950505050505050505050565b60008261408f57634e487b7160e01b600052601260045260246000fd5b500490565b60008060008060008060c087890312156140ad57600080fd5b863567ffffffffffffffff808211156140c557600080fd5b6140d18a838b0161318d565b975060208901359150808211156140e757600080fd5b506140f489828a0161318d565b9550506040870135614105816132c3565b959894975094956060810135955060808101359460a0909101359350915050565b6080815260006141396080830187613454565b828103602084015261414b8187613454565b604084019590955250506060015292915050565b6000821982111561417257614172613a88565b500190565b60006101008a83528960208401528060408401526141978184018a613454565b905082810360608401526141ab8189613454565b90506001600160a01b03871660808401528560a084015282810360c08401526141d48186613454565b9150508260e08301529998505050505050505050565b82815260008251614202816020850160208701613428565b919091016020019392505050565b86815285602082015260c06040820152600061422f60c0830187613454565b82810360608401526142418187613454565b6001600160a01b03959095166080840152505060a00152949350505050565b8381526060602082015260006142796060830185613454565b905082604083015294935050505056fe6080604052600160005534801561001557600080fd5b50610324806100256000396000f3fe608060405234801561001057600080fd5b50600436106100355760003560e01c8062f55d9d1461003a5780631cff79cd1461004f575b600080fd5b61004d6100483660046101da565b610079565b005b61006261005d3660046101fc565b6100bb565b60405161007092919061027f565b60405180910390f35b6002600054141561009d5760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff8116ff5b60006060600260005414156100e35760405163caa30f5560e01b815260040160405180910390fd5b600260005573ffffffffffffffffffffffffffffffffffffffff85163b610136576040517f6f7c43f100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff16848460405161015d9291906102de565b6000604051808303816000865af19150503d806000811461019a576040519150601f19603f3d011682016040523d82523d6000602084013e61019f565b606091505b50600160005590969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101d557600080fd5b919050565b6000602082840312156101ec57600080fd5b6101f5826101b1565b9392505050565b60008060006040848603121561021157600080fd5b61021a846101b1565b9250602084013567ffffffffffffffff8082111561023757600080fd5b818601915086601f83011261024b57600080fd5b81358181111561025a57600080fd5b87602082850101111561026c57600080fd5b6020830194508093505050509250925092565b821515815260006020604081840152835180604085015260005b818110156102b557858101830151858201606001528201610299565b818111156102c7576000606083870101525b50601f01601f191692909201606001949350505050565b818382376000910190815291905056fea264697066735822122032cb5e746816b7fac95205c068b30da37bd40119a57265be331c162cae74712464736f6c63430008090033a26469706673582212207a2dbc57a1c98fee8c2369d9cf383e7218fef232e89a2c6ccc8240252688875764736f6c63430008090033

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

000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f

-----Decoded View---------------
Arg [0] : authModule_ (address): 0xE3B83f79Fbf01B25659f8A814945aB82186A8AD0
Arg [1] : tokenDeployer_ (address): 0xb28478319B64f8D47e19A120209A211D902F8b8f

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e3b83f79fbf01b25659f8a814945ab82186a8ad0
Arg [1] : 000000000000000000000000b28478319b64f8d47e19a120209a211d902f8b8f


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  ]

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.