ETH Price: $2,858.57 (-2.81%)

Contract

0xD6965a9b739240dB7ACD36E3AFb2dfe1dAE7c694

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TokenManagerDelegateV2

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.8.18;

import "../interfaces/IWrappedNFT721.sol";
import "../interfaces/IWrappedNFT1155.sol";
import "./TokenManagerDelegate.sol";
import "../components/Proxy.sol";

/**
 * @title TokenManagerDelegateV2
 * @dev Enhanced version of TokenManagerDelegate with NFT support
 * This contract provides:
 * - NFT token pair type management
 * - NFT minting and burning functionality
 * - Operator role management
 * - Support for ERC721 and ERC1155 tokens
 */
contract TokenManagerDelegateV2 is TokenManagerDelegate, Proxy {

    /************************************************************
     **
     ** STATE VARIABLES
     **
     ************************************************************/
    /// @notice Address of the operator who can set token pair types
    address public operator;

    /// @notice Enumeration of supported token types for cross-chain operations
    /// @dev Defines the types of tokens that can be transferred across chains
    /// - ERC20: Standard fungible tokens
    /// - ERC721: Non-fungible tokens
    /// - ERC1155: Multi-token standard
    enum TokenCrossType {ERC20, ERC721, ERC1155}
    
    /// @notice Mapping from token pair ID to token type
    mapping(uint => uint8) public mapTokenPairType;


    /************************************************************
     **
     ** EVENTS
     **
     ************************************************************/
     /// @notice Emitted when the operator address is changed
     /// @param oldOperator Previous operator address
     /// @param newOperator New operator address
     event SetOperator(address indexed oldOperator, address indexed newOperator);
     
     /// @notice Emitted when a token pair type is set
     /// @param tokenPairId ID of the token pair
     /// @param tokenPairType Type of the token pair
     event SetTokenPairType(uint indexed tokenPairId, uint indexed tokenPairType);

    /**
     * @notice Modifier to restrict function access to operator only
     * @dev Throws if called by any account other than the operator
     */
    modifier onlyOperator() {
        require(msg.sender == operator, "not operator");
        _;
    }

    /************************************************************
     **
     ** MANIPULATIONS
     **
     ************************************************************/
    /**
     * @notice Sets token pair types for multiple token pairs
     * @dev Can only be called by the operator
     * @param tokenPairIds Array of token pair IDs
     * @param tokenPairTypes Array of token pair types
     * Requirements:
     * - Arrays must have the same length
     * - Caller must be the operator
     * Emits:
     * - SetTokenPairType event for each token pair
     */
    function setTokenPairTypes(uint[] calldata tokenPairIds, uint8[] calldata tokenPairTypes)
        external
        onlyOperator
    {
       require(tokenPairIds.length == tokenPairTypes.length, "length mismatch");
       for(uint idx = 0; idx < tokenPairIds.length; ++idx) {
          mapTokenPairType[tokenPairIds[idx]] = tokenPairTypes[idx];
          emit SetTokenPairType(tokenPairIds[idx], tokenPairTypes[idx]);
       }
    }

    /**
     * @notice Sets the operator address
     * @dev Can only be called by the contract owner
     * @param account New operator address
     * Emits:
     * - SetOperator event with old and new operator addresses
     */
    function setOperator(address account)
        external
        onlyOwner
    {
       emit SetOperator(operator, account);
       operator = account;
    }

    //*****************************************************************************
    //*****************************************************************************
    // ERC1155
    //*****************************************************************************
    //*****************************************************************************
    /**
     * @notice Mints NFTs of specified type
     * @dev Can only be called by admin
     * @param tokenCrossType Type of NFT (ERC721 or ERC1155)
     * @param tokenAddress Address of the NFT contract
     * @param to Address to receive the NFTs
     * @param tokenIDs ID of the NFT to mint
     * @param values Amount of NFTs to mint (for ERC1155)
     * @param data Additional data for the NFT
     * Requirements:
     * - Caller must be admin
     * - Token type must be valid
     */
    function mintNFT(
        uint    tokenCrossType,
        address tokenAddress,
        address to,
        uint[] calldata tokenIDs,
        uint[] calldata values,
        bytes  calldata data
    )
        external
        onlyAdmin
    {
        if(tokenCrossType == uint(TokenCrossType.ERC721)) {
            IWrappedNFT721(tokenAddress).mintBatch(to, tokenIDs, data);
        }
        else if(tokenCrossType == uint(TokenCrossType.ERC1155)) {
            IWrappedNFT1155(tokenAddress).mintBatch(to, tokenIDs, values, data);
        }
        else {
            require(false, "Invalid NFT type");
        }
    }

    /**
     * @notice Burns NFTs of specified type
     * @dev Can only be called by admin
     * @param tokenCrossType Type of NFT (ERC721 or ERC1155)
     * @param tokenAddress Address of the NFT contract
     * @param from Address to burn NFTs from
     * @param tokenIDs ID of the NFT to burn
     * @param values Amount of NFTs to burn (for ERC1155)
     * Requirements:
     * - Caller must be admin
     * - Token type must be valid
     */
    function burnNFT(
        uint    tokenCrossType,
        address tokenAddress,
        address from,
        uint[] calldata tokenIDs,
        uint[] calldata values
    )
        external
        onlyAdmin
    {
        if(tokenCrossType == uint(TokenCrossType.ERC721)) {
            IWrappedNFT721(tokenAddress).burnBatch(from, tokenIDs);
        }
        else if(tokenCrossType == uint(TokenCrossType.ERC1155)) {
            IWrappedNFT1155(tokenAddress).burnBatch(from, tokenIDs, values);
        }
        else {
            require(false, "Invalid NFT type");
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys `amount` tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 amount) public virtual {
        _burn(_msgSender(), amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, deducting from the caller's
     * allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `amount`.
     */
    function burnFrom(address account, uint256 amount) public virtual {
        _spendAllowance(account, _msgSender(), amount);
        _burn(account, amount);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

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

pragma solidity ^0.8.0;

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

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

    /**
     * @dev Returns the 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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}

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

pragma solidity ^0.8.0;

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

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

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

import "./Owned.sol";

/**
 * @title Admin
 * @dev Contract for managing administrative access control
 * This contract provides functionality for managing admin addresses
 * and controlling access to administrative functions
 * 
 * Key features:
 * - Admin address management
 * - Access control through modifiers
 * - Admin addition and removal
 * 
 * @custom:security
 * - Inherits Owned contract for ownership management
 * - Only owner can add/remove admins
 * - Only admins can access protected functions
 */
contract Admin is Owned {
    /**
     * @dev Mapping of addresses to their admin status
     * 
     * @custom:usage
     * - Used to track admin addresses
     * - Provides quick lookup for admin status
     * - Supports admin access control
     */
    mapping(address => bool) public mapAdmin;

    /**
     * @dev Emitted when a new admin is added
     * 
     * @param admin The address of the newly added admin
     */
    event AddAdmin(address admin);

    /**
     * @dev Emitted when an admin is removed
     * 
     * @param admin The address of the removed admin
     */
    event RemoveAdmin(address admin);

    /**
     * @dev Modifier to restrict function access to admin addresses only
     * 
     * @custom:requirements
     * - Caller must be an admin
     * 
     * @custom:reverts
     * - If caller is not an admin
     */
    modifier onlyAdmin() {
        require(mapAdmin[msg.sender], "not admin");
        _;
    }

    /**
     * @dev Adds a new admin address
     * 
     * @param admin The address to be added as admin
     * 
     * @custom:requirements
     * - Caller must be the contract owner
     * 
     * @custom:effects
     * - Sets admin status for the address
     * - Emits AddAdmin event
     */
    function addAdmin(
        address admin
    )
        external
        onlyOwner
    {
        mapAdmin[admin] = true;

        emit AddAdmin(admin);
    }

    /**
     * @dev Removes an admin address
     * 
     * @param admin The address to be removed from admin status
     * 
     * @custom:requirements
     * - Caller must be the contract owner
     * 
     * @custom:effects
     * - Removes admin status for the address
     * - Emits RemoveAdmin event
     */
    function removeAdmin(
        address admin
    )
        external
        onlyOwner
    {
        delete mapAdmin[admin];

        emit RemoveAdmin(admin);
    }
}

File 10 of 19 : BasicStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

import "../lib/BasicStorageLib.sol";

/**
 * @title BasicStorage
 * @dev Base contract for managing different types of storage data
 * This contract provides basic storage functionality for various data types
 * using the BasicStorageLib library
 * 
 * Key features:
 * - Multiple data type storage support
 * - Library-based storage management
 * - Internal storage access
 * 
 * @custom:usage
 * - Used as base contract for storage functionality
 * - Provides structured storage for different data types
 * - Supports inheritance for storage management
 */
contract BasicStorage {
    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    //// basic variables
    /**
     * @dev Library usage declarations for different data types
     * 
     * @custom:usage
     * - UintData: For unsigned integer storage
     * - BoolData: For boolean storage
     * - AddressData: For address storage
     * - BytesData: For bytes storage
     * - StringData: For string storage
     */
    using BasicStorageLib for BasicStorageLib.UintData;
    using BasicStorageLib for BasicStorageLib.BoolData;
    using BasicStorageLib for BasicStorageLib.AddressData;
    using BasicStorageLib for BasicStorageLib.BytesData;
    using BasicStorageLib for BasicStorageLib.StringData;

    /**
     * @dev Internal storage variables for different data types
     * 
     * @custom:usage
     * - uintData: Stores unsigned integers
     * - boolData: Stores boolean values
     * - addressData: Stores addresses
     * - bytesData: Stores bytes data
     * - stringData: Stores strings
     * 
     * @custom:security
     * - Internal visibility for controlled access
     * - Library-based storage management
     */
    BasicStorageLib.UintData    internal uintData;
    BasicStorageLib.BoolData    internal boolData;
    BasicStorageLib.AddressData internal addressData;
    BasicStorageLib.BytesData   internal bytesData;
    BasicStorageLib.StringData  internal stringData;
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

/**
 * @title Owned
 * @dev Base contract for ownership management
 * This contract provides functionality for managing contract ownership
 * with support for ownership transfer and renunciation
 * 
 * Key features:
 * - Ownership assignment
 * - Ownership transfer
 * - Ownership renunciation
 * - Two-step ownership transfer
 * 
 * @custom:security
 * - Owner-only access control
 * - Safe ownership transfer
 * - Ownership renunciation capability
 */
contract Owned {

    /**
     * @dev Emitted when ownership is transferred
     * 
     * @param previousOwner Address of the previous owner
     * @param newOwner Address of the new owner
     */
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Modifier to restrict function access to owner only
     * 
     * @custom:requirements
     * - Caller must be the contract owner
     * 
     * @custom:reverts
     * - If caller is not the owner
     */
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    /**
     * @dev Public state variable for contract owner
     * 
     * @custom:usage
     * - Stores current owner address
     * - Accessible for external queries
     * - Modified through ownership functions
     */
    address public owner;

    /**
     * @dev Constructor assigns initial owner
     * 
     * @custom:effects
     * - Sets initial owner to contract deployer
     */
    constructor() {
        owner = msg.sender;
    }

    /**
     * @dev Public state variable for pending owner
     * 
     * @custom:usage
     * - Stores address of pending owner
     * - Used in two-step ownership transfer
     */
    address public newOwner;

    /**
     * @dev Transfers ownership to a new address
     * 
     * @param _newOwner Address of the new owner
     * 
     * @custom:requirements
     * - Caller must be the current owner
     * - New owner address must not be zero
     * 
     * @custom:effects
     * - Updates owner address
     * - Emits OwnershipTransferred event
     */
    function transferOwner(address _newOwner) public onlyOwner {
        require(_newOwner != address(0), "New owner is the zero address");
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
    }

    /**
     * @dev Initiates two-step ownership transfer
     * 
     * @param _newOwner Address of the new owner
     * 
     * @custom:requirements
     * - Caller must be the current owner
     * 
     * @custom:effects
     * - Sets pending owner address
     */
    function changeOwner(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }

    /**
     * @dev Accepts pending ownership transfer
     * 
     * @custom:requirements
     * - Caller must be the pending owner
     * 
     * @custom:effects
     * - Updates owner address to pending owner
     */
    function acceptOwnership() public {
        if (msg.sender == newOwner) {
            owner = newOwner;
        }
    }

    /**
     * @dev Renounces ownership of the contract
     * 
     * @custom:requirements
     * - Caller must be the current owner
     * 
     * @custom:effects
     * - Sets owner to zero address
     * - Makes contract unowned
     */
    function renounceOwnership() public onlyOwner {
        owner = address(0);
    }
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

/**
 * @title Proxy
 * @dev Base contract for proxy pattern implementation
 * This contract provides functionality for delegating calls to implementation contracts
 * and supports contract upgradeability
 * 
 * Key features:
 * - Implementation contract delegation
 * - Contract upgrade support
 * - Fallback handling
 * - Receive function support
 * 
 * @custom:security
 * - Implementation address validation
 * - Safe delegatecall execution
 * - Proper return data handling
 */
contract Proxy {

    /**
     * @dev Emitted when the implementation contract is upgraded
     * 
     * @param implementation Address of the new implementation contract
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Internal storage for implementation contract address
     * 
     * @custom:usage
     * - Stores current implementation address
     * - Used for delegatecall operations
     * - Modified through upgrade operations
     */
    address internal _implementation;

    /**
     * @dev Returns the current implementation contract address
     * 
     * @return Address of the current implementation contract
     */
    function implementation() public view returns (address) {
        return _implementation;
    }

    /**
     * @dev Internal function to handle fallback calls
     * Delegates all calls to the implementation contract
     * 
     * @custom:requirements
     * - Implementation contract must be set
     * 
     * @custom:effects
     * - Executes delegatecall to implementation
     * - Handles return data
     * 
     * @custom:reverts
     * - If implementation contract is not set
     * - If delegatecall fails
     */
    function _fallback() internal {
        address _impl = _implementation;
        require(_impl != address(0), "implementation contract not set");

        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)

            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }

    /**
     * @dev Fallback function to handle unknown function calls
     * Delegates all calls to the implementation contract
     * 
     * @custom:effects
     * - Forwards call to _fallback
     */
    fallback() external payable {
        return _fallback();
    }

    /**
     * @dev Receive function to handle incoming ETH
     * Delegates all calls to the implementation contract
     * 
     * @custom:effects
     * - Forwards call to _fallback
     */
    receive() external payable {
        return _fallback();
    }
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface IWrappedNFT1155 {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
    function transferOwner(address) external;
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function update(string calldata, string calldata) external;

    function burnBatch(address , uint256[] calldata , uint256[] calldata ) external;
    function mintBatch(address , uint256[] calldata , uint256[] calldata , bytes calldata) external;
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface IWrappedNFT721 {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
    function transferOwner(address) external;
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function burn(address, uint) external;
    function update(string calldata, string calldata) external;
    function mint(address, uint, bytes calldata) external;

    function burnBatch(address , uint256[] calldata) external;
    function mintBatch(address , uint256[] calldata , bytes calldata) external;
}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

interface IWrappedToken {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
    function transferOwner(address) external;
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function mint(address, uint) external;
    function burn(address, uint) external;
    function update(string memory, string memory) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.18;

/**
 * @title BasicStorageLib
 * @dev Library for basic storage operations with support for multiple data types
 * This library provides a structured approach to contract storage with a two-level key system
 * 
 * Key features:
 * - Support for multiple data types (uint, bool, address, bytes, string)
 * - Two-level key storage system for flexible data organization
 * - CRUD operations for each data type with consistent interface
 * - Gas-efficient storage patterns
 * 
 * @custom:security
 * - Internal access only to prevent unauthorized storage manipulation
 * - Safe storage operations with proper type enforcement
 * - Type-specific operations to prevent type confusion
 * - Consistent interface reduces likelihood of implementation errors
 * 
 * @custom:usage
 * - Used as a foundation for complex contract storage patterns
 * - Enables modular and organized data storage in contracts
 * - Simplifies storage access with standardized methods
 * - Perfect for contracts with diverse data storage needs
 */
library BasicStorageLib {

    /**
     * @dev Structure for storing uint values
     * Provides a two-level nested mapping for uint storage
     * 
     * @custom:usage
     * - Stores uint values with two-level key system for hierarchical data
     * - Used for numeric data storage such as balances, timestamps, amounts
     * - Primary key often represents a category, while innerKey represents specific item
     * - Essential for tracking numeric values in complex systems
     */
    struct UintData {
        mapping(bytes => mapping(bytes => uint))           _storage;
    }

    /**
     * @dev Structure for storing boolean values
     * Provides a two-level nested mapping for boolean storage
     * 
     * @custom:usage
     * - Stores boolean values with two-level key system for hierarchical data
     * - Used for flag and state storage such as activation status or permissions
     * - Efficient for representing binary states (true/false)
     * - Perfect for access control and feature toggles
     */
    struct BoolData {
        mapping(bytes => mapping(bytes => bool))           _storage;
    }

    /**
     * @dev Structure for storing address values
     * Provides a two-level nested mapping for address storage
     * 
     * @custom:usage
     * - Stores address values with two-level key system for hierarchical data
     * - Used for contract and account address storage
     * - Essential for tracking ownership, relationships between entities
     * - Enables role-based systems and contract registries
     */
    struct AddressData {
        mapping(bytes => mapping(bytes => address))        _storage;
    }

    /**
     * @dev Structure for storing bytes values
     * Provides a two-level nested mapping for bytes storage
     * 
     * @custom:usage
     * - Stores bytes values with two-level key system for hierarchical data
     * - Used for raw data storage such as cryptographic proofs, signatures
     * - Perfect for storing variable-length binary data
     * - Enables storage of complex serialized structures
     */
    struct BytesData {
        mapping(bytes => mapping(bytes => bytes))          _storage;
    }

    /**
     * @dev Structure for storing string values
     * Provides a two-level nested mapping for string storage
     * 
     * @custom:usage
     * - Stores string values with two-level key system for hierarchical data
     * - Used for text data storage such as names, descriptions, metadata
     * - Human-readable information storage
     * - Suitable for configuration parameters and user-facing content
     */
    struct StringData {
        mapping(bytes => mapping(bytes => string))         _storage;
    }

    /**
     * @dev Set uint value in storage
     * Assigns a uint value to a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization (e.g., user ID, token type)
     * @param innerKey Secondary key for specific attribute (e.g., balance, timestamp)
     * @param value Unsigned integer value to store
     * 
     * @custom:effects
     * - Updates storage with new value, overwriting any existing value
     * - Gas usage scales with key sizes, not with value size
     * - Optimized for single-slot storage operations
     */
    function setStorage(UintData storage self, bytes memory key, bytes memory innerKey, uint value) internal {
        self._storage[key][innerKey] = value;
    }

    /**
     * @dev Get uint value from storage
     * Retrieves a uint value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific attribute
     * @return Stored uint value, or 0 if no value has been set
     * 
     * @custom:effects
     * - Read-only operation that doesn't modify state
     * - Returns default value (0) if entry doesn't exist
     * - Gas cost is constant regardless of value stored
     */
    function getStorage(UintData storage self, bytes memory key, bytes memory innerKey) internal view returns (uint) {
        return self._storage[key][innerKey];
    }

    /**
     * @dev Delete uint value from storage
     * Removes a uint value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific attribute
     * 
     * @custom:effects
     * - Removes value from storage, setting it to default value (0)
     * - Gas refund is provided when clearing storage to zero
     * - Frees up storage space, potentially reducing contract storage costs
     */
    function delStorage(UintData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /**
     * @dev Set boolean value in storage
     * Assigns a boolean value to a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization (e.g., feature name, user ID)
     * @param innerKey Secondary key for specific flag (e.g., active, approved)
     * @param value Boolean value to store
     * 
     * @custom:effects
     * - Updates storage with new value, overwriting any existing value
     * - Gas efficient for storing binary state information
     * - Packs values efficiently in storage
     */
    function setStorage(BoolData storage self, bytes memory key, bytes memory innerKey, bool value) internal {
        self._storage[key][innerKey] = value;
    }

    /**
     * @dev Get boolean value from storage
     * Retrieves a boolean value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific flag
     * @return Stored boolean value, or false if no value has been set
     * 
     * @custom:effects
     * - Read-only operation that doesn't modify state
     * - Returns default value (false) if entry doesn't exist
     * - Gas efficient for checking state conditions
     */
    function getStorage(BoolData storage self, bytes memory key, bytes memory innerKey) internal view returns (bool) {
        return self._storage[key][innerKey];
    }

    /**
     * @dev Delete boolean value from storage
     * Removes a boolean value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific flag
     * 
     * @custom:effects
     * - Removes value from storage, setting it to default value (false)
     * - Gas refund is provided when clearing storage to zero
     * - Particularly efficient for boolean values
     */
    function delStorage(BoolData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /**
     * @dev Set address value in storage
     * Assigns an address value to a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization (e.g., role name, contract type)
     * @param innerKey Secondary key for specific relationship (e.g., owner, delegate)
     * @param value Ethereum address to store
     * 
     * @custom:effects
     * - Updates storage with new address, overwriting any existing value
     * - Stores full 20-byte Ethereum addresses
     * - Critical for tracking contract relationships and ownership
     */
    function setStorage(AddressData storage self, bytes memory key, bytes memory innerKey, address value) internal {
        self._storage[key][innerKey] = value;
    }

    /**
     * @dev Get address value from storage
     * Retrieves an address value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific relationship
     * @return Stored address value, or address(0) if no value has been set
     * 
     * @custom:effects
     * - Read-only operation that doesn't modify state
     * - Returns default value (address(0)) if entry doesn't exist
     * - Used for permission checks and relationship verification
     */
    function getStorage(AddressData storage self, bytes memory key, bytes memory innerKey) internal view returns (address) {
        return self._storage[key][innerKey];
    }

    /**
     * @dev Delete address value from storage
     * Removes an address value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific relationship
     * 
     * @custom:effects
     * - Removes value from storage, setting it to default value (address(0))
     * - Gas refund is provided when clearing storage to zero
     * - Important for revoking permissions or updating relationships
     */
    function delStorage(AddressData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /**
     * @dev Set bytes value in storage
     * Assigns a bytes value to a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization (e.g., data type, record ID)
     * @param innerKey Secondary key for specific data (e.g., signature, hash)
     * @param value Bytes data to store
     * 
     * @custom:effects
     * - Updates storage with new bytes data, overwriting any existing value
     * - Dynamically sized data is stored with length prefix
     * - Gas cost scales with the size of the bytes array
     * - Suitable for arbitrary binary data storage
     */
    function setStorage(BytesData storage self, bytes memory key, bytes memory innerKey, bytes memory value) internal {
        self._storage[key][innerKey] = value;
    }

    /**
     * @dev Get bytes value from storage
     * Retrieves a bytes value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific data
     * @return Stored bytes value, or empty bytes if no value has been set
     * 
     * @custom:effects
     * - Read-only operation that doesn't modify state
     * - Returns default value (empty bytes) if entry doesn't exist
     * - Gas cost scales with the size of the retrieved data
     * - Used for retrieving serialized data, proofs, or signatures
     */
    function getStorage(BytesData storage self, bytes memory key, bytes memory innerKey) internal view returns (bytes memory) {
        return self._storage[key][innerKey];
    }

    /**
     * @dev Delete bytes value from storage
     * Removes a bytes value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific data
     * 
     * @custom:effects
     * - Removes value from storage, setting it to default value (empty bytes)
     * - Gas refund is provided when clearing storage
     * - More gas efficient for larger data due to storage refunds
     * - Complete removal of variable-length data
     */
    function delStorage(BytesData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /**
     * @dev Set string value in storage
     * Assigns a string value to a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization (e.g., metadata type, record ID)
     * @param innerKey Secondary key for specific text (e.g., name, description)
     * @param value String data to store
     * 
     * @custom:effects
     * - Updates storage with new string, overwriting any existing value
     * - Strings are stored as UTF-8 encoded bytes with length prefix
     * - Gas cost scales with the length of the string
     * - Ideal for human-readable text storage
     */
    function setStorage(StringData storage self, bytes memory key, bytes memory innerKey, string memory value) internal {
        self._storage[key][innerKey] = value;
    }

    /**
     * @dev Get string value from storage
     * Retrieves a string value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific text
     * @return Stored string value, or empty string if no value has been set
     * 
     * @custom:effects
     * - Read-only operation that doesn't modify state
     * - Returns default value (empty string) if entry doesn't exist
     * - Gas cost scales with the length of the retrieved string
     * - Used for retrieving human-readable configuration and metadata
     */
    function getStorage(StringData storage self, bytes memory key, bytes memory innerKey) internal view returns (string memory) {
        return self._storage[key][innerKey];
    }

    /**
     * @dev Delete string value from storage
     * Removes a string value from a specific key pair in storage
     * 
     * @param self Storage structure reference
     * @param key Primary key for categorization
     * @param innerKey Secondary key for specific text
     * 
     * @custom:effects
     * - Removes value from storage, setting it to default value (empty string)
     * - Gas refund is provided when clearing storage
     * - More gas efficient for longer strings due to storage refunds
     * - Complete removal of variable-length text data
     */
    function delStorage(StringData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

}

// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.8.18;

/**
 * Math operations with safety checks
 */

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "../interfaces/IWrappedToken.sol";
import "../components/Admin.sol";
import "./TokenManagerStorage.sol";
import "./WrappedToken.sol";

/**
 * @title TokenManagerDelegate
 * @dev Implementation contract for token management functionality
 * This contract provides:
 * - Token pair management (add, update, remove)
 * - Token minting and burning
 * - Token ownership management
 * - Token information retrieval
 */
contract TokenManagerDelegate is TokenManagerStorage, Admin {
    using SafeMath for uint;
    /************************************************************
     **
     ** EVENTS
     **
     ************************************************************/

     /// @notice Emitted when a new token is added
     /// @param tokenAddress Address of the new token
     /// @param name Name of the token
     /// @param symbol Symbol of the token
     /// @param decimals Number of decimal places
     event AddToken(address tokenAddress, string name, string symbol, uint8 decimals);
     
     /// @notice Emitted when a new token pair is added
     /// @param id ID of the token pair
     /// @param fromChainID Source chain ID
     /// @param fromAccount Source token address
     /// @param toChainID Destination chain ID
     /// @param toAccount Destination token address
     event AddTokenPair(uint indexed id, uint fromChainID, bytes fromAccount, uint toChainID, bytes toAccount);
     
     /// @notice Emitted when a token pair is updated
     /// @param id ID of the token pair
     /// @param aInfo Updated ancestor token information
     /// @param fromChainID Source chain ID
     /// @param fromAccount Source token address
     /// @param toChainID Destination chain ID
     /// @param toAccount Destination token address
     event UpdateTokenPair(uint indexed id, AncestorInfo aInfo, uint fromChainID, bytes fromAccount, uint toChainID, bytes toAccount);
     
     /// @notice Emitted when a token pair is removed
     /// @param id ID of the removed token pair
     event RemoveTokenPair(uint indexed id);
     
     /// @notice Emitted when a token's information is updated
     /// @param tokenAddress Address of the updated token
     /// @param name New name of the token
     /// @param symbol New symbol of the token
     event UpdateToken(address tokenAddress, string name, string symbol);

    /**
     *
     * MODIFIERS
     *
     */

    /**
     * @notice Modifier to ensure token pair ID does not exist
     * @dev Throws if token pair ID already exists
     */
    modifier onlyNotExistID(uint id) {
        require(mapTokenPairInfo[id].fromChainID == 0, "token exist");
        _;
    }

    /**
     * @notice Modifier to ensure token pair ID exists
     * @dev Throws if token pair ID does not exist
     */
    modifier onlyExistID(uint id) {
        require(mapTokenPairInfo[id].fromChainID > 0, "token not exist");
        _;
    }

    /**
    *
    * MANIPULATIONS
    *
    */
    
    /**
     * @notice Converts bytes to address
     * @dev Uses assembly for efficient conversion
     * @param b Bytes to convert
     * @return addr The converted address
     */
    function bytesToAddress(bytes memory b) internal pure returns (address addr) {
        assembly {
            addr := mload(add(b,20))
        }
    }

    /**
     * @notice Mints new tokens
     * @dev Can only be called by admin
     * @param tokenAddress Address of the token to mint
     * @param to Address to receive the tokens
     * @param value Amount of tokens to mint
     */
    function mintToken(
        address tokenAddress,
        address to,
        uint    value
    )
        external
        onlyAdmin
    {
        IWrappedToken(tokenAddress).mint(to, value);
    }

    /**
     * @notice Burns tokens
     * @dev Can only be called by admin
     * @param tokenAddress Address of the token to burn
     * @param from Address to burn tokens from
     * @param value Amount of tokens to burn
     */
    function burnToken(
        address tokenAddress,
        address from,
        uint    value
    )
        external
        onlyAdmin
    {
        IWrappedToken(tokenAddress).burn(from, value);
    }

    /**
     * @notice Adds a new token
     * @dev Can only be called by owner
     * @param name Name of the token
     * @param symbol Symbol of the token
     * @param decimals Number of decimal places
     * Emits:
     * - AddToken event with token details
     */
    function addToken(
        string memory name,
        string memory symbol,
        uint8 decimals
    )
        external
        onlyOwner
    {
        address tokenAddress = address(new WrappedToken(name, symbol, decimals));

        emit AddToken(tokenAddress, name, symbol, decimals);
    }

    /**
     * @notice Adds a new token pair
     * @dev Can only be called by owner
     * @param id ID of the token pair
     * @param aInfo Information about the ancestor token
     * @param fromChainID Source chain ID
     * @param fromAccount Source token address
     * @param toChainID Destination chain ID
     * @param toAccount Destination token address
     * Requirements:
     * - Token pair ID must not exist
     * - Caller must be owner
     * Emits:
     * - AddTokenPair event with pair details
     */
    function addTokenPair(
        uint    id,

        AncestorInfo calldata aInfo,

        uint           fromChainID,
        bytes calldata fromAccount,
        uint           toChainID,
        bytes calldata toAccount
    )
        public
        onlyOwner
        onlyNotExistID(id)
    {
        // create a new record
        mapTokenPairInfo[id].fromChainID = fromChainID;
        mapTokenPairInfo[id].fromAccount = fromAccount;
        mapTokenPairInfo[id].toChainID = toChainID;
        mapTokenPairInfo[id].toAccount = toAccount;

        mapTokenPairInfo[id].aInfo.account = aInfo.account;
        mapTokenPairInfo[id].aInfo.name = aInfo.name;
        mapTokenPairInfo[id].aInfo.symbol = aInfo.symbol;
        mapTokenPairInfo[id].aInfo.decimals = aInfo.decimals;
        mapTokenPairInfo[id].aInfo.chainID = aInfo.chainID;

        mapTokenPairIndex[totalTokenPairs] = id;
        totalTokenPairs = totalTokenPairs.add(1);

        // fire event
        emit AddTokenPair(id, fromChainID, fromAccount, toChainID, toAccount);
    }

    /**
     * @notice Updates an existing token pair
     * @dev Can only be called by owner
     * @param id ID of the token pair to update
     * @param aInfo Updated ancestor token information
     * @param fromChainID Updated source chain ID
     * @param fromAccount Updated source token address
     * @param toChainID Updated destination chain ID
     * @param toAccount Updated destination token address
     * Requirements:
     * - Token pair ID must exist
     * - Caller must be owner
     * Emits:
     * - UpdateTokenPair event with updated details
     */
    function updateTokenPair(
        uint    id,

        AncestorInfo calldata aInfo,

        uint           fromChainID,
        bytes calldata fromAccount,
        uint           toChainID,
        bytes calldata toAccount
    )
        public
        onlyOwner
        onlyExistID(id)
    {
        mapTokenPairInfo[id].aInfo.account = aInfo.account;
        mapTokenPairInfo[id].aInfo.name = aInfo.name;
        mapTokenPairInfo[id].aInfo.symbol = aInfo.symbol;
        mapTokenPairInfo[id].aInfo.decimals = aInfo.decimals;
        mapTokenPairInfo[id].aInfo.chainID = aInfo.chainID;

        mapTokenPairInfo[id].fromChainID = fromChainID;
        mapTokenPairInfo[id].fromAccount = fromAccount;
        mapTokenPairInfo[id].toChainID = toChainID;
        mapTokenPairInfo[id].toAccount = toAccount;

        emit UpdateTokenPair(id, aInfo, fromChainID, fromAccount, toChainID, toAccount);
    }

    /**
     * @notice Removes a token pair
     * @dev Can only be called by owner
     * @param id ID of the token pair to remove
     * Requirements:
     * - Token pair ID must exist
     * - Caller must be owner
     * Emits:
     * - RemoveTokenPair event with the removed ID
     */
    function removeTokenPair(
        uint id
    )
        external
        onlyOwner
        onlyExistID(id)
    {
        for(uint i=0; i<totalTokenPairs; i++) {
            if (id == mapTokenPairIndex[i]) {
                if (i != totalTokenPairs - 1) {
                    mapTokenPairIndex[i] = mapTokenPairIndex[totalTokenPairs - 1];
                }
 
                delete mapTokenPairIndex[totalTokenPairs - 1];
                totalTokenPairs--;
                delete mapTokenPairInfo[id];
                emit RemoveTokenPair(id);
                return;
            }
        }
    }

    /**
     * @notice Updates token information
     * @dev Can only be called by owner
     * @param tokenAddress Address of the token to update
     * @param name New name of the token
     * @param symbol New symbol of the token
     * Emits:
     * - UpdateToken event with updated details
     */
    function updateToken(address tokenAddress, string calldata name, string calldata symbol)
        external
        onlyOwner
    {
        IWrappedToken(tokenAddress).update(name, symbol);

        emit UpdateToken(tokenAddress, name, symbol);
    }

    /**
     * @notice Changes token ownership
     * @dev Can only be called by owner
     * @param tokenAddress Address of the token
     * @param _newOwner Address of the new owner
     */
    function changeTokenOwner(address tokenAddress, address _newOwner) external onlyOwner {
        IWrappedToken(tokenAddress).changeOwner(_newOwner);
    }

    /**
     * @notice Accepts token ownership
     * @dev Can be called by the new owner
     * @param tokenAddress Address of the token
     */
    function acceptTokenOwnership(address tokenAddress) external {
        IWrappedToken(tokenAddress).acceptOwnership();
    }

    /**
     * @notice Transfers token ownership
     * @dev Can only be called by owner
     * @param tokenAddress Address of the token
     * @param _newOwner Address of the new owner
     */
    function transferTokenOwner(address tokenAddress, address _newOwner) external onlyOwner {
        IWrappedToken(tokenAddress).transferOwner(_newOwner);
    }

    /**
     * @notice Gets complete token pair information
     * @param id ID of the token pair
     * @return fromChainID Source chain ID
     * @return fromAccount Source token address
     * @return toChainID Destination chain ID
     * @return toAccount Destination token address
     */
    function getTokenPairInfo(
        uint id
    )
        external
        view
        returns (uint fromChainID, bytes memory fromAccount, uint toChainID, bytes memory toAccount)
    {
        fromChainID = mapTokenPairInfo[id].fromChainID;
        fromAccount = mapTokenPairInfo[id].fromAccount;
        toChainID = mapTokenPairInfo[id].toChainID;
        toAccount = mapTokenPairInfo[id].toAccount;
    }

    /**
     * @notice Gets simplified token pair information
     * @param id ID of the token pair
     * @return fromChainID Source chain ID
     * @return fromAccount Source token address
     * @return toChainID Destination chain ID
     */
    function getTokenPairInfoSlim(
        uint id
    )
        external
        view
        returns (uint fromChainID, bytes memory fromAccount, uint toChainID)
    {
        fromChainID = mapTokenPairInfo[id].fromChainID;
        fromAccount = mapTokenPairInfo[id].fromAccount;
        toChainID = mapTokenPairInfo[id].toChainID;
    }

    /**
     * @notice Gets token information
     * @param id ID of the token pair
     * @return addr Address of the token
     * @return name Name of the token
     * @return symbol Symbol of the token
     * @return decimals Number of decimal places
     */
    function getTokenInfo(uint id) external view returns (address addr, string memory name, string memory symbol, uint8 decimals) {
        if (mapTokenPairInfo[id].fromChainID == 0) {
            name = '';
            symbol = '';
            decimals = 0;
            addr = address(0);
        } else {
            address instance = bytesToAddress(mapTokenPairInfo[id].toAccount);
            name = IWrappedToken(instance).name();
            symbol = IWrappedToken(instance).symbol();
            decimals = IWrappedToken(instance).decimals();
            addr = instance;
        }
    }

    function getAncestorInfo(uint id) external view returns (bytes memory account, string memory name, string memory symbol, uint8 decimals, uint chainId) {
        account = mapTokenPairInfo[id].aInfo.account;
        name = mapTokenPairInfo[id].aInfo.name;
        symbol = mapTokenPairInfo[id].aInfo.symbol;
        decimals = mapTokenPairInfo[id].aInfo.decimals;
        chainId = mapTokenPairInfo[id].aInfo.chainID;
    }

    function getAncestorSymbol(uint id) external view returns (string memory symbol, uint8 decimals) {
        symbol = mapTokenPairInfo[id].aInfo.symbol;
        decimals = mapTokenPairInfo[id].aInfo.decimals;
    }

    function getAncestorChainID(uint id) external view returns (uint chainID) {
        chainID = mapTokenPairInfo[id].aInfo.chainID;
    }

    function getTokenPairs()
        external
        view
        returns (uint[] memory id, uint[] memory fromChainID, bytes[] memory fromAccount, uint[] memory toChainID, bytes[] memory toAccount,
          string[] memory ancestorSymbol, uint8[] memory ancestorDecimals, bytes[] memory ancestorAccount, string[] memory ancestorName, uint[] memory ancestorChainID)
    {
        uint cnt = totalTokenPairs;
        uint theId = 0;
        uint i = 0;

        id = new uint[](cnt);
        fromChainID = new uint[](cnt);
        fromAccount = new bytes[](cnt);
        toChainID = new uint[](cnt);
        toAccount = new bytes[](cnt);

        ancestorSymbol = new string[](cnt);
        ancestorDecimals = new uint8[](cnt);

        ancestorAccount = new bytes[](cnt);
        ancestorName = new string[](cnt);
        ancestorChainID = new uint[](cnt);

        i = 0;
        theId = 0;
        uint j = 0;
        for (; j < totalTokenPairs; j++) {
            theId = mapTokenPairIndex[j];
            id[i] = theId;
            fromChainID[i] = mapTokenPairInfo[theId].fromChainID;
            fromAccount[i] = mapTokenPairInfo[theId].fromAccount;
            toChainID[i] = mapTokenPairInfo[theId].toChainID;
            toAccount[i] = mapTokenPairInfo[theId].toAccount;

            ancestorSymbol[i] = mapTokenPairInfo[theId].aInfo.symbol;
            ancestorDecimals[i] = mapTokenPairInfo[theId].aInfo.decimals;

            ancestorAccount[i] = mapTokenPairInfo[theId].aInfo.account;
            ancestorName[i] = mapTokenPairInfo[theId].aInfo.name;
            ancestorChainID[i] = mapTokenPairInfo[theId].aInfo.chainID;
            i ++;
        }
    }

    function getTokenPairsByChainID(uint chainID1, uint chainID2)
        external
        view
        returns (uint[] memory id, uint[] memory fromChainID, bytes[] memory fromAccount, uint[] memory toChainID, bytes[] memory toAccount,
          string[] memory ancestorSymbol, uint8[] memory ancestorDecimals, bytes[] memory ancestorAccount, string[] memory ancestorName, uint[] memory ancestorChainID)
    {
        uint cnt = 0;
        uint i = 0;
        uint theId = 0;
        uint[] memory id_valid = new uint[](totalTokenPairs);
        for (; i < totalTokenPairs; i++ ) {
            theId = mapTokenPairIndex[i];
            if ((mapTokenPairInfo[theId].fromChainID == chainID1) && (mapTokenPairInfo[theId].toChainID == chainID2) ||
            (mapTokenPairInfo[theId].toChainID == chainID1) && (mapTokenPairInfo[theId].fromChainID == chainID2)) {
                id_valid[cnt] = theId;
                cnt ++;
            }
        }

        id = new uint[](cnt);
        fromChainID = new uint[](cnt);
        fromAccount = new bytes[](cnt);
        toChainID = new uint[](cnt);
        toAccount = new bytes[](cnt);

        ancestorSymbol = new string[](cnt);
        ancestorDecimals = new uint8[](cnt);

        ancestorAccount = new bytes[](cnt);
        ancestorName = new string[](cnt);
        ancestorChainID = new uint[](cnt);

        for (i = 0; i < cnt; i++) {
            theId = id_valid[i];

            id[i] = theId;
            fromChainID[i] = mapTokenPairInfo[theId].fromChainID;
            fromAccount[i] = mapTokenPairInfo[theId].fromAccount;
            toChainID[i] = mapTokenPairInfo[theId].toChainID;
            toAccount[i] = mapTokenPairInfo[theId].toAccount;

            ancestorSymbol[i] = mapTokenPairInfo[theId].aInfo.symbol;
            ancestorDecimals[i] = mapTokenPairInfo[theId].aInfo.decimals;
            
            ancestorAccount[i] = mapTokenPairInfo[theId].aInfo.account;
            ancestorName[i] = mapTokenPairInfo[theId].aInfo.name;
            ancestorChainID[i] = mapTokenPairInfo[theId].aInfo.chainID;
        }
    }
}

File 18 of 19 : TokenManagerStorage.sol
// SPDX-License-Identifier: MIT

/*

  Copyright 2023 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.8.18;

import "../components/BasicStorage.sol";

/**
 * @title TokenManagerStorage
 * @dev Storage contract for token management functionality
 * This contract provides:
 * - Token pair information storage
 * - Ancestor token information storage
 * - Token pair mapping and indexing
 */
contract TokenManagerStorage is BasicStorage {
    /************************************************************
     **
     ** STRUCTURE DEFINATIONS
     **
     ************************************************************/

    /**
     * @notice Structure for storing ancestor token information
     * @dev Contains basic information about the original token
     * @param account Address of the token contract
     * @param name Name of the token
     * @param symbol Symbol of the token
     * @param decimals Number of decimal places
     * @param chainID ID of the blockchain where the token originates
     */
    struct AncestorInfo {
      bytes   account;
      string  name;
      string  symbol;
      uint8   decimals;
      uint    chainID;
    }

    /**
     * @notice Structure for storing token pair information
     * @dev Contains information about token pairs for cross-chain operations
     * @param aInfo Information about the ancestor token
     * @param fromChainID ID of the source blockchain (e.g., eth=60, etc=61, wan=5718350)
     * @param fromAccount Address of the token on the source chain
     * @param toChainID ID of the destination blockchain
     * @param toAccount Address of the token on the destination chain
     */
    struct TokenPairInfo {
      AncestorInfo aInfo;
      uint      fromChainID;
      bytes     fromAccount;
      uint      toChainID;
      bytes     toAccount;
    }
    
    /**
     * @notice Structure for storing complete token pair information
     * @dev Extends TokenPairInfo with a unique identifier
     * @param id Unique identifier for the token pair
     * @param aInfo Information about the ancestor token
     * @param fromChainID ID of the source blockchain
     * @param fromAccount Address of the token on the source chain
     * @param toChainID ID of the destination blockchain
     * @param toAccount Address of the token on the destination chain
     */
    struct TokenPairInfoFull {
      uint      id;
      AncestorInfo aInfo;
      uint      fromChainID;
      bytes     fromAccount;
      uint      toChainID;
      bytes     toAccount;
    }


    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    /// @notice Total number of token pairs registered in the system
    uint public totalTokenPairs = 0;

    /// @notice Mapping from token pair ID to token pair information
    mapping(uint => TokenPairInfo) public mapTokenPairInfo;
    
    /// @notice Mapping from index to token pair ID for enumeration
    mapping(uint => uint) public mapTokenPairIndex;
}

// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

/**
 * @title WrappedToken
 * @dev Implementation of a wrapped ERC20 token with burnable functionality
 * This contract provides:
 * - Custom decimal places
 * - Custom name and symbol
 * - Minting and burning capabilities
 * - Ownership management
 * - Token transfer restrictions
 */
contract WrappedToken is ERC20Burnable, Ownable {
    /// @notice Number of decimal places for token amounts
    uint8 private _decimal;
    
    /// @notice Name of the token
    string private _name;
    
    /// @notice Symbol of the token
    string private _symbol;

    /**
     * @notice Initializes the token with name, symbol and decimal places
     * @dev Sets the values for {name}, {symbol} and {decimals}
     * @param name_ Name of the token
     * @param symbol_ Symbol of the token
     * @param decimal_ Number of decimal places
     * Requirements:
     * - All parameters must be provided
     */
    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimal_
    ) ERC20(name_, symbol_) {
        _name = name_;
        _symbol = symbol_;
        _decimal = decimal_;
    }

    /**
     * @notice Returns the number of decimal places for token amounts
     * @return Number of decimal places
     */
    function decimals() public view virtual override returns (uint8) {
        return _decimal;
    }

    /**
     * @notice Returns the name of the token
     * @return Name of the token
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @notice Returns the symbol of the token
     * @return Symbol of the token
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * ============================================================================
     * code for mapping token
     * ============================================================================
     */

    /****************************************************************************
     **
     ** MODIFIERS
     **
     ****************************************************************************/
    /**
     * @notice Modifier to ensure value is greater than zero
     * @dev Throws if value is zero
     * @param value Value to check
     */
    modifier onlyMeaningfulValue(uint256 value) {
        require(value > 0, "Value is null");
        _;
    }

    /****************************************************************************
     **
     ** MANIPULATIONS of mapping token
     **
     ****************************************************************************/

    /**
     * @notice Mints new tokens
     * @dev Can only be called by owner
     * @param account_ Address to receive the minted tokens
     * @param value_ Amount of tokens to mint
     * Requirements:
     * - Caller must be owner
     * - Value must be greater than zero
     */
    function mint(address account_, uint256 value_)
        external
        onlyOwner
        onlyMeaningfulValue(value_)
    {
        _mint(account_, value_);
    }

    /**
     * @notice Burns tokens from an account
     * @dev Can only be called by owner
     * @param account_ Address to burn tokens from
     * @param value_ Amount of tokens to burn
     * Requirements:
     * - Caller must be owner
     * - Value must be greater than zero
     */
    function burn(address account_, uint256 value_)
        external
        onlyOwner
        onlyMeaningfulValue(value_)
    {
        _burn(account_, value_);
    }

    /**
     * @notice Updates token name and symbol
     * @dev Can only be called by owner
     * @param name_ New name of the token
     * @param symbol_ New symbol of the token
     * Requirements:
     * - Caller must be owner
     */
    function update(string memory name_, string memory symbol_)
        external
        onlyOwner
    {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @notice Transfers ownership of the token
     * @dev Can only be called by current owner
     * @param newOwner_ Address of the new owner
     * Requirements:
     * - Caller must be current owner
     */
    function transferOwner(address newOwner_) public onlyOwner {
        Ownable.transferOwnership(newOwner_);
    }

    /**
     * @notice Hook that is called before any token transfer
     * @dev Prevents transfers to the token contract itself
     * @param to Address receiving the tokens
     * Requirements:
     * - Recipient cannot be the token contract
     */
    function _beforeTokenTransfer(address /*from*/, address to, uint256 /*amount*/) internal override view { 
        require(to != address(this), "to address incorrect");
    }
}

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

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"AddAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"AddToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromChainID","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"fromAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"toChainID","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"}],"name":"AddTokenPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"RemoveAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"RemoveTokenPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOperator","type":"address"},{"indexed":true,"internalType":"address","name":"newOperator","type":"address"}],"name":"SetOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenPairId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenPairType","type":"uint256"}],"name":"SetTokenPairType","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"}],"name":"UpdateToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"bytes","name":"account","type":"bytes"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"chainID","type":"uint256"}],"indexed":false,"internalType":"struct TokenManagerStorage.AncestorInfo","name":"aInfo","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"fromChainID","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"fromAccount","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"toChainID","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"toAccount","type":"bytes"}],"name":"UpdateTokenPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"acceptTokenOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"addToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"bytes","name":"account","type":"bytes"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"chainID","type":"uint256"}],"internalType":"struct TokenManagerStorage.AncestorInfo","name":"aInfo","type":"tuple"},{"internalType":"uint256","name":"fromChainID","type":"uint256"},{"internalType":"bytes","name":"fromAccount","type":"bytes"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"bytes","name":"toAccount","type":"bytes"}],"name":"addTokenPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenCrossType","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"tokenIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"burnNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"changeTokenOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAncestorChainID","outputs":[{"internalType":"uint256","name":"chainID","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAncestorInfo","outputs":[{"internalType":"bytes","name":"account","type":"bytes"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getAncestorSymbol","outputs":[{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getTokenInfo","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getTokenPairInfo","outputs":[{"internalType":"uint256","name":"fromChainID","type":"uint256"},{"internalType":"bytes","name":"fromAccount","type":"bytes"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"bytes","name":"toAccount","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getTokenPairInfoSlim","outputs":[{"internalType":"uint256","name":"fromChainID","type":"uint256"},{"internalType":"bytes","name":"fromAccount","type":"bytes"},{"internalType":"uint256","name":"toChainID","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokenPairs","outputs":[{"internalType":"uint256[]","name":"id","type":"uint256[]"},{"internalType":"uint256[]","name":"fromChainID","type":"uint256[]"},{"internalType":"bytes[]","name":"fromAccount","type":"bytes[]"},{"internalType":"uint256[]","name":"toChainID","type":"uint256[]"},{"internalType":"bytes[]","name":"toAccount","type":"bytes[]"},{"internalType":"string[]","name":"ancestorSymbol","type":"string[]"},{"internalType":"uint8[]","name":"ancestorDecimals","type":"uint8[]"},{"internalType":"bytes[]","name":"ancestorAccount","type":"bytes[]"},{"internalType":"string[]","name":"ancestorName","type":"string[]"},{"internalType":"uint256[]","name":"ancestorChainID","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainID1","type":"uint256"},{"internalType":"uint256","name":"chainID2","type":"uint256"}],"name":"getTokenPairsByChainID","outputs":[{"internalType":"uint256[]","name":"id","type":"uint256[]"},{"internalType":"uint256[]","name":"fromChainID","type":"uint256[]"},{"internalType":"bytes[]","name":"fromAccount","type":"bytes[]"},{"internalType":"uint256[]","name":"toChainID","type":"uint256[]"},{"internalType":"bytes[]","name":"toAccount","type":"bytes[]"},{"internalType":"string[]","name":"ancestorSymbol","type":"string[]"},{"internalType":"uint8[]","name":"ancestorDecimals","type":"uint8[]"},{"internalType":"bytes[]","name":"ancestorAccount","type":"bytes[]"},{"internalType":"string[]","name":"ancestorName","type":"string[]"},{"internalType":"uint256[]","name":"ancestorChainID","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mapAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapTokenPairIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapTokenPairInfo","outputs":[{"components":[{"internalType":"bytes","name":"account","type":"bytes"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"chainID","type":"uint256"}],"internalType":"struct TokenManagerStorage.AncestorInfo","name":"aInfo","type":"tuple"},{"internalType":"uint256","name":"fromChainID","type":"uint256"},{"internalType":"bytes","name":"fromAccount","type":"bytes"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"bytes","name":"toAccount","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapTokenPairType","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenCrossType","type":"uint256"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIDs","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"mintToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"newOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"removeTokenPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenPairIds","type":"uint256[]"},{"internalType":"uint8[]","name":"tokenPairTypes","type":"uint8[]"}],"name":"setTokenPairTypes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalTokenPairs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferTokenOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"name":"updateToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"bytes","name":"account","type":"bytes"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"chainID","type":"uint256"}],"internalType":"struct TokenManagerStorage.AncestorInfo","name":"aInfo","type":"tuple"},{"internalType":"uint256","name":"fromChainID","type":"uint256"},{"internalType":"bytes","name":"fromAccount","type":"bytes"},{"internalType":"uint256","name":"toChainID","type":"uint256"},{"internalType":"bytes","name":"toAccount","type":"bytes"}],"name":"updateTokenPair","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052600060055534801561001557600080fd5b50600880546001600160a01b03191633179055615bd2806100376000396000f3fe608060405260043610620002535760003560e01c8063715018a6116200013f578063b3ab15fb11620000bb578063d51dddd71162000079578063d51dddd714620007ac578063e101d3c114620007f1578063e24e4fdb1462000826578063f3bdd863146200083e578063f4debe1e14620008635762000265565b8063b3ab15fb14620006f1578063b90732761462000716578063cbfbd61a146200074d578063d0ad718d1462000772578063d4ee1d90146200078a5762000265565b80638da5cb5b11620001095780638da5cb5b14620006285780639027e6f7146200064a5780639947f9321462000682578063a6f9dae114620006a7578063af33f17e14620006cc5762000265565b8063715018a6146200057a57806375d2e27d146200059257806379ba509714620005d95780638c7a63ae14620005f15762000265565b80634fb2e45d11620001cf5780635c60da1b11620001995780635c60da1b14620004b35780635d2e9ead14620004d35780636bec32da146200050b5780636c45e2dc14620005305780637048027514620005555762000265565b80634fb2e45d14620003d6578063563cb1ab14620003fb578063570ca735146200043857806358a007fb14620004735762000265565b80633ad8873a116200021d5780633ad8873a14620003035780633cc281df1462000342578063408e743d146200036757806341246e53146200038c5780634f600ae814620003b15762000265565b80631785f53c146200026f5780632859c58014620002945780632b56590514620002b95780633416794d14620002de5762000265565b3662000265576200026362000897565b005b6200026362000897565b3480156200027c57600080fd5b50620002636200028e366004620036fb565b62000923565b348015620002a157600080fd5b5062000263620002b336600462003767565b620009a8565b348015620002c657600080fd5b5062000263620002d83660046200380c565b62000ad3565b348015620002eb57600080fd5b5062000263620002fd36600462003826565b62000cd8565b3480156200031057600080fd5b5062000328620003223660046200380c565b62000d6b565b6040516200033993929190620038bb565b60405180910390f35b3480156200034f57600080fd5b506200026362000361366004620036fb565b62000e35565b3480156200037457600080fd5b506200026362000386366004620038e6565b62000e86565b3480156200039957600080fd5b5062000263620003ab366004620038e6565b62000f15565b348015620003be57600080fd5b5062000263620003d036600462003962565b62000f71565b348015620003e357600080fd5b5062000263620003f5366004620036fb565b6200117e565b3480156200040857600080fd5b50620004206200041a36600462003a23565b6200125f565b604051620003399a9998979695949392919062003b0e565b3480156200044557600080fd5b50600c546200045a906001600160a01b031681565b6040516001600160a01b03909116815260200162000339565b3480156200048057600080fd5b50620004a4620004923660046200380c565b60076020526000908152604090205481565b60405190815260200162000339565b348015620004c057600080fd5b50600b546001600160a01b03166200045a565b348015620004e057600080fd5b50620004f8620004f23660046200380c565b62001bec565b6040516200033995949392919062003bfd565b3480156200051857600080fd5b50620002636200052a36600462003826565b62001f34565b3480156200053d57600080fd5b50620002636200054f36600462003962565b62001f9c565b3480156200056257600080fd5b506200026362000574366004620036fb565b62002162565b3480156200058757600080fd5b5062000263620021e4565b3480156200059f57600080fd5b50620005c6620005b13660046200380c565b600d6020526000908152604090205460ff1681565b60405160ff909116815260200162000339565b348015620005e657600080fd5b506200026362002223565b348015620005fe57600080fd5b5062000616620006103660046200380c565b6200225b565b60405162000339949392919062003cb9565b3480156200063557600080fd5b506008546200045a906001600160a01b031681565b3480156200065757600080fd5b506200066f620006693660046200380c565b6200249d565b6040516200033995949392919062003d08565b3480156200068f57600080fd5b5062000263620006a136600462003d5f565b620026c1565b348015620006b457600080fd5b5062000263620006c6366004620036fb565b620027ba565b348015620006d957600080fd5b5062000263620006eb36600462003e33565b62002809565b348015620006fe57600080fd5b506200026362000710366004620036fb565b620028e6565b3480156200072357600080fd5b506200073b620007353660046200380c565b6200296f565b60405162000339949392919062003ebc565b3480156200075a57600080fd5b50620002636200076c36600462003efc565b62002ada565b3480156200077f57600080fd5b50620004a460055481565b3480156200079757600080fd5b506009546200045a906001600160a01b031681565b348015620007b957600080fd5b50620007e0620007cb366004620036fb565b600a6020526000908152604090205460ff1681565b604051901515815260200162000339565b348015620007fe57600080fd5b5062000816620008103660046200380c565b62002c70565b6040516200033992919062003f6e565b3480156200083357600080fd5b506200042062002d37565b3480156200084b57600080fd5b50620002636200085d36600462004074565b620035a9565b3480156200087057600080fd5b50620004a4620008823660046200380c565b60009081526006602052604090206004015490565b600b546001600160a01b031680620008f65760405162461bcd60e51b815260206004820152601f60248201527f696d706c656d656e746174696f6e20636f6e7472616374206e6f74207365740060448201526064015b60405180910390fd5b60405136600082376000803683855af43d806000843e81801562000918578184f35b8184fd5b5050505050565b6008546001600160a01b03163314620009505760405162461bcd60e51b8152600401620008ed90620040f4565b6001600160a01b0381166000818152600a6020908152604091829020805460ff1916905590519182527f753f40ca3312b2408759a67875b367955e7baa221daf08aa3d643d96202ac12b91015b60405180910390a150565b336000908152600a602052604090205460ff16620009da5760405162461bcd60e51b8152600401620008ed9062004117565b6001870362000a4f5760405163b2dc5dc360e01b81526001600160a01b0387169063b2dc5dc39062000a15908890889088906004016200416d565b600060405180830381600087803b15801562000a3057600080fd5b505af115801562000a45573d6000803e3d6000fd5b5050505062000aca565b6002870362000a8e57604051631ac8311560e21b81526001600160a01b03871690636b20c4549062000a1590889088908890889088906004016200419d565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c6964204e4654207479706560801b6044820152606401620008ed565b50505050505050565b6008546001600160a01b0316331462000b005760405162461bcd60e51b8152600401620008ed90620040f4565b600081815260066020526040902060050154819062000b545760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401620008ed565b60005b60055481101562000cd357600081815260076020526040902054830362000cbe57600160055462000b899190620041ef565b811462000bc65760076000600160055462000ba59190620041ef565b81526020808201929092526040908101600090812054848252600790935220555b60076000600160055462000bdb9190620041ef565b8152602001908152602001600020600090556005600081548092919062000c029062004205565b9091555050600083815260066020526040812090818162000c24828262003673565b62000c3460018301600062003673565b62000c4460028301600062003673565b5060038101805460ff19169055600060049091018190556005830181905562000c7290600684019062003673565b600782016000905560088201600062000c8c919062003673565b505060405183907fa219112a711e6173c2e8978836823d4e86832d96c0ea2fd05ec77687b7a073ab90600090a2505050565b8062000cca816200421f565b91505062000b57565b505050565b336000908152600a602052604090205460ff1662000d0a5760405162461bcd60e51b8152600401620008ed9062004117565b604051632770a7eb60e21b81526001600160a01b03838116600483015260248201839052841690639dc29fac906044015b600060405180830381600087803b15801562000d5657600080fd5b505af115801562000aca573d6000803e3d6000fd5b60008181526006602081905260408220600581015491018054919260609290919062000d97906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462000dc5906200423b565b801562000e165780601f1062000dea5761010080835404028352916020019162000e16565b820191906000526020600020905b81548152906001019060200180831162000df857829003601f168201915b5050506000968752505060066020526040909420600701549294915050565b806001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562000e7157600080fd5b505af11580156200091c573d6000803e3d6000fd5b6008546001600160a01b0316331462000eb35760405162461bcd60e51b8152600401620008ed90620040f4565b604051634fb2e45d60e01b81526001600160a01b038281166004830152831690634fb2e45d906024015b600060405180830381600087803b15801562000ef857600080fd5b505af115801562000f0d573d6000803e3d6000fd5b505050505050565b6008546001600160a01b0316331462000f425760405162461bcd60e51b8152600401620008ed90620040f4565b60405163a6f9dae160e01b81526001600160a01b03828116600483015283169063a6f9dae19060240162000edd565b6008546001600160a01b0316331462000f9e5760405162461bcd60e51b8152600401620008ed90620040f4565b60008881526006602052604090206005015488901562000fef5760405162461bcd60e51b815260206004820152600b60248201526a1d1bdad95b88195e1a5cdd60aa1b6044820152606401620008ed565b6000898152600660208190526040909120600581018990550162001015868883620042c1565b506000898152600660205260409020600781018590556008016200103b838583620042c1565b506200104888806200438d565b60008b81526006602052604090209162001064919083620042c1565b506200107460208901896200438d565b60008b81526006602052604090206001019162001093919083620042c1565b50620010a360408901896200438d565b60008b815260066020526040902060020191620010c2919083620042c1565b50620010d56080890160608a01620043d6565b60008a815260066020908152604080832060038101805460ff191660ff969096169590951790945560808c013560049094019390935560058054835260079091529190208a9055546200112a9060016200365c565b60055560405189907f226f08da880957e11c8affd4d622bb21b058cf67830d2ee56bb82d9b7197e9a7906200116b908a908a908a908a908a908a9062004426565b60405180910390a2505050505050505050565b6008546001600160a01b03163314620011ab5760405162461bcd60e51b8152600401620008ed90620040f4565b6001600160a01b038116620012035760405162461bcd60e51b815260206004820152601d60248201527f4e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401620008ed565b6008546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600880546001600160a01b0319166001600160a01b0392909216919091179055565b6060806060806060806060806060806000806000806005546001600160401b0381111562001291576200129162003f95565b604051908082528060200260200182016040528015620012bb578160200160208202803683370190505b5090505b6005548310156200139f57600760008481526020019081526020016000205491508f60066000848152602001908152602001600020600501541480156200131657506000828152600660205260409020600701548f145b806200135357508f60066000848152602001908152602001600020600701541480156200135357506000828152600660205260409020600501548f145b156200138a57818185815181106200136f576200136f6200446a565b60209081029190910101528362001386816200421f565b9450505b8262001396816200421f565b935050620012bf565b836001600160401b03811115620013ba57620013ba62003f95565b604051908082528060200260200182016040528015620013e4578160200160208202803683370190505b509d50836001600160401b0381111562001402576200140262003f95565b6040519080825280602002602001820160405280156200142c578160200160208202803683370190505b509c50836001600160401b038111156200144a576200144a62003f95565b6040519080825280602002602001820160405280156200147f57816020015b6060815260200190600190039081620014695790505b509b50836001600160401b038111156200149d576200149d62003f95565b604051908082528060200260200182016040528015620014c7578160200160208202803683370190505b509a50836001600160401b03811115620014e557620014e562003f95565b6040519080825280602002602001820160405280156200151a57816020015b6060815260200190600190039081620015045790505b509950836001600160401b0381111562001538576200153862003f95565b6040519080825280602002602001820160405280156200156d57816020015b6060815260200190600190039081620015575790505b509850836001600160401b038111156200158b576200158b62003f95565b604051908082528060200260200182016040528015620015b5578160200160208202803683370190505b509750836001600160401b03811115620015d357620015d362003f95565b6040519080825280602002602001820160405280156200160857816020015b6060815260200190600190039081620015f25790505b509650836001600160401b0381111562001626576200162662003f95565b6040519080825280602002602001820160405280156200165b57816020015b6060815260200190600190039081620016455790505b509550836001600160401b0381111562001679576200167962003f95565b604051908082528060200260200182016040528015620016a3578160200160208202803683370190505b509450600092505b8383101562001bd957808381518110620016c957620016c96200446a565b60200260200101519150818e8481518110620016e957620016e96200446a565b60200260200101818152505060066000838152602001908152602001600020600501548d84815181106200172157620017216200446a565b60200260200101818152505060066000838152602001908152602001600020600601805462001750906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200177e906200423b565b8015620017cf5780601f10620017a357610100808354040283529160200191620017cf565b820191906000526020600020905b815481529060010190602001808311620017b157829003601f168201915b50505050508c8481518110620017e957620017e96200446a565b602002602001018190525060066000838152602001908152602001600020600701548b84815181106200182057620018206200446a565b6020026020010181815250506006600083815260200190815260200160002060080180546200184f906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200187d906200423b565b8015620018ce5780601f10620018a257610100808354040283529160200191620018ce565b820191906000526020600020905b815481529060010190602001808311620018b057829003601f168201915b50505050508a8481518110620018e857620018e86200446a565b602002602001018190525060066000838152602001908152602001600020600001600201805462001919906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001947906200423b565b8015620019985780601f106200196c5761010080835404028352916020019162001998565b820191906000526020600020905b8154815290600101906020018083116200197a57829003601f168201915b5050505050898481518110620019b257620019b26200446a565b602090810291909101810191909152600083815260069091526040902060030154885160ff90911690899085908110620019f057620019f06200446a565b60ff9092166020928302919091018201526000838152600690915260409020805462001a1c906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001a4a906200423b565b801562001a9b5780601f1062001a6f5761010080835404028352916020019162001a9b565b820191906000526020600020905b81548152906001019060200180831162001a7d57829003601f168201915b505050505087848151811062001ab55762001ab56200446a565b602002602001018190525060066000838152602001908152602001600020600001600101805462001ae6906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001b14906200423b565b801562001b655780601f1062001b395761010080835404028352916020019162001b65565b820191906000526020600020905b81548152906001019060200180831162001b4757829003601f168201915b505050505086848151811062001b7f5762001b7f6200446a565b6020026020010181905250600660008381526020019081526020016000206000016004015485848151811062001bb95762001bb96200446a565b60209081029190910101528262001bd0816200421f565b935050620016ab565b505050509295989b9194979a5092959850565b6006602052806000526040600020600091509050806000016040518060a001604052908160008201805462001c21906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001c4f906200423b565b801562001ca05780601f1062001c745761010080835404028352916020019162001ca0565b820191906000526020600020905b81548152906001019060200180831162001c8257829003601f168201915b5050505050815260200160018201805462001cbb906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001ce9906200423b565b801562001d3a5780601f1062001d0e5761010080835404028352916020019162001d3a565b820191906000526020600020905b81548152906001019060200180831162001d1c57829003601f168201915b5050505050815260200160028201805462001d55906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001d83906200423b565b801562001dd45780601f1062001da85761010080835404028352916020019162001dd4565b820191906000526020600020905b81548152906001019060200180831162001db657829003601f168201915b5050509183525050600382015460ff16602082015260049091015460409091015260058201546006830180549293919262001e0f906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001e3d906200423b565b801562001e8e5780601f1062001e625761010080835404028352916020019162001e8e565b820191906000526020600020905b81548152906001019060200180831162001e7057829003601f168201915b50505050509080600701549080600801805462001eab906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001ed9906200423b565b801562001f2a5780601f1062001efe5761010080835404028352916020019162001f2a565b820191906000526020600020905b81548152906001019060200180831162001f0c57829003601f168201915b5050505050905085565b336000908152600a602052604090205460ff1662001f665760405162461bcd60e51b8152600401620008ed9062004117565b6040516340c10f1960e01b81526001600160a01b038381166004830152602482018390528416906340c10f199060440162000d3b565b6008546001600160a01b0316331462001fc95760405162461bcd60e51b8152600401620008ed90620040f4565b60008881526006602052604090206005015488906200201d5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401620008ed565b6200202988806200438d565b60008b81526006602052604090209162002045919083620042c1565b506200205560208901896200438d565b60008b81526006602052604090206001019162002074919083620042c1565b506200208460408901896200438d565b60008b815260066020526040902060020191620020a3919083620042c1565b50620020b66080890160608a01620043d6565b60008a815260066020819052604090912060038101805460ff191660ff949094169390931790925560808a013560048301556005820189905501620020fd868883620042c1565b5060008981526006602052604090206007810185905560080162002123838583620042c1565b50887f4eb0f9fb05e08613a2eba9dc272a43421cf32f9ccab592725ab663e3238f5f55898989898989896040516200116b9796959493929190620044c8565b6008546001600160a01b031633146200218f5760405162461bcd60e51b8152600401620008ed90620040f4565b6001600160a01b0381166000818152600a6020908152604091829020805460ff1916600117905590519182527fad6de4452a631e641cb59902236607946ce9272b9b981f2f80e8d129cb9084ba91016200099d565b6008546001600160a01b03163314620022115760405162461bcd60e51b8152600401620008ed90620040f4565b600880546001600160a01b0319169055565b6009546001600160a01b031633036200225957600954600880546001600160a01b0319166001600160a01b039092169190911790555b565b600081815260066020526040812060050154606090819083908103620022a457505060408051602080820183526000808352835191820190935282815291935091508262002496565b60008581526006602052604081206008018054620023539190620022c8906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620022f6906200423b565b8015620023475780601f106200231b5761010080835404028352916020019162002347565b820191906000526020600020905b8154815290600101906020018083116200232957829003601f168201915b50505050506014015190565b9050806001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562002394573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620023be9190810190620045b9565b9350806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620023ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620024299190810190620045b9565b9250806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200246a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200249091906200462f565b90945090505b9193509193565b6000818152600660205260408120805460609283928392829190620024c2906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620024f0906200423b565b8015620025415780601f10620025155761010080835404028352916020019162002541565b820191906000526020600020905b8154815290600101906020018083116200252357829003601f168201915b505050600089815260066020526040902060010180549398509262002569925090506200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462002597906200423b565b8015620025e85780601f10620025bc57610100808354040283529160200191620025e8565b820191906000526020600020905b815481529060010190602001808311620025ca57829003601f168201915b505050600089815260066020526040902060020180549397509262002610925090506200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200263e906200423b565b80156200268f5780601f1062002663576101008083540402835291602001916200268f565b820191906000526020600020905b8154815290600101906020018083116200267157829003601f168201915b50505060009889525050600660205260409096206003810154600490910154959794969560ff90911694909350915050565b336000908152600a602052604090205460ff16620026f35760405162461bcd60e51b8152600401620008ed9062004117565b600189036200276c57604051631143124160e11b81526001600160a01b0389169063228624829062002732908a908a908a90889088906004016200464f565b600060405180830381600087803b1580156200274d57600080fd5b505af115801562002762573d6000803e3d6000fd5b50505050620027af565b6002890362000a8e57604051630fbfeffd60e11b81526001600160a01b03891690631f7fdffa9062002732908a908a908a908a908a908a908a906004016200468b565b505050505050505050565b6008546001600160a01b03163314620027e75760405162461bcd60e51b8152600401620008ed90620040f4565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b03163314620028365760405162461bcd60e51b8152600401620008ed90620040f4565b60405163f4c84d1960e01b81526001600160a01b0386169063f4c84d19906200286a908790879087908790600401620046de565b600060405180830381600087803b1580156200288557600080fd5b505af11580156200289a573d6000803e3d6000fd5b505050507f86ead451719b8f4b763de2648808971e9bf540eed93efadafb044cd7ef5d91f48585858585604051620028d795949392919062004709565b60405180910390a15050505050565b6008546001600160a01b03163314620029135760405162461bcd60e51b8152600401620008ed90620040f4565b600c546040516001600160a01b038084169216907f2709918445f306d3e94d280907c62c5d2525ac3192d2e544774c7f181d65af3e90600090a3600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600081815260066020819052604082206005810154910180549192606092909183916200299c906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620029ca906200423b565b801562002a1b5780601f10620029ef5761010080835404028352916020019162002a1b565b820191906000526020600020905b815481529060010190602001808311620029fd57829003601f168201915b50505060008881526006602052604090206007810154600890910180549497509095509262002a4d925090506200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462002a7b906200423b565b801562002acc5780601f1062002aa05761010080835404028352916020019162002acc565b820191906000526020600020905b81548152906001019060200180831162002aae57829003601f168201915b505050505090509193509193565b600c546001600160a01b0316331462002b255760405162461bcd60e51b815260206004820152600c60248201526b3737ba1037b832b930ba37b960a11b6044820152606401620008ed565b82811462002b685760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401620008ed565b60005b838110156200091c5782828281811062002b895762002b896200446a565b905060200201602081019062002ba09190620043d6565b600d600087878581811062002bb95762002bb96200446a565b90506020020135815260200190815260200160002060006101000a81548160ff021916908360ff16021790555082828281811062002bfb5762002bfb6200446a565b905060200201602081019062002c129190620043d6565b60ff1685858381811062002c2a5762002c2a6200446a565b905060200201357f20f86c53e8884644ce473603799d40ecf47d8c4c1d55384fe8d0eeaf697786eb60405160405180910390a362002c68816200421f565b905062002b6b565b60008181526006602052604081206002018054606092919062002c93906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462002cc1906200423b565b801562002d125780601f1062002ce65761010080835404028352916020019162002d12565b820191906000526020600020905b81548152906001019060200180831162002cf457829003601f168201915b505050600095865250506006602052604090932060030154929360ff90931692915050565b60608060608060608060608060608060006005549050600080826001600160401b0381111562002d6b5762002d6b62003f95565b60405190808252806020026020018201604052801562002d95578160200160208202803683370190505b509c50826001600160401b0381111562002db35762002db362003f95565b60405190808252806020026020018201604052801562002ddd578160200160208202803683370190505b509b50826001600160401b0381111562002dfb5762002dfb62003f95565b60405190808252806020026020018201604052801562002e3057816020015b606081526020019060019003908162002e1a5790505b509a50826001600160401b0381111562002e4e5762002e4e62003f95565b60405190808252806020026020018201604052801562002e78578160200160208202803683370190505b509950826001600160401b0381111562002e965762002e9662003f95565b60405190808252806020026020018201604052801562002ecb57816020015b606081526020019060019003908162002eb55790505b509850826001600160401b0381111562002ee95762002ee962003f95565b60405190808252806020026020018201604052801562002f1e57816020015b606081526020019060019003908162002f085790505b509750826001600160401b0381111562002f3c5762002f3c62003f95565b60405190808252806020026020018201604052801562002f66578160200160208202803683370190505b509650826001600160401b0381111562002f845762002f8462003f95565b60405190808252806020026020018201604052801562002fb957816020015b606081526020019060019003908162002fa35790505b509550826001600160401b0381111562002fd75762002fd762003f95565b6040519080825280602002602001820160405280156200300c57816020015b606081526020019060019003908162002ff65790505b509450826001600160401b038111156200302a576200302a62003f95565b60405190808252806020026020018201604052801562003054578160200160208202803683370190505b509350600090506000915060005b600554811015620035995760076000828152602001908152602001600020549250828e83815181106200309957620030996200446a565b60200260200101818152505060066000848152602001908152602001600020600501548d8381518110620030d157620030d16200446a565b60200260200101818152505060066000848152602001908152602001600020600601805462003100906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200312e906200423b565b80156200317f5780601f1062003153576101008083540402835291602001916200317f565b820191906000526020600020905b8154815290600101906020018083116200316157829003601f168201915b50505050508c83815181106200319957620031996200446a565b602002602001018190525060066000848152602001908152602001600020600701548b8381518110620031d057620031d06200446a565b602002602001018181525050600660008481526020019081526020016000206008018054620031ff906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200322d906200423b565b80156200327e5780601f1062003252576101008083540402835291602001916200327e565b820191906000526020600020905b8154815290600101906020018083116200326057829003601f168201915b50505050508a83815181106200329857620032986200446a565b6020026020010181905250600660008481526020019081526020016000206000016002018054620032c9906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620032f7906200423b565b8015620033485780601f106200331c5761010080835404028352916020019162003348565b820191906000526020600020905b8154815290600101906020018083116200332a57829003601f168201915b50505050508983815181106200336257620033626200446a565b602090810291909101810191909152600084815260069091526040902060030154885160ff90911690899084908110620033a057620033a06200446a565b60ff90921660209283029190910182015260008481526006909152604090208054620033cc906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620033fa906200423b565b80156200344b5780601f106200341f576101008083540402835291602001916200344b565b820191906000526020600020905b8154815290600101906020018083116200342d57829003601f168201915b50505050508783815181106200346557620034656200446a565b602002602001018190525060066000848152602001908152602001600020600001600101805462003496906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620034c4906200423b565b8015620035155780601f10620034e95761010080835404028352916020019162003515565b820191906000526020600020905b815481529060010190602001808311620034f757829003601f168201915b50505050508683815181106200352f576200352f6200446a565b602002602001018190525060066000848152602001908152602001600020600001600401548583815181106200356957620035696200446a565b60209081029190910101528162003580816200421f565b925050808062003590906200421f565b91505062003062565b5050505090919293949596979899565b6008546001600160a01b03163314620035d65760405162461bcd60e51b8152600401620008ed90620040f4565b6000838383604051620035e990620036b5565b620035f79392919062004730565b604051809103906000f08015801562003614573d6000803e3d6000fd5b5090507fbb5f9980e27ec75b79e41ce422e643c6c0116fd9f599776a72f89032f70fe205818585856040516200364e949392919062003cb9565b60405180910390a150505050565b60006200366a82846200476d565b90505b92915050565b50805462003681906200423b565b6000825580601f1062003692575050565b601f016020900490600052602060002090810190620036b29190620036c3565b50565b611419806200478483390190565b5b80821115620036da5760008155600101620036c4565b5090565b80356001600160a01b0381168114620036f657600080fd5b919050565b6000602082840312156200370e57600080fd5b6200366a82620036de565b60008083601f8401126200372c57600080fd5b5081356001600160401b038111156200374457600080fd5b6020830191508360208260051b85010111156200376057600080fd5b9250929050565b600080600080600080600060a0888a0312156200378357600080fd5b873596506200379560208901620036de565b9550620037a560408901620036de565b945060608801356001600160401b0380821115620037c257600080fd5b620037d08b838c0162003719565b909650945060808a0135915080821115620037ea57600080fd5b50620037f98a828b0162003719565b989b979a50959850939692959293505050565b6000602082840312156200381f57600080fd5b5035919050565b6000806000606084860312156200383c57600080fd5b6200384784620036de565b92506200385760208501620036de565b9150604084013590509250925092565b60005b83811015620038845781810151838201526020016200386a565b50506000910152565b60008151808452620038a781602086016020860162003867565b601f01601f19169290920160200192915050565b838152606060208201526000620038d660608301856200388d565b9050826040830152949350505050565b60008060408385031215620038fa57600080fd5b6200390583620036de565b91506200391560208401620036de565b90509250929050565b60008083601f8401126200393157600080fd5b5081356001600160401b038111156200394957600080fd5b6020830191508360208285010111156200376057600080fd5b60008060008060008060008060c0898b0312156200397f57600080fd5b8835975060208901356001600160401b03808211156200399e57600080fd5b908a019060a0828d031215620039b357600080fd5b90975060408a0135965060608a01359080821115620039d157600080fd5b620039df8c838d016200391e565b909750955060808b0135945060a08b013591508082111562003a0057600080fd5b5062003a0f8b828c016200391e565b999c989b5096995094979396929594505050565b6000806040838503121562003a3757600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101562003a785781518752958201959082019060010162003a5a565b509495945050505050565b6000815180845260208085019450848260051b860182860160005b8581101562003acc57838303895262003ab98383516200388d565b9885019892509084019060010162003a9e565b5090979650505050505050565b600081518084526020808501945080840160005b8381101562003a7857815160ff168752958201959082019060010162003aed565b600061014080835262003b248184018e62003a46565b9050828103602084015262003b3a818d62003a46565b9050828103604084015262003b50818c62003a83565b9050828103606084015262003b66818b62003a46565b9050828103608084015262003b7c818a62003a83565b905082810360a084015262003b92818962003a83565b905082810360c084015262003ba8818862003ad9565b905082810360e084015262003bbe818762003a83565b905082810361010084015262003bd5818662003a83565b905082810361012084015262003bec818562003a46565b9d9c50505050505050505050505050565b60a081526000865160a08084015262003c1b6101408401826200388d565b90506020880151609f19808584030160c086015262003c3b83836200388d565b925060408a01519150808584030160e08601525062003c5b82826200388d565b91505060ff6060890151166101008401526080880151610120840152866020840152828103604084015262003c9181876200388d565b9050846060840152828103608084015262003cad81856200388d565b98975050505050505050565b6001600160a01b038516815260806020820181905260009062003cdf908301866200388d565b828103604084015262003cf381866200388d565b91505060ff8316606083015295945050505050565b60a08152600062003d1d60a08301886200388d565b828103602084015262003d3181886200388d565b9050828103604084015262003d4781876200388d565b60ff9590951660608401525050608001529392505050565b600080600080600080600080600060c08a8c03121562003d7e57600080fd5b8935985062003d9060208b01620036de565b975062003da060408b01620036de565b965060608a01356001600160401b038082111562003dbd57600080fd5b62003dcb8d838e0162003719565b909850965060808c013591508082111562003de557600080fd5b62003df38d838e0162003719565b909650945060a08c013591508082111562003e0d57600080fd5b5062003e1c8c828d016200391e565b915080935050809150509295985092959850929598565b60008060008060006060868803121562003e4c57600080fd5b62003e5786620036de565b945060208601356001600160401b038082111562003e7457600080fd5b62003e8289838a016200391e565b9096509450604088013591508082111562003e9c57600080fd5b5062003eab888289016200391e565b969995985093965092949392505050565b84815260806020820152600062003ed760808301866200388d565b846040840152828103606084015262003ef181856200388d565b979650505050505050565b6000806000806040858703121562003f1357600080fd5b84356001600160401b038082111562003f2b57600080fd5b62003f398883890162003719565b9096509450602087013591508082111562003f5357600080fd5b5062003f628782880162003719565b95989497509550505050565b60408152600062003f8360408301856200388d565b905060ff831660208301529392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562003fd65762003fd662003f95565b604052919050565b60006001600160401b0382111562003ffa5762003ffa62003f95565b50601f01601f191660200190565b600082601f8301126200401a57600080fd5b8135620040316200402b8262003fde565b62003fab565b8181528460208386010111156200404757600080fd5b816020850160208301376000918101602001919091529392505050565b60ff81168114620036b257600080fd5b6000806000606084860312156200408a57600080fd5b83356001600160401b0380821115620040a257600080fd5b620040b08783880162004008565b94506020860135915080821115620040c757600080fd5b50620040d68682870162004008565b9250506040840135620040e98162004064565b809150509250925092565b6020808252600990820152682737ba1037bbb732b960b91b604082015260600190565b6020808252600990820152683737ba1030b236b4b760b91b604082015260600190565b81835260006001600160fb1b038311156200415457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906200419490830184866200413a565b95945050505050565b6001600160a01b0386168152606060208201819052600090620041c490830186886200413a565b828103604084015262003cad8185876200413a565b634e487b7160e01b600052601160045260246000fd5b818103818111156200366d576200366d620041d9565b600081620042175762004217620041d9565b506000190190565b600060018201620042345762004234620041d9565b5060010190565b600181811c908216806200425057607f821691505b6020821081036200427157634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000cd357600081815260208120601f850160051c81016020861015620042a05750805b601f850160051c820191505b8181101562000f0d57828155600101620042ac565b6001600160401b03831115620042db57620042db62003f95565b620042f383620042ec83546200423b565b8362004277565b6000601f8411600181146200432a5760008515620043115750838201355b600019600387901b1c1916600186901b1783556200091c565b600083815260209020601f19861690835b828110156200435d57868501358255602094850194600190920191016200433b565b50868210156200437b5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000808335601e19843603018112620043a557600080fd5b8301803591506001600160401b03821115620043c057600080fd5b6020019150368190038213156200376057600080fd5b600060208284031215620043e957600080fd5b8135620043f68162004064565b9392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b86815260806020820152600062004442608083018789620043fd565b85604084015282810360608401526200445d818587620043fd565b9998505050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126200449857600080fd5b83016020810192503590506001600160401b03811115620044b857600080fd5b8036038213156200376057600080fd5b60a081526000620044da898a62004480565b60a080850152620044f161014085018284620043fd565b9150506200450360208b018b62004480565b609f19808685030160c08701526200451d848385620043fd565b93506200452e60408e018e62004480565b93509150808685030160e0870152506200454a838383620043fd565b9250505060608a01356200455e8162004064565b60ff1661010084015260808a01356101208401526020830189905282810360408401526200458e81888a620043fd565b90508560608401528281036080840152620045ab818587620043fd565b9a9950505050505050505050565b600060208284031215620045cc57600080fd5b81516001600160401b03811115620045e357600080fd5b8201601f81018413620045f557600080fd5b8051620046066200402b8262003fde565b8181528560208385010111156200461c57600080fd5b6200419482602083016020860162003867565b6000602082840312156200464257600080fd5b8151620043f68162004064565b6001600160a01b03861681526060602082018190526000906200467690830186886200413a565b828103604084015262003cad818587620043fd565b6001600160a01b0388168152608060208201819052600090620046b2908301888a6200413a565b8281036040840152620046c78187896200413a565b90508281036060840152620045ab818587620043fd565b604081526000620046f4604083018688620043fd565b828103602084015262003ef1818587620043fd565b6001600160a01b0386168152606060208201819052600090620046769083018688620043fd565b6060815260006200474560608301866200388d565b82810360208401526200475981866200388d565b91505060ff83166040830152949350505050565b808201808211156200366d576200366d620041d956fe60806040523480156200001157600080fd5b5060405162001419380380620014198339810160408190526200003491620001d0565b82826003620000448382620002e4565b506004620000538282620002e4565b505050620000706200006a620000b560201b60201c565b620000b9565b60066200007e8482620002e4565b5060076200008d8382620002e4565b506005805460ff909216600160a01b0260ff60a01b1990921691909117905550620003b09050565b3390565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013357600080fd5b81516001600160401b03808211156200015057620001506200010b565b604051601f8301601f19908116603f011681019082821181831017156200017b576200017b6200010b565b816040528381526020925086838588010111156200019857600080fd5b600091505b83821015620001bc57858201830151818301840152908201906200019d565b600093810190920192909252949350505050565b600080600060608486031215620001e657600080fd5b83516001600160401b0380821115620001fe57600080fd5b6200020c8783880162000121565b945060208601519150808211156200022357600080fd5b50620002328682870162000121565b925050604084015160ff811681146200024a57600080fd5b809150509250925092565b600181811c908216806200026a57607f821691505b6020821081036200028b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002df57600081815260208120601f850160051c81016020861015620002ba5750805b601f850160051c820191505b81811015620002db57828155600101620002c6565b5050505b505050565b81516001600160401b038111156200030057620003006200010b565b620003188162000311845462000255565b8462000291565b602080601f831160018114620003505760008415620003375750858301515b600019600386901b1c1916600185901b178555620002db565b600085815260208120601f198616915b82811015620003815788860151825594840194600190910190840162000360565b5085821015620003a05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61105980620003c06000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063715018a6116100ad578063a457c2d711610071578063a457c2d71461027e578063a9059cbb14610291578063dd62ed3e146102a4578063f2fde38b146102b7578063f4c84d19146102ca57600080fd5b8063715018a61461022d57806379cc6790146102355780638da5cb5b1461024857806395d89b41146102635780639dc29fac1461026b57600080fd5b806339509351116100f457806339509351146101b657806340c10f19146101c957806342966c68146101de5780634fb2e45d146101f157806370a082311461020457600080fd5b806306fdde0314610131578063095ea7b31461014f57806318160ddd1461017257806323b872dd14610184578063313ce56714610197575b600080fd5b6101396102dd565b6040516101469190610c75565b60405180910390f35b61016261015d366004610cdf565b61036f565b6040519015158152602001610146565b6002545b604051908152602001610146565b610162610192366004610d09565b610389565b600554600160a01b900460ff1660405160ff9091168152602001610146565b6101626101c4366004610cdf565b6103ad565b6101dc6101d7366004610cdf565b6103cf565b005b6101dc6101ec366004610d45565b61042c565b6101dc6101ff366004610d5e565b610439565b610176610212366004610d5e565b6001600160a01b031660009081526020819052604090205490565b6101dc61044a565b6101dc610243366004610cdf565b61045e565b6005546040516001600160a01b039091168152602001610146565b610139610477565b6101dc610279366004610cdf565b610486565b61016261028c366004610cdf565b6104d9565b61016261029f366004610cdf565b610554565b6101766102b2366004610d80565b610562565b6101dc6102c5366004610d5e565b61058d565b6101dc6102d8366004610e56565b610603565b6060600680546102ec90610eba565b80601f016020809104026020016040519081016040528092919081815260200182805461031890610eba565b80156103655780601f1061033a57610100808354040283529160200191610365565b820191906000526020600020905b81548152906001019060200180831161034857829003601f168201915b5050505050905090565b60003361037d818585610624565b60019150505b92915050565b600033610397858285610748565b6103a28585856107c2565b506001949350505050565b60003361037d8185856103c08383610562565b6103ca9190610ef4565b610624565b6103d7610971565b806000811161041d5760405162461bcd60e51b815260206004820152600d60248201526c15985b1d59481a5cc81b9d5b1b609a1b60448201526064015b60405180910390fd5b61042783836109cb565b505050565b6104363382610a96565b50565b610441610971565b6104368161058d565b610452610971565b61045c6000610bd4565b565b610469823383610748565b6104738282610a96565b5050565b6060600780546102ec90610eba565b61048e610971565b80600081116104cf5760405162461bcd60e51b815260206004820152600d60248201526c15985b1d59481a5cc81b9d5b1b609a1b6044820152606401610414565b6104278383610a96565b600033816104e78286610562565b9050838110156105475760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610414565b6103a28286868403610624565b60003361037d8185856107c2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610595610971565b6001600160a01b0381166105fa5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610414565b61043681610bd4565b61060b610971565b60066106178382610f63565b5060076104278282610f63565b6001600160a01b0383166106865760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610414565b6001600160a01b0382166106e75760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610414565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006107548484610562565b905060001981146107bc57818110156107af5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610414565b6107bc8484848403610624565b50505050565b6001600160a01b0383166108265760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610414565b6001600160a01b0382166108885760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610414565b610893838383610c26565b6001600160a01b0383166000908152602081905260409020548181101561090b5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610414565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36107bc565b6005546001600160a01b0316331461045c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610414565b6001600160a01b038216610a215760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610414565b610a2d60008383610c26565b8060026000828254610a3f9190610ef4565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610af65760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610414565b610b0282600083610c26565b6001600160a01b03821660009081526020819052604090205481811015610b765760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610414565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b306001600160a01b038316036104275760405162461bcd60e51b81526020600482015260146024820152731d1bc81859191c995cdcc81a5b98dbdc9c9958dd60621b6044820152606401610414565b600060208083528351808285015260005b81811015610ca257858101830151858201604001528201610c86565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610cda57600080fd5b919050565b60008060408385031215610cf257600080fd5b610cfb83610cc3565b946020939093013593505050565b600080600060608486031215610d1e57600080fd5b610d2784610cc3565b9250610d3560208501610cc3565b9150604084013590509250925092565b600060208284031215610d5757600080fd5b5035919050565b600060208284031215610d7057600080fd5b610d7982610cc3565b9392505050565b60008060408385031215610d9357600080fd5b610d9c83610cc3565b9150610daa60208401610cc3565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610dda57600080fd5b813567ffffffffffffffff80821115610df557610df5610db3565b604051601f8301601f19908116603f01168101908282118183101715610e1d57610e1d610db3565b81604052838152866020858801011115610e3657600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215610e6957600080fd5b823567ffffffffffffffff80821115610e8157600080fd5b610e8d86838701610dc9565b93506020850135915080821115610ea357600080fd5b50610eb085828601610dc9565b9150509250929050565b600181811c90821680610ece57607f821691505b602082108103610eee57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561038357634e487b7160e01b600052601160045260246000fd5b601f82111561042757600081815260208120601f850160051c81016020861015610f3c5750805b601f850160051c820191505b81811015610f5b57828155600101610f48565b505050505050565b815167ffffffffffffffff811115610f7d57610f7d610db3565b610f9181610f8b8454610eba565b84610f15565b602080601f831160018114610fc65760008415610fae5750858301515b600019600386901b1c1916600185901b178555610f5b565b600085815260208120601f198616915b82811015610ff557888601518255948401946001909101908401610fd6565b50858210156110135787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220d6e77c582a20ca54c3c7c855197faee6ae98dd5cadc02f78be55abb5bcbebc3a64736f6c63430008120033a264697066735822122027abfc8f211406077d0cd812d4bb9d4dcd16479b5ac7cce5833f0e94662fc4cb64736f6c63430008120033

Deployed Bytecode

0x608060405260043610620002535760003560e01c8063715018a6116200013f578063b3ab15fb11620000bb578063d51dddd71162000079578063d51dddd714620007ac578063e101d3c114620007f1578063e24e4fdb1462000826578063f3bdd863146200083e578063f4debe1e14620008635762000265565b8063b3ab15fb14620006f1578063b90732761462000716578063cbfbd61a146200074d578063d0ad718d1462000772578063d4ee1d90146200078a5762000265565b80638da5cb5b11620001095780638da5cb5b14620006285780639027e6f7146200064a5780639947f9321462000682578063a6f9dae114620006a7578063af33f17e14620006cc5762000265565b8063715018a6146200057a57806375d2e27d146200059257806379ba509714620005d95780638c7a63ae14620005f15762000265565b80634fb2e45d11620001cf5780635c60da1b11620001995780635c60da1b14620004b35780635d2e9ead14620004d35780636bec32da146200050b5780636c45e2dc14620005305780637048027514620005555762000265565b80634fb2e45d14620003d6578063563cb1ab14620003fb578063570ca735146200043857806358a007fb14620004735762000265565b80633ad8873a116200021d5780633ad8873a14620003035780633cc281df1462000342578063408e743d146200036757806341246e53146200038c5780634f600ae814620003b15762000265565b80631785f53c146200026f5780632859c58014620002945780632b56590514620002b95780633416794d14620002de5762000265565b3662000265576200026362000897565b005b6200026362000897565b3480156200027c57600080fd5b50620002636200028e366004620036fb565b62000923565b348015620002a157600080fd5b5062000263620002b336600462003767565b620009a8565b348015620002c657600080fd5b5062000263620002d83660046200380c565b62000ad3565b348015620002eb57600080fd5b5062000263620002fd36600462003826565b62000cd8565b3480156200031057600080fd5b5062000328620003223660046200380c565b62000d6b565b6040516200033993929190620038bb565b60405180910390f35b3480156200034f57600080fd5b506200026362000361366004620036fb565b62000e35565b3480156200037457600080fd5b506200026362000386366004620038e6565b62000e86565b3480156200039957600080fd5b5062000263620003ab366004620038e6565b62000f15565b348015620003be57600080fd5b5062000263620003d036600462003962565b62000f71565b348015620003e357600080fd5b5062000263620003f5366004620036fb565b6200117e565b3480156200040857600080fd5b50620004206200041a36600462003a23565b6200125f565b604051620003399a9998979695949392919062003b0e565b3480156200044557600080fd5b50600c546200045a906001600160a01b031681565b6040516001600160a01b03909116815260200162000339565b3480156200048057600080fd5b50620004a4620004923660046200380c565b60076020526000908152604090205481565b60405190815260200162000339565b348015620004c057600080fd5b50600b546001600160a01b03166200045a565b348015620004e057600080fd5b50620004f8620004f23660046200380c565b62001bec565b6040516200033995949392919062003bfd565b3480156200051857600080fd5b50620002636200052a36600462003826565b62001f34565b3480156200053d57600080fd5b50620002636200054f36600462003962565b62001f9c565b3480156200056257600080fd5b506200026362000574366004620036fb565b62002162565b3480156200058757600080fd5b5062000263620021e4565b3480156200059f57600080fd5b50620005c6620005b13660046200380c565b600d6020526000908152604090205460ff1681565b60405160ff909116815260200162000339565b348015620005e657600080fd5b506200026362002223565b348015620005fe57600080fd5b5062000616620006103660046200380c565b6200225b565b60405162000339949392919062003cb9565b3480156200063557600080fd5b506008546200045a906001600160a01b031681565b3480156200065757600080fd5b506200066f620006693660046200380c565b6200249d565b6040516200033995949392919062003d08565b3480156200068f57600080fd5b5062000263620006a136600462003d5f565b620026c1565b348015620006b457600080fd5b5062000263620006c6366004620036fb565b620027ba565b348015620006d957600080fd5b5062000263620006eb36600462003e33565b62002809565b348015620006fe57600080fd5b506200026362000710366004620036fb565b620028e6565b3480156200072357600080fd5b506200073b620007353660046200380c565b6200296f565b60405162000339949392919062003ebc565b3480156200075a57600080fd5b50620002636200076c36600462003efc565b62002ada565b3480156200077f57600080fd5b50620004a460055481565b3480156200079757600080fd5b506009546200045a906001600160a01b031681565b348015620007b957600080fd5b50620007e0620007cb366004620036fb565b600a6020526000908152604090205460ff1681565b604051901515815260200162000339565b348015620007fe57600080fd5b5062000816620008103660046200380c565b62002c70565b6040516200033992919062003f6e565b3480156200083357600080fd5b506200042062002d37565b3480156200084b57600080fd5b50620002636200085d36600462004074565b620035a9565b3480156200087057600080fd5b50620004a4620008823660046200380c565b60009081526006602052604090206004015490565b600b546001600160a01b031680620008f65760405162461bcd60e51b815260206004820152601f60248201527f696d706c656d656e746174696f6e20636f6e7472616374206e6f74207365740060448201526064015b60405180910390fd5b60405136600082376000803683855af43d806000843e81801562000918578184f35b8184fd5b5050505050565b6008546001600160a01b03163314620009505760405162461bcd60e51b8152600401620008ed90620040f4565b6001600160a01b0381166000818152600a6020908152604091829020805460ff1916905590519182527f753f40ca3312b2408759a67875b367955e7baa221daf08aa3d643d96202ac12b91015b60405180910390a150565b336000908152600a602052604090205460ff16620009da5760405162461bcd60e51b8152600401620008ed9062004117565b6001870362000a4f5760405163b2dc5dc360e01b81526001600160a01b0387169063b2dc5dc39062000a15908890889088906004016200416d565b600060405180830381600087803b15801562000a3057600080fd5b505af115801562000a45573d6000803e3d6000fd5b5050505062000aca565b6002870362000a8e57604051631ac8311560e21b81526001600160a01b03871690636b20c4549062000a1590889088908890889088906004016200419d565b60405162461bcd60e51b815260206004820152601060248201526f496e76616c6964204e4654207479706560801b6044820152606401620008ed565b50505050505050565b6008546001600160a01b0316331462000b005760405162461bcd60e51b8152600401620008ed90620040f4565b600081815260066020526040902060050154819062000b545760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401620008ed565b60005b60055481101562000cd357600081815260076020526040902054830362000cbe57600160055462000b899190620041ef565b811462000bc65760076000600160055462000ba59190620041ef565b81526020808201929092526040908101600090812054848252600790935220555b60076000600160055462000bdb9190620041ef565b8152602001908152602001600020600090556005600081548092919062000c029062004205565b9091555050600083815260066020526040812090818162000c24828262003673565b62000c3460018301600062003673565b62000c4460028301600062003673565b5060038101805460ff19169055600060049091018190556005830181905562000c7290600684019062003673565b600782016000905560088201600062000c8c919062003673565b505060405183907fa219112a711e6173c2e8978836823d4e86832d96c0ea2fd05ec77687b7a073ab90600090a2505050565b8062000cca816200421f565b91505062000b57565b505050565b336000908152600a602052604090205460ff1662000d0a5760405162461bcd60e51b8152600401620008ed9062004117565b604051632770a7eb60e21b81526001600160a01b03838116600483015260248201839052841690639dc29fac906044015b600060405180830381600087803b15801562000d5657600080fd5b505af115801562000aca573d6000803e3d6000fd5b60008181526006602081905260408220600581015491018054919260609290919062000d97906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462000dc5906200423b565b801562000e165780601f1062000dea5761010080835404028352916020019162000e16565b820191906000526020600020905b81548152906001019060200180831162000df857829003601f168201915b5050506000968752505060066020526040909420600701549294915050565b806001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801562000e7157600080fd5b505af11580156200091c573d6000803e3d6000fd5b6008546001600160a01b0316331462000eb35760405162461bcd60e51b8152600401620008ed90620040f4565b604051634fb2e45d60e01b81526001600160a01b038281166004830152831690634fb2e45d906024015b600060405180830381600087803b15801562000ef857600080fd5b505af115801562000f0d573d6000803e3d6000fd5b505050505050565b6008546001600160a01b0316331462000f425760405162461bcd60e51b8152600401620008ed90620040f4565b60405163a6f9dae160e01b81526001600160a01b03828116600483015283169063a6f9dae19060240162000edd565b6008546001600160a01b0316331462000f9e5760405162461bcd60e51b8152600401620008ed90620040f4565b60008881526006602052604090206005015488901562000fef5760405162461bcd60e51b815260206004820152600b60248201526a1d1bdad95b88195e1a5cdd60aa1b6044820152606401620008ed565b6000898152600660208190526040909120600581018990550162001015868883620042c1565b506000898152600660205260409020600781018590556008016200103b838583620042c1565b506200104888806200438d565b60008b81526006602052604090209162001064919083620042c1565b506200107460208901896200438d565b60008b81526006602052604090206001019162001093919083620042c1565b50620010a360408901896200438d565b60008b815260066020526040902060020191620010c2919083620042c1565b50620010d56080890160608a01620043d6565b60008a815260066020908152604080832060038101805460ff191660ff969096169590951790945560808c013560049094019390935560058054835260079091529190208a9055546200112a9060016200365c565b60055560405189907f226f08da880957e11c8affd4d622bb21b058cf67830d2ee56bb82d9b7197e9a7906200116b908a908a908a908a908a908a9062004426565b60405180910390a2505050505050505050565b6008546001600160a01b03163314620011ab5760405162461bcd60e51b8152600401620008ed90620040f4565b6001600160a01b038116620012035760405162461bcd60e51b815260206004820152601d60248201527f4e6577206f776e657220697320746865207a65726f20616464726573730000006044820152606401620008ed565b6008546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600880546001600160a01b0319166001600160a01b0392909216919091179055565b6060806060806060806060806060806000806000806005546001600160401b0381111562001291576200129162003f95565b604051908082528060200260200182016040528015620012bb578160200160208202803683370190505b5090505b6005548310156200139f57600760008481526020019081526020016000205491508f60066000848152602001908152602001600020600501541480156200131657506000828152600660205260409020600701548f145b806200135357508f60066000848152602001908152602001600020600701541480156200135357506000828152600660205260409020600501548f145b156200138a57818185815181106200136f576200136f6200446a565b60209081029190910101528362001386816200421f565b9450505b8262001396816200421f565b935050620012bf565b836001600160401b03811115620013ba57620013ba62003f95565b604051908082528060200260200182016040528015620013e4578160200160208202803683370190505b509d50836001600160401b0381111562001402576200140262003f95565b6040519080825280602002602001820160405280156200142c578160200160208202803683370190505b509c50836001600160401b038111156200144a576200144a62003f95565b6040519080825280602002602001820160405280156200147f57816020015b6060815260200190600190039081620014695790505b509b50836001600160401b038111156200149d576200149d62003f95565b604051908082528060200260200182016040528015620014c7578160200160208202803683370190505b509a50836001600160401b03811115620014e557620014e562003f95565b6040519080825280602002602001820160405280156200151a57816020015b6060815260200190600190039081620015045790505b509950836001600160401b0381111562001538576200153862003f95565b6040519080825280602002602001820160405280156200156d57816020015b6060815260200190600190039081620015575790505b509850836001600160401b038111156200158b576200158b62003f95565b604051908082528060200260200182016040528015620015b5578160200160208202803683370190505b509750836001600160401b03811115620015d357620015d362003f95565b6040519080825280602002602001820160405280156200160857816020015b6060815260200190600190039081620015f25790505b509650836001600160401b0381111562001626576200162662003f95565b6040519080825280602002602001820160405280156200165b57816020015b6060815260200190600190039081620016455790505b509550836001600160401b0381111562001679576200167962003f95565b604051908082528060200260200182016040528015620016a3578160200160208202803683370190505b509450600092505b8383101562001bd957808381518110620016c957620016c96200446a565b60200260200101519150818e8481518110620016e957620016e96200446a565b60200260200101818152505060066000838152602001908152602001600020600501548d84815181106200172157620017216200446a565b60200260200101818152505060066000838152602001908152602001600020600601805462001750906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200177e906200423b565b8015620017cf5780601f10620017a357610100808354040283529160200191620017cf565b820191906000526020600020905b815481529060010190602001808311620017b157829003601f168201915b50505050508c8481518110620017e957620017e96200446a565b602002602001018190525060066000838152602001908152602001600020600701548b84815181106200182057620018206200446a565b6020026020010181815250506006600083815260200190815260200160002060080180546200184f906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200187d906200423b565b8015620018ce5780601f10620018a257610100808354040283529160200191620018ce565b820191906000526020600020905b815481529060010190602001808311620018b057829003601f168201915b50505050508a8481518110620018e857620018e86200446a565b602002602001018190525060066000838152602001908152602001600020600001600201805462001919906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001947906200423b565b8015620019985780601f106200196c5761010080835404028352916020019162001998565b820191906000526020600020905b8154815290600101906020018083116200197a57829003601f168201915b5050505050898481518110620019b257620019b26200446a565b602090810291909101810191909152600083815260069091526040902060030154885160ff90911690899085908110620019f057620019f06200446a565b60ff9092166020928302919091018201526000838152600690915260409020805462001a1c906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001a4a906200423b565b801562001a9b5780601f1062001a6f5761010080835404028352916020019162001a9b565b820191906000526020600020905b81548152906001019060200180831162001a7d57829003601f168201915b505050505087848151811062001ab55762001ab56200446a565b602002602001018190525060066000838152602001908152602001600020600001600101805462001ae6906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001b14906200423b565b801562001b655780601f1062001b395761010080835404028352916020019162001b65565b820191906000526020600020905b81548152906001019060200180831162001b4757829003601f168201915b505050505086848151811062001b7f5762001b7f6200446a565b6020026020010181905250600660008381526020019081526020016000206000016004015485848151811062001bb95762001bb96200446a565b60209081029190910101528262001bd0816200421f565b935050620016ab565b505050509295989b9194979a5092959850565b6006602052806000526040600020600091509050806000016040518060a001604052908160008201805462001c21906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001c4f906200423b565b801562001ca05780601f1062001c745761010080835404028352916020019162001ca0565b820191906000526020600020905b81548152906001019060200180831162001c8257829003601f168201915b5050505050815260200160018201805462001cbb906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001ce9906200423b565b801562001d3a5780601f1062001d0e5761010080835404028352916020019162001d3a565b820191906000526020600020905b81548152906001019060200180831162001d1c57829003601f168201915b5050505050815260200160028201805462001d55906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001d83906200423b565b801562001dd45780601f1062001da85761010080835404028352916020019162001dd4565b820191906000526020600020905b81548152906001019060200180831162001db657829003601f168201915b5050509183525050600382015460ff16602082015260049091015460409091015260058201546006830180549293919262001e0f906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001e3d906200423b565b801562001e8e5780601f1062001e625761010080835404028352916020019162001e8e565b820191906000526020600020905b81548152906001019060200180831162001e7057829003601f168201915b50505050509080600701549080600801805462001eab906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462001ed9906200423b565b801562001f2a5780601f1062001efe5761010080835404028352916020019162001f2a565b820191906000526020600020905b81548152906001019060200180831162001f0c57829003601f168201915b5050505050905085565b336000908152600a602052604090205460ff1662001f665760405162461bcd60e51b8152600401620008ed9062004117565b6040516340c10f1960e01b81526001600160a01b038381166004830152602482018390528416906340c10f199060440162000d3b565b6008546001600160a01b0316331462001fc95760405162461bcd60e51b8152600401620008ed90620040f4565b60008881526006602052604090206005015488906200201d5760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881b9bdd08195e1a5cdd608a1b6044820152606401620008ed565b6200202988806200438d565b60008b81526006602052604090209162002045919083620042c1565b506200205560208901896200438d565b60008b81526006602052604090206001019162002074919083620042c1565b506200208460408901896200438d565b60008b815260066020526040902060020191620020a3919083620042c1565b50620020b66080890160608a01620043d6565b60008a815260066020819052604090912060038101805460ff191660ff949094169390931790925560808a013560048301556005820189905501620020fd868883620042c1565b5060008981526006602052604090206007810185905560080162002123838583620042c1565b50887f4eb0f9fb05e08613a2eba9dc272a43421cf32f9ccab592725ab663e3238f5f55898989898989896040516200116b9796959493929190620044c8565b6008546001600160a01b031633146200218f5760405162461bcd60e51b8152600401620008ed90620040f4565b6001600160a01b0381166000818152600a6020908152604091829020805460ff1916600117905590519182527fad6de4452a631e641cb59902236607946ce9272b9b981f2f80e8d129cb9084ba91016200099d565b6008546001600160a01b03163314620022115760405162461bcd60e51b8152600401620008ed90620040f4565b600880546001600160a01b0319169055565b6009546001600160a01b031633036200225957600954600880546001600160a01b0319166001600160a01b039092169190911790555b565b600081815260066020526040812060050154606090819083908103620022a457505060408051602080820183526000808352835191820190935282815291935091508262002496565b60008581526006602052604081206008018054620023539190620022c8906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620022f6906200423b565b8015620023475780601f106200231b5761010080835404028352916020019162002347565b820191906000526020600020905b8154815290600101906020018083116200232957829003601f168201915b50505050506014015190565b9050806001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562002394573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620023be9190810190620045b9565b9350806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620023ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620024299190810190620045b9565b9250806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200246a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200249091906200462f565b90945090505b9193509193565b6000818152600660205260408120805460609283928392829190620024c2906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620024f0906200423b565b8015620025415780601f10620025155761010080835404028352916020019162002541565b820191906000526020600020905b8154815290600101906020018083116200252357829003601f168201915b505050600089815260066020526040902060010180549398509262002569925090506200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462002597906200423b565b8015620025e85780601f10620025bc57610100808354040283529160200191620025e8565b820191906000526020600020905b815481529060010190602001808311620025ca57829003601f168201915b505050600089815260066020526040902060020180549397509262002610925090506200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200263e906200423b565b80156200268f5780601f1062002663576101008083540402835291602001916200268f565b820191906000526020600020905b8154815290600101906020018083116200267157829003601f168201915b50505060009889525050600660205260409096206003810154600490910154959794969560ff90911694909350915050565b336000908152600a602052604090205460ff16620026f35760405162461bcd60e51b8152600401620008ed9062004117565b600189036200276c57604051631143124160e11b81526001600160a01b0389169063228624829062002732908a908a908a90889088906004016200464f565b600060405180830381600087803b1580156200274d57600080fd5b505af115801562002762573d6000803e3d6000fd5b50505050620027af565b6002890362000a8e57604051630fbfeffd60e11b81526001600160a01b03891690631f7fdffa9062002732908a908a908a908a908a908a908a906004016200468b565b505050505050505050565b6008546001600160a01b03163314620027e75760405162461bcd60e51b8152600401620008ed90620040f4565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6008546001600160a01b03163314620028365760405162461bcd60e51b8152600401620008ed90620040f4565b60405163f4c84d1960e01b81526001600160a01b0386169063f4c84d19906200286a908790879087908790600401620046de565b600060405180830381600087803b1580156200288557600080fd5b505af11580156200289a573d6000803e3d6000fd5b505050507f86ead451719b8f4b763de2648808971e9bf540eed93efadafb044cd7ef5d91f48585858585604051620028d795949392919062004709565b60405180910390a15050505050565b6008546001600160a01b03163314620029135760405162461bcd60e51b8152600401620008ed90620040f4565b600c546040516001600160a01b038084169216907f2709918445f306d3e94d280907c62c5d2525ac3192d2e544774c7f181d65af3e90600090a3600c80546001600160a01b0319166001600160a01b0392909216919091179055565b600081815260066020819052604082206005810154910180549192606092909183916200299c906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620029ca906200423b565b801562002a1b5780601f10620029ef5761010080835404028352916020019162002a1b565b820191906000526020600020905b815481529060010190602001808311620029fd57829003601f168201915b50505060008881526006602052604090206007810154600890910180549497509095509262002a4d925090506200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462002a7b906200423b565b801562002acc5780601f1062002aa05761010080835404028352916020019162002acc565b820191906000526020600020905b81548152906001019060200180831162002aae57829003601f168201915b505050505090509193509193565b600c546001600160a01b0316331462002b255760405162461bcd60e51b815260206004820152600c60248201526b3737ba1037b832b930ba37b960a11b6044820152606401620008ed565b82811462002b685760405162461bcd60e51b815260206004820152600f60248201526e0d8cadccee8d040dad2e6dac2e8c6d608b1b6044820152606401620008ed565b60005b838110156200091c5782828281811062002b895762002b896200446a565b905060200201602081019062002ba09190620043d6565b600d600087878581811062002bb95762002bb96200446a565b90506020020135815260200190815260200160002060006101000a81548160ff021916908360ff16021790555082828281811062002bfb5762002bfb6200446a565b905060200201602081019062002c129190620043d6565b60ff1685858381811062002c2a5762002c2a6200446a565b905060200201357f20f86c53e8884644ce473603799d40ecf47d8c4c1d55384fe8d0eeaf697786eb60405160405180910390a362002c68816200421f565b905062002b6b565b60008181526006602052604081206002018054606092919062002c93906200423b565b80601f016020809104026020016040519081016040528092919081815260200182805462002cc1906200423b565b801562002d125780601f1062002ce65761010080835404028352916020019162002d12565b820191906000526020600020905b81548152906001019060200180831162002cf457829003601f168201915b505050600095865250506006602052604090932060030154929360ff90931692915050565b60608060608060608060608060608060006005549050600080826001600160401b0381111562002d6b5762002d6b62003f95565b60405190808252806020026020018201604052801562002d95578160200160208202803683370190505b509c50826001600160401b0381111562002db35762002db362003f95565b60405190808252806020026020018201604052801562002ddd578160200160208202803683370190505b509b50826001600160401b0381111562002dfb5762002dfb62003f95565b60405190808252806020026020018201604052801562002e3057816020015b606081526020019060019003908162002e1a5790505b509a50826001600160401b0381111562002e4e5762002e4e62003f95565b60405190808252806020026020018201604052801562002e78578160200160208202803683370190505b509950826001600160401b0381111562002e965762002e9662003f95565b60405190808252806020026020018201604052801562002ecb57816020015b606081526020019060019003908162002eb55790505b509850826001600160401b0381111562002ee95762002ee962003f95565b60405190808252806020026020018201604052801562002f1e57816020015b606081526020019060019003908162002f085790505b509750826001600160401b0381111562002f3c5762002f3c62003f95565b60405190808252806020026020018201604052801562002f66578160200160208202803683370190505b509650826001600160401b0381111562002f845762002f8462003f95565b60405190808252806020026020018201604052801562002fb957816020015b606081526020019060019003908162002fa35790505b509550826001600160401b0381111562002fd75762002fd762003f95565b6040519080825280602002602001820160405280156200300c57816020015b606081526020019060019003908162002ff65790505b509450826001600160401b038111156200302a576200302a62003f95565b60405190808252806020026020018201604052801562003054578160200160208202803683370190505b509350600090506000915060005b600554811015620035995760076000828152602001908152602001600020549250828e83815181106200309957620030996200446a565b60200260200101818152505060066000848152602001908152602001600020600501548d8381518110620030d157620030d16200446a565b60200260200101818152505060066000848152602001908152602001600020600601805462003100906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200312e906200423b565b80156200317f5780601f1062003153576101008083540402835291602001916200317f565b820191906000526020600020905b8154815290600101906020018083116200316157829003601f168201915b50505050508c83815181106200319957620031996200446a565b602002602001018190525060066000848152602001908152602001600020600701548b8381518110620031d057620031d06200446a565b602002602001018181525050600660008481526020019081526020016000206008018054620031ff906200423b565b80601f01602080910402602001604051908101604052809291908181526020018280546200322d906200423b565b80156200327e5780601f1062003252576101008083540402835291602001916200327e565b820191906000526020600020905b8154815290600101906020018083116200326057829003601f168201915b50505050508a83815181106200329857620032986200446a565b6020026020010181905250600660008481526020019081526020016000206000016002018054620032c9906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620032f7906200423b565b8015620033485780601f106200331c5761010080835404028352916020019162003348565b820191906000526020600020905b8154815290600101906020018083116200332a57829003601f168201915b50505050508983815181106200336257620033626200446a565b602090810291909101810191909152600084815260069091526040902060030154885160ff90911690899084908110620033a057620033a06200446a565b60ff90921660209283029190910182015260008481526006909152604090208054620033cc906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620033fa906200423b565b80156200344b5780601f106200341f576101008083540402835291602001916200344b565b820191906000526020600020905b8154815290600101906020018083116200342d57829003601f168201915b50505050508783815181106200346557620034656200446a565b602002602001018190525060066000848152602001908152602001600020600001600101805462003496906200423b565b80601f0160208091040260200160405190810160405280929190818152602001828054620034c4906200423b565b8015620035155780601f10620034e95761010080835404028352916020019162003515565b820191906000526020600020905b815481529060010190602001808311620034f757829003601f168201915b50505050508683815181106200352f576200352f6200446a565b602002602001018190525060066000848152602001908152602001600020600001600401548583815181106200356957620035696200446a565b60209081029190910101528162003580816200421f565b925050808062003590906200421f565b91505062003062565b5050505090919293949596979899565b6008546001600160a01b03163314620035d65760405162461bcd60e51b8152600401620008ed90620040f4565b6000838383604051620035e990620036b5565b620035f79392919062004730565b604051809103906000f08015801562003614573d6000803e3d6000fd5b5090507fbb5f9980e27ec75b79e41ce422e643c6c0116fd9f599776a72f89032f70fe205818585856040516200364e949392919062003cb9565b60405180910390a150505050565b60006200366a82846200476d565b90505b92915050565b50805462003681906200423b565b6000825580601f1062003692575050565b601f016020900490600052602060002090810190620036b29190620036c3565b50565b611419806200478483390190565b5b80821115620036da5760008155600101620036c4565b5090565b80356001600160a01b0381168114620036f657600080fd5b919050565b6000602082840312156200370e57600080fd5b6200366a82620036de565b60008083601f8401126200372c57600080fd5b5081356001600160401b038111156200374457600080fd5b6020830191508360208260051b85010111156200376057600080fd5b9250929050565b600080600080600080600060a0888a0312156200378357600080fd5b873596506200379560208901620036de565b9550620037a560408901620036de565b945060608801356001600160401b0380821115620037c257600080fd5b620037d08b838c0162003719565b909650945060808a0135915080821115620037ea57600080fd5b50620037f98a828b0162003719565b989b979a50959850939692959293505050565b6000602082840312156200381f57600080fd5b5035919050565b6000806000606084860312156200383c57600080fd5b6200384784620036de565b92506200385760208501620036de565b9150604084013590509250925092565b60005b83811015620038845781810151838201526020016200386a565b50506000910152565b60008151808452620038a781602086016020860162003867565b601f01601f19169290920160200192915050565b838152606060208201526000620038d660608301856200388d565b9050826040830152949350505050565b60008060408385031215620038fa57600080fd5b6200390583620036de565b91506200391560208401620036de565b90509250929050565b60008083601f8401126200393157600080fd5b5081356001600160401b038111156200394957600080fd5b6020830191508360208285010111156200376057600080fd5b60008060008060008060008060c0898b0312156200397f57600080fd5b8835975060208901356001600160401b03808211156200399e57600080fd5b908a019060a0828d031215620039b357600080fd5b90975060408a0135965060608a01359080821115620039d157600080fd5b620039df8c838d016200391e565b909750955060808b0135945060a08b013591508082111562003a0057600080fd5b5062003a0f8b828c016200391e565b999c989b5096995094979396929594505050565b6000806040838503121562003a3757600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b8381101562003a785781518752958201959082019060010162003a5a565b509495945050505050565b6000815180845260208085019450848260051b860182860160005b8581101562003acc57838303895262003ab98383516200388d565b9885019892509084019060010162003a9e565b5090979650505050505050565b600081518084526020808501945080840160005b8381101562003a7857815160ff168752958201959082019060010162003aed565b600061014080835262003b248184018e62003a46565b9050828103602084015262003b3a818d62003a46565b9050828103604084015262003b50818c62003a83565b9050828103606084015262003b66818b62003a46565b9050828103608084015262003b7c818a62003a83565b905082810360a084015262003b92818962003a83565b905082810360c084015262003ba8818862003ad9565b905082810360e084015262003bbe818762003a83565b905082810361010084015262003bd5818662003a83565b905082810361012084015262003bec818562003a46565b9d9c50505050505050505050505050565b60a081526000865160a08084015262003c1b6101408401826200388d565b90506020880151609f19808584030160c086015262003c3b83836200388d565b925060408a01519150808584030160e08601525062003c5b82826200388d565b91505060ff6060890151166101008401526080880151610120840152866020840152828103604084015262003c9181876200388d565b9050846060840152828103608084015262003cad81856200388d565b98975050505050505050565b6001600160a01b038516815260806020820181905260009062003cdf908301866200388d565b828103604084015262003cf381866200388d565b91505060ff8316606083015295945050505050565b60a08152600062003d1d60a08301886200388d565b828103602084015262003d3181886200388d565b9050828103604084015262003d4781876200388d565b60ff9590951660608401525050608001529392505050565b600080600080600080600080600060c08a8c03121562003d7e57600080fd5b8935985062003d9060208b01620036de565b975062003da060408b01620036de565b965060608a01356001600160401b038082111562003dbd57600080fd5b62003dcb8d838e0162003719565b909850965060808c013591508082111562003de557600080fd5b62003df38d838e0162003719565b909650945060a08c013591508082111562003e0d57600080fd5b5062003e1c8c828d016200391e565b915080935050809150509295985092959850929598565b60008060008060006060868803121562003e4c57600080fd5b62003e5786620036de565b945060208601356001600160401b038082111562003e7457600080fd5b62003e8289838a016200391e565b9096509450604088013591508082111562003e9c57600080fd5b5062003eab888289016200391e565b969995985093965092949392505050565b84815260806020820152600062003ed760808301866200388d565b846040840152828103606084015262003ef181856200388d565b979650505050505050565b6000806000806040858703121562003f1357600080fd5b84356001600160401b038082111562003f2b57600080fd5b62003f398883890162003719565b9096509450602087013591508082111562003f5357600080fd5b5062003f628782880162003719565b95989497509550505050565b60408152600062003f8360408301856200388d565b905060ff831660208301529392505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562003fd65762003fd662003f95565b604052919050565b60006001600160401b0382111562003ffa5762003ffa62003f95565b50601f01601f191660200190565b600082601f8301126200401a57600080fd5b8135620040316200402b8262003fde565b62003fab565b8181528460208386010111156200404757600080fd5b816020850160208301376000918101602001919091529392505050565b60ff81168114620036b257600080fd5b6000806000606084860312156200408a57600080fd5b83356001600160401b0380821115620040a257600080fd5b620040b08783880162004008565b94506020860135915080821115620040c757600080fd5b50620040d68682870162004008565b9250506040840135620040e98162004064565b809150509250925092565b6020808252600990820152682737ba1037bbb732b960b91b604082015260600190565b6020808252600990820152683737ba1030b236b4b760b91b604082015260600190565b81835260006001600160fb1b038311156200415457600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906200419490830184866200413a565b95945050505050565b6001600160a01b0386168152606060208201819052600090620041c490830186886200413a565b828103604084015262003cad8185876200413a565b634e487b7160e01b600052601160045260246000fd5b818103818111156200366d576200366d620041d9565b600081620042175762004217620041d9565b506000190190565b600060018201620042345762004234620041d9565b5060010190565b600181811c908216806200425057607f821691505b6020821081036200427157634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000cd357600081815260208120601f850160051c81016020861015620042a05750805b601f850160051c820191505b8181101562000f0d57828155600101620042ac565b6001600160401b03831115620042db57620042db62003f95565b620042f383620042ec83546200423b565b8362004277565b6000601f8411600181146200432a5760008515620043115750838201355b600019600387901b1c1916600186901b1783556200091c565b600083815260209020601f19861690835b828110156200435d57868501358255602094850194600190920191016200433b565b50868210156200437b5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000808335601e19843603018112620043a557600080fd5b8301803591506001600160401b03821115620043c057600080fd5b6020019150368190038213156200376057600080fd5b600060208284031215620043e957600080fd5b8135620043f68162004064565b9392505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b86815260806020820152600062004442608083018789620043fd565b85604084015282810360608401526200445d818587620043fd565b9998505050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126200449857600080fd5b83016020810192503590506001600160401b03811115620044b857600080fd5b8036038213156200376057600080fd5b60a081526000620044da898a62004480565b60a080850152620044f161014085018284620043fd565b9150506200450360208b018b62004480565b609f19808685030160c08701526200451d848385620043fd565b93506200452e60408e018e62004480565b93509150808685030160e0870152506200454a838383620043fd565b9250505060608a01356200455e8162004064565b60ff1661010084015260808a01356101208401526020830189905282810360408401526200458e81888a620043fd565b90508560608401528281036080840152620045ab818587620043fd565b9a9950505050505050505050565b600060208284031215620045cc57600080fd5b81516001600160401b03811115620045e357600080fd5b8201601f81018413620045f557600080fd5b8051620046066200402b8262003fde565b8181528560208385010111156200461c57600080fd5b6200419482602083016020860162003867565b6000602082840312156200464257600080fd5b8151620043f68162004064565b6001600160a01b03861681526060602082018190526000906200467690830186886200413a565b828103604084015262003cad818587620043fd565b6001600160a01b0388168152608060208201819052600090620046b2908301888a6200413a565b8281036040840152620046c78187896200413a565b90508281036060840152620045ab818587620043fd565b604081526000620046f4604083018688620043fd565b828103602084015262003ef1818587620043fd565b6001600160a01b0386168152606060208201819052600090620046769083018688620043fd565b6060815260006200474560608301866200388d565b82810360208401526200475981866200388d565b91505060ff83166040830152949350505050565b808201808211156200366d576200366d620041d956fe60806040523480156200001157600080fd5b5060405162001419380380620014198339810160408190526200003491620001d0565b82826003620000448382620002e4565b506004620000538282620002e4565b505050620000706200006a620000b560201b60201c565b620000b9565b60066200007e8482620002e4565b5060076200008d8382620002e4565b506005805460ff909216600160a01b0260ff60a01b1990921691909117905550620003b09050565b3390565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013357600080fd5b81516001600160401b03808211156200015057620001506200010b565b604051601f8301601f19908116603f011681019082821181831017156200017b576200017b6200010b565b816040528381526020925086838588010111156200019857600080fd5b600091505b83821015620001bc57858201830151818301840152908201906200019d565b600093810190920192909252949350505050565b600080600060608486031215620001e657600080fd5b83516001600160401b0380821115620001fe57600080fd5b6200020c8783880162000121565b945060208601519150808211156200022357600080fd5b50620002328682870162000121565b925050604084015160ff811681146200024a57600080fd5b809150509250925092565b600181811c908216806200026a57607f821691505b6020821081036200028b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002df57600081815260208120601f850160051c81016020861015620002ba5750805b601f850160051c820191505b81811015620002db57828155600101620002c6565b5050505b505050565b81516001600160401b038111156200030057620003006200010b565b620003188162000311845462000255565b8462000291565b602080601f831160018114620003505760008415620003375750858301515b600019600386901b1c1916600185901b178555620002db565b600085815260208120601f198616915b82811015620003815788860151825594840194600190910190840162000360565b5085821015620003a05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61105980620003c06000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063715018a6116100ad578063a457c2d711610071578063a457c2d71461027e578063a9059cbb14610291578063dd62ed3e146102a4578063f2fde38b146102b7578063f4c84d19146102ca57600080fd5b8063715018a61461022d57806379cc6790146102355780638da5cb5b1461024857806395d89b41146102635780639dc29fac1461026b57600080fd5b806339509351116100f457806339509351146101b657806340c10f19146101c957806342966c68146101de5780634fb2e45d146101f157806370a082311461020457600080fd5b806306fdde0314610131578063095ea7b31461014f57806318160ddd1461017257806323b872dd14610184578063313ce56714610197575b600080fd5b6101396102dd565b6040516101469190610c75565b60405180910390f35b61016261015d366004610cdf565b61036f565b6040519015158152602001610146565b6002545b604051908152602001610146565b610162610192366004610d09565b610389565b600554600160a01b900460ff1660405160ff9091168152602001610146565b6101626101c4366004610cdf565b6103ad565b6101dc6101d7366004610cdf565b6103cf565b005b6101dc6101ec366004610d45565b61042c565b6101dc6101ff366004610d5e565b610439565b610176610212366004610d5e565b6001600160a01b031660009081526020819052604090205490565b6101dc61044a565b6101dc610243366004610cdf565b61045e565b6005546040516001600160a01b039091168152602001610146565b610139610477565b6101dc610279366004610cdf565b610486565b61016261028c366004610cdf565b6104d9565b61016261029f366004610cdf565b610554565b6101766102b2366004610d80565b610562565b6101dc6102c5366004610d5e565b61058d565b6101dc6102d8366004610e56565b610603565b6060600680546102ec90610eba565b80601f016020809104026020016040519081016040528092919081815260200182805461031890610eba565b80156103655780601f1061033a57610100808354040283529160200191610365565b820191906000526020600020905b81548152906001019060200180831161034857829003601f168201915b5050505050905090565b60003361037d818585610624565b60019150505b92915050565b600033610397858285610748565b6103a28585856107c2565b506001949350505050565b60003361037d8185856103c08383610562565b6103ca9190610ef4565b610624565b6103d7610971565b806000811161041d5760405162461bcd60e51b815260206004820152600d60248201526c15985b1d59481a5cc81b9d5b1b609a1b60448201526064015b60405180910390fd5b61042783836109cb565b505050565b6104363382610a96565b50565b610441610971565b6104368161058d565b610452610971565b61045c6000610bd4565b565b610469823383610748565b6104738282610a96565b5050565b6060600780546102ec90610eba565b61048e610971565b80600081116104cf5760405162461bcd60e51b815260206004820152600d60248201526c15985b1d59481a5cc81b9d5b1b609a1b6044820152606401610414565b6104278383610a96565b600033816104e78286610562565b9050838110156105475760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610414565b6103a28286868403610624565b60003361037d8185856107c2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610595610971565b6001600160a01b0381166105fa5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610414565b61043681610bd4565b61060b610971565b60066106178382610f63565b5060076104278282610f63565b6001600160a01b0383166106865760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610414565b6001600160a01b0382166106e75760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610414565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006107548484610562565b905060001981146107bc57818110156107af5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610414565b6107bc8484848403610624565b50505050565b6001600160a01b0383166108265760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610414565b6001600160a01b0382166108885760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610414565b610893838383610c26565b6001600160a01b0383166000908152602081905260409020548181101561090b5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610414565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36107bc565b6005546001600160a01b0316331461045c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610414565b6001600160a01b038216610a215760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610414565b610a2d60008383610c26565b8060026000828254610a3f9190610ef4565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610af65760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610414565b610b0282600083610c26565b6001600160a01b03821660009081526020819052604090205481811015610b765760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610414565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b306001600160a01b038316036104275760405162461bcd60e51b81526020600482015260146024820152731d1bc81859191c995cdcc81a5b98dbdc9c9958dd60621b6044820152606401610414565b600060208083528351808285015260005b81811015610ca257858101830151858201604001528201610c86565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b0381168114610cda57600080fd5b919050565b60008060408385031215610cf257600080fd5b610cfb83610cc3565b946020939093013593505050565b600080600060608486031215610d1e57600080fd5b610d2784610cc3565b9250610d3560208501610cc3565b9150604084013590509250925092565b600060208284031215610d5757600080fd5b5035919050565b600060208284031215610d7057600080fd5b610d7982610cc3565b9392505050565b60008060408385031215610d9357600080fd5b610d9c83610cc3565b9150610daa60208401610cc3565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112610dda57600080fd5b813567ffffffffffffffff80821115610df557610df5610db3565b604051601f8301601f19908116603f01168101908282118183101715610e1d57610e1d610db3565b81604052838152866020858801011115610e3657600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215610e6957600080fd5b823567ffffffffffffffff80821115610e8157600080fd5b610e8d86838701610dc9565b93506020850135915080821115610ea357600080fd5b50610eb085828601610dc9565b9150509250929050565b600181811c90821680610ece57607f821691505b602082108103610eee57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561038357634e487b7160e01b600052601160045260246000fd5b601f82111561042757600081815260208120601f850160051c81016020861015610f3c5750805b601f850160051c820191505b81811015610f5b57828155600101610f48565b505050505050565b815167ffffffffffffffff811115610f7d57610f7d610db3565b610f9181610f8b8454610eba565b84610f15565b602080601f831160018114610fc65760008415610fae5750858301515b600019600386901b1c1916600185901b178555610f5b565b600085815260208120601f198616915b82811015610ff557888601518255948401946001909101908401610fd6565b50858210156110135787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220d6e77c582a20ca54c3c7c855197faee6ae98dd5cadc02f78be55abb5bcbebc3a64736f6c63430008120033a264697066735822122027abfc8f211406077d0cd812d4bb9d4dcd16479b5ac7cce5833f0e94662fc4cb64736f6c63430008120033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.