ETH Price: $3,393.52 (+1.76%)

Token

FPX FLY x Cheers UP Emoji (FPXCUPEMOJI)
 

Overview

Max Total Supply

5,149 FPXCUPEMOJI

Holders

2,840

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
0xdf8375741e8d74e9c110a1d9572b8b4d5d92b579
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
FPXEmoji

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : FPXEmoji.sol
// SPDX-License-Identifier: MIT
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../library/sealable/v1/Sealable.sol";
import "../library/random/v1/OnChainRandom.sol";
import "./IFPXEmoji.sol";
import "../library/opensea-operatorfilter/v1/FlexibleOperatorFilterer.sol";

/*
 ____                   _           _         
|  _ \                 | |         | |        
| |_) | __ _ ___  ___  | |     __ _| |__  ___ 
|  _ < / _` / __|/ _ \ | |    / _` | '_ \/ __|
| |_) | (_| \__ \  __/ | |___| (_| | |_) \__ \
|____/ \__,_|___/\___| |______\__,_|_.__/|___/
                                              
*/

pragma solidity ^0.8.17;

/**
 * @title FPXEmoji
 * @author BaseLabs
 */
contract FPXEmoji is
    ERC1155,
    IFPXEmoji,
    Pausable,
    OnChainRandom,
    ReentrancyGuard,
    Ownable,
    Sealable,
    FlexibleOperatorFilterer
{
    string public constant name = "FPX FLY x Cheers UP Emoji";
    string public constant symbol = "FPXCUPEMOJI";
    mapping(uint256 => Formula) private _formulas;
    mapping(uint256 => Uint256Pair[]) private _airdropPlans;
    mapping(uint256 => string) public tokenURIs;

    constructor() ERC1155("") {}

    /***********************************|
    |               Core                |
    |__________________________________*/

    /**
     * @notice airdrop method handles the airdrop process for a specified airdrop plan. The
     * airdrop plan specifies the number of each type of token to be airdropped.
     * The function receives an array of addresses and an array of numbers, where
     * each number in the array represents the number of tokens to be airdropped to
     * the corresponding address in the addresses array.
     * @param airdropId_ The ID of the airdrop plan to be used for the airdrop.
     * @param addresses_ The array of addresses to receive the airdrop.
     * @param nums_ The array of numbers, where each number represents the number
     *              of tokens to be airdropped to the corresponding address.
     */
    function airdrop(
        uint256 airdropId_,
        address[] calldata addresses_,
        uint256[] calldata nums_
    ) external onlyOwner onlyNotSealed nonReentrant {
        Uint256Pair[] memory airdropPlan = _airdropPlans[airdropId_];
        uint256 planSize = airdropPlan.length;
        if (planSize == 0) revert ErrInvalidAirdropPlan();
        uint256 totalSize = 0;
        for (uint256 i = 0; i < planSize; ++i) {
            totalSize += airdropPlan[i].value;
        }
        for (uint256 i = 0; i < addresses_.length; ++i) {
            address account = addresses_[i];
            uint256 num = nums_[i];
            for (uint256 j = 0; j < num; ++j) {
                uint256 entropy = _unsafeRandom() % totalSize;
                uint256 step = 0;
                bool minted = false;
                for (uint256 k = 0; k < planSize; ++k) {
                    step += airdropPlan[k].value;
                    if (entropy < step) {
                        airdropPlan[k].value--;
                        totalSize--;
                        _mint(account, airdropPlan[k].key, 1, "");
                        minted = true;
                        break;
                    }
                }
                if (!minted) revert ErrUnreachableCode();
            }
        }
        _overwriteAirdropPlan(airdropId_, airdropPlan);
    }

    /**
     * @notice The merge function merges the given formula and burns its input tokens.
     * It then generates a new token using the output of the formula and mints it
     * to the caller of the function.
     * @param formulaId_ The ID of the formula to be used for the merge.
     * @dev The onlyEOA and nonReentrant modifiers are used to restrict the
     * caller to external accounts and to prevent reentrancy, respectively.
     */
    function merge(uint256 formulaId_) external onlyEOA nonReentrant {
        (Formula memory formula, bool valid) = getFormula(formulaId_);
        if (!valid) revert ErrFormulaIsInvalid();
        for (uint256 i = 0; i < formula.input.length; ++i) {
            _burn(msg.sender, formula.input[i].key, formula.input[i].value);
        }
        uint256 tokenId = _dice(formula.output);
        _mint(msg.sender, tokenId, 1, "");
        emit Rerolled(msg.sender, formulaId_, tokenId);
    }

    /**
     * @notice Burn a batch of tokens from an account.
     * @param account_ The address of the account from which the tokens will be burned.
     * @param ids_ The IDs of the tokens to burn.
     * @param values_ The numbers of the tokens to burn.
     */
    function burnBatch(
        address account_,
        uint256[] memory ids_,
        uint256[] memory values_
    ) external {
        if (account_ != msg.sender && !isApprovedForAll(account_, msg.sender))
            revert ErrNotPermitted();
        _burnBatch(account_, ids_, values_);
    }

    /**
     * @notice _dice is used to select a key from a list of key-value pairs with
     * probabilities proportional to their values.
     * @param pairs_ The list of key-value pairs.
     * @return The selected key.
     */
    function _dice(Uint256Pair[] memory pairs_) internal returns (uint256) {
        unchecked {
            if (pairs_.length == 1) {
                return pairs_[0].key;
            }
            uint256 totalSize = 0;
            for (uint256 i = 0; i < pairs_.length; ++i) {
                totalSize += pairs_[i].value;
            }
            uint256 entropy = _unsafeRandom() % totalSize;
            uint256 step = 0;
            for (uint256 i = 0; i < pairs_.length; ++i) {
                step += pairs_[i].value;
                if (entropy < step) {
                    return pairs_[i].key;
                }
            }
            revert ErrUnreachableCode();
        }
    }

    /***********************************|
    |              Admin                |
    |__________________________________*/

    /**
     * @notice mint is used to mints multiple tokens at once
     * @param addresses_ the addresses to which the tokens will be minted
     * @param tokenIds_ the token IDs of the tokens to be minted
     * @param nums_ the number of tokens to be minted
     */
    function mint(
        address[] calldata addresses_,
        uint256[] calldata tokenIds_,
        uint256[] calldata nums_
    ) external onlyOwner onlyNotSealed nonReentrant {
        if (
            addresses_.length == 0 ||
            addresses_.length != tokenIds_.length ||
            addresses_.length != nums_.length
        ) revert ErrInvalidArguments();
        for (uint256 i = 0; i < addresses_.length; ++i) {
            _mint(addresses_[i], tokenIds_[i], nums_[i], "");
        }
    }

    /**
     * @notice setTokenURI is used to set the URI for a given token ID.
     * @param tokenIds_ The IDs of the tokens to set the URI for.
     * @param tokenURIs_ The URI values to set for the token IDs.
     */
    function setTokenURI(
        uint256[] calldata tokenIds_,
        string[] calldata tokenURIs_
    ) external onlyOwner onlyNotSealed {
        if ((tokenIds_.length == 0) || (tokenIds_.length != tokenURIs_.length))
            revert ErrInvalidArguments();
        for (uint256 i = 0; i < tokenIds_.length; ++i) {
            uint256 tokenId = tokenIds_[i];
            string memory tokenURI = tokenURIs_[i];
            tokenURIs[tokenId] = tokenURI;
            emit URI(tokenURI, tokenId);
        }
    }

    /**
     * @notice setFormula is used to sets the formula with the given ID.
     * @param formulaId_ ID of the formula to set.
     * @param formula_ Formula to set.
     * @param overwrite_ Flag to indicate if the formula should be overwritten if it already exists.
     */
    function setFormula(
        uint256 formulaId_,
        Formula calldata formula_,
        bool overwrite_
    ) external onlyOwner onlyNotSealed {
        if (!overwrite_) {
            if (_formulas[formulaId_].input.length != 0)
                revert ErrFormulaAlreadyExists();
        }
        if (formula_.output.length == 0 || formula_.input.length == 0)
            revert ErrInvalidArguments();
        _formulas[formulaId_] = formula_;
        emit FormulaUpdated(formulaId_);
    }

    /**
     * @notice setAirdropPlan is used to set an airdrop plan for the given airdrop ID.
     * If `overwrite` is set to true, the existing plan for the given ID will be overwritten.
     * If the given plan is empty or a plan already exists for the given ID and `overwrite` is not set to true, the function will revert.
     *
     * @param airdropId_ The ID of the airdrop for which to set the plan.
     * @param plan_ The airdrop plan to set.
     * @param overwrite_ Whether to overwrite an existing plan for the given airdrop ID.
     */
    function setAirdropPlan(
        uint256 airdropId_,
        Uint256Pair[] calldata plan_,
        bool overwrite_
    ) external onlyOwner onlyNotSealed {
        if (overwrite_) {
            _overwriteAirdropPlan(airdropId_, plan_);
            return;
        }
        if (_airdropPlans[airdropId_].length != 0)
            revert ErrAirdropPlanAlreadyExists();
        if (plan_.length == 0) revert ErrInvalidAirdropPlan();
        Uint256Pair[] storage airdropPlan = _airdropPlans[airdropId_];
        for (uint256 i = 0; i < plan_.length; ++i) {
            airdropPlan.push(plan_[i]);
        }
        emit AirdropPlanUpdated(airdropId_);
    }

    /**
     * @notice _overwriteAirdropPlan is used to overwrite the existing airdrop plan.
     * @param airdropId_ The ID of the airdrop.
     * @param plan_ The new airdrop plan to be set.
     */
    function _overwriteAirdropPlan(
        uint256 airdropId_,
        Uint256Pair[] memory plan_
    ) internal {
        if (_airdropPlans[airdropId_].length != plan_.length)
            revert ErrInvalidArguments();
        for (uint256 i = 0; i < plan_.length; ++i) {
            _airdropPlans[airdropId_][i] = plan_[i];
        }
        emit AirdropPlanUpdated(airdropId_);
    }

    /**
     * @notice for the purpose of protecting user assets, under extreme conditions,
     * the circulation of all tokens in the contract needs to be frozen.
     * This process is under the supervision of the community.
     */
    function emergencyPause() external onlyOwner onlyNotSealed {
        _pause();
    }

    /**
     * @notice unpause the contract
     */
    function unpause() external onlyOwner onlyNotSealed {
        _unpause();
    }

    /**
     * @notice sealContract is used to seal the contract.
     */
    function sealContract() external onlyOwner onlyNotSealed {
        contractSealed = true;
        emit ContractSealed();
    }

    /***********************************|
    |             Getters               |
    |__________________________________*/

    /**
     * @notice uri is used to get the URI corresponding to the tokenId
     * @param tokenId_ token id
     * @return metadata uri corresponding to the token
     */
    function uri(
        uint256 tokenId_
    ) public view virtual override(ERC1155, IFPXEmoji) returns (string memory) {
        return tokenURIs[tokenId_];
    }

    /**
     * @notice isFormulaValid is used to check if a formula is valid.
     * @param formula_ The formula to be checked.
     * @return This function returns true if the formula is valid, otherwise it returns false.
     */
    function isFormulaValid(
        Formula memory formula_
    ) public view returns (bool) {
        if (formula_.input.length == 0 || formula_.output.length == 0) {
            return false;
        }
        if (formula_.endTime > 0 && block.timestamp > formula_.endTime) {
            return false;
        }
        return formula_.startTime > 0 && block.timestamp > formula_.startTime;
    }

    /**
     * @notice getFormula is used to get a formula.
     * @param formulaId_ The ID of the formula.
     * @return formula_ the formula.
     * @return valid_ a bool indicating whether the formula is valid.
     */
    function getFormula(
        uint256 formulaId_
    ) public view returns (Formula memory formula_, bool valid_) {
        formula_ = _formulas[formulaId_];
        valid_ = isFormulaValid(formula_);
    }

    /**
     * @notice getAirdropPlan is used to get an airdrop plan.
     * @param airdropId_ The ID of the airdrop.
     * @return This function returns the airdrop plan.
     */
    function getAirdropPlan(
        uint256 airdropId_
    ) external view returns (Uint256Pair[] memory) {
        return _airdropPlans[airdropId_];
    }

    /**
     * @notice supportsInterface is used to check if an interface is supported by this contract.
     * @param interfaceId The interface ID to be checked.
     * @return This function returns true if the interface is supported, otherwise it returns false.
     */
    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual override(ERC1155, IERC165) returns (bool) {
        return
            ERC1155.supportsInterface(interfaceId) ||
            ERC165.supportsInterface(interfaceId);
    }

    /**
     * @notice _beforeTokenTransfer is used to perform actions before a token transfer.
     * @param operator The address of the operator calling this function.
     * @param from The address of the account sending the tokens.
     * @param to The address of the account receiving the tokens.
     * @param ids The IDs of the tokens being transferred.
     * @param amounts The amounts of the tokens being transferred.
     * @param data Additional data provided with the transfer.
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual override {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
        if (paused()) revert ErrContractPaused();
    }

    /**
     * @notice for security reasons, CA is not allowed to call sensitive methods.
     */
    modifier onlyEOA() {
        if (tx.origin != msg.sender) revert ErrOnlyEOA();
        _;
    }

    /***********************************|
    |     Operator Filter Registry      |
    |__________________________________*/

    /**
     * @notice setApprovalForAll is used to set an operator's approval for all token transfers.
     * @param operator The address of the operator to set approval for.
     * @param approved Whether the operator is approved or not.
     */
    function setApprovalForAll(
        address operator,
        bool approved
    ) public override(ERC1155, IERC1155) onlyAllowedOperatorApproval(operator) {
        super.setApprovalForAll(operator, approved);
    }

    /**
     * @notice safeTransferFrom is used to safely transfer tokens from one account to another.
     * @param from The address of the account sending the tokens.
     * @param to The address of the account receiving the tokens.
     * @param tokenId The ID of the token being transferred.
     * @param amount The amount of the token being transferred.
     * @param data Additional data provided with the transfer.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        uint256 amount,
        bytes memory data
    ) public override(ERC1155, IERC1155) onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId, amount, data);
    }

    /**
     * @notice safeBatchTransferFrom is used to safely transfer multiple tokens from one account to another.
     * @param from The address of the account sending the tokens.
     * @param to The address of the account receiving the tokens.
     * @param ids The IDs of the tokens being transferred.
     * @param amounts The amounts of the tokens being transferred.
     * @param data Additional data provided with the transfer.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override(ERC1155, IERC1155) onlyAllowedOperator(from) {
        super.safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @notice owner is used to get the owner address of this contract.
     * @return the address of the owner of this contract
     */
    function owner()
        public
        view
        virtual
        override(Ownable, FlexibleOperatorFilterer)
        returns (address)
    {
        return Ownable.owner();
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

    bool private _paused;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

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

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

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

File 5 of 18 : ERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.0;

import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 *
 * _Available since v3.1._
 */
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
    using Address for address;

    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

    // Mapping from account to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
    string private _uri;

    /**
     * @dev See {_setURI}.
     */
    constructor(string memory uri_) {
        _setURI(uri_);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC1155).interfaceId ||
            interfaceId == type(IERC1155MetadataURI).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256) public view virtual override returns (string memory) {
        return _uri;
    }

    /**
     * @dev See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        require(account != address(0), "ERC1155: address zero is not a valid owner");
        return _balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
        public
        view
        virtual
        override
        returns (uint256[] memory)
    {
        require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

    /**
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[account][operator];
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not token owner or approved"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender() || isApprovedForAll(from, _msgSender()),
            "ERC1155: caller is not token owner or approved"
        );
        _safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

        emit TransferSingle(operator, from, to, id, amount);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
        require(to != address(0), "ERC1155: transfer to the zero address");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
            _balances[id][to] += amount;
        }

        emit TransferBatch(operator, from, to, ids, amounts);

        _afterTokenTransfer(operator, from, to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
    }

    /**
     * @dev Sets a new URI for all token types, by relying on the token type ID
     * substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * By this mechanism, any occurrence of the `\{id\}` substring in either the
     * URI or any of the amounts in the JSON file at said URI will be replaced by
     * clients with the token type ID.
     *
     * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
     * interpreted by clients as
     * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
     * for token type ID 0x4cce0.
     *
     * See {uri}.
     *
     * Because these URIs cannot be meaningfully represented by the {URI} event,
     * this function emits no events.
     */
    function _setURI(string memory newuri) internal virtual {
        _uri = newuri;
    }

    /**
     * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        _balances[id][to] += amount;
        emit TransferSingle(operator, address(0), to, id, amount);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _mintBatch(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

        for (uint256 i = 0; i < ids.length; i++) {
            _balances[ids[i]][to] += amounts[i];
        }

        emit TransferBatch(operator, address(0), to, ids, amounts);

        _afterTokenTransfer(operator, address(0), to, ids, amounts, data);

        _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
    }

    /**
     * @dev Destroys `amount` tokens of token type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `amount` tokens of token type `id`.
     */
    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");

        address operator = _msgSender();
        uint256[] memory ids = _asSingletonArray(id);
        uint256[] memory amounts = _asSingletonArray(amount);

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }

        emit TransferSingle(operator, from, address(0), id, amount);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     */
    function _burnBatch(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        _beforeTokenTransfer(operator, from, address(0), ids, amounts, "");

        for (uint256 i = 0; i < ids.length; i++) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
        }

        emit TransferBatch(operator, from, address(0), ids, amounts);

        _afterTokenTransfer(operator, from, address(0), ids, amounts, "");
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits an {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC1155: setting approval status for self");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `ids` and `amounts` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    /**
     * @dev Hook that is called after any token transfer. This includes minting
     * and burning, as well as batched variants.
     *
     * The same hook is called on both single and batched variants. For single
     * transfers, the length of the `id` and `amount` arrays will be 1.
     *
     * Calling conditions (for each `id` and `amount` pair):
     *
     * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * of token type `id` will be  transferred to `to`.
     * - When `from` is zero, `amount` tokens of token type `id` will be minted
     * for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
     * will be burned.
     * - `from` and `to` are never both zero.
     * - `ids` and `amounts` have the same, non-zero length.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {}

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (to.isContract()) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
        uint256[] memory array = new uint256[](1);
        array[0] = element;

        return array;
    }
}

File 6 of 18 : IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.0;

import "../IERC1155.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

File 7 of 18 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 8 of 18 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 9 of 18 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

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

pragma solidity ^0.8.0;

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

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

File 11 of 18 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 12 of 18 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 13 of 18 : IFPXEmoji.sol
// SPDX-License-Identifier: MIT
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

/*
 ____                   _           _         
|  _ \                 | |         | |        
| |_) | __ _ ___  ___  | |     __ _| |__  ___ 
|  _ < / _` / __|/ _ \ | |    / _` | '_ \/ __|
| |_) | (_| \__ \  __/ | |___| (_| | |_) \__ \
|____/ \__,_|___/\___| |______\__,_|_.__/|___/
                                              
*/

pragma solidity ^0.8.7;

/**
 * @title IFPXEmoji
 * @author BaseLabs
 */
interface IFPXEmoji is IERC1155 {
    error ErrOnlyEOA();
    error ErrUnreachableCode();
    error ErrNotPermitted();
    error ErrContractPaused();
    error ErrFormulaAlreadyExists();
    error ErrInvalidArguments();
    error ErrFormulaIsInvalid();
    error ErrInvalidAirdropPlan();
    error ErrAirdropPlanAlreadyExists();

    event FormulaUpdated(uint256 formulaId);
    event AirdropPlanUpdated(uint256 airdropId);
    event Rerolled(
        address indexed account,
        uint256 indexed formulaId,
        uint256 indexed tokenId
    );

    struct Uint256Pair {
        uint256 key;
        uint256 value;
    }
    struct Formula {
        uint256 startTime;
        uint256 endTime;
        Uint256Pair[] input;
        Uint256Pair[] output;
    }
    struct Airdrop {
        Uint256Pair[] data;
    }

    /**
     * @notice airdrop method handles the airdrop process for a specified airdrop plan. The
     * airdrop plan specifies the number of each type of token to be airdropped.
     * The function receives an array of addresses and an array of numbers, where
     * each number in the array represents the number of tokens to be airdropped to
     * the corresponding address in the addresses array.
     * @param airdropId_ The ID of the airdrop plan to be used for the airdrop.
     * @param addresses_ The array of addresses to receive the airdrop.
     * @param nums_ The array of numbers, where each number represents the number
     *              of tokens to be airdropped to the corresponding address.
     */
    function airdrop(
        uint256 airdropId_,
        address[] calldata addresses_,
        uint256[] calldata nums_
    ) external;

    /**
     * @notice The merge function merges the given formula and burns its input tokens.
     * It then generates a new token using the output of the formula and mints it
     * to the caller of the function.
     * @param formulaId_ The ID of the formula to be used for the merge.
     * @dev The onlyEOA and nonReentrant modifiers are used to restrict the
     * caller to external accounts and to prevent reentrancy, respectively.
     */
    function merge(uint256 formulaId_) external;

    /**
     * @notice Burn a batch of tokens from an account.
     * @param account_ The address of the account from which the tokens will be burned.
     * @param ids_ The IDs of the tokens to burn.
     * @param values_ The numbers of the tokens to burn.
     */
    function burnBatch(
        address account_,
        uint256[] memory ids_,
        uint256[] memory values_
    ) external;

    /**
     * @notice mint is used to mints multiple tokens at once
     * @param addresses_ the addresses to which the tokens will be minted
     * @param tokenIds_ the token IDs of the tokens to be minted
     * @param nums_ the number of tokens to be minted
     */
    function mint(
        address[] calldata addresses_,
        uint256[] calldata tokenIds_,
        uint256[] calldata nums_
    ) external;

    /**
     * @notice setTokenURI is used to set the URI for a given token ID.
     * @param tokenIds_ The IDs of the tokens to set the URI for.
     * @param tokenURIs_ The URI values to set for the token IDs.
     */
    function setTokenURI(
        uint256[] calldata tokenIds_,
        string[] calldata tokenURIs_
    ) external;

    /**
     * @notice setFormula is used to sets the formula with the given ID.
     * @param formulaId_ ID of the formula to set.
     * @param formula_ Formula to set.
     * @param overwrite_ Flag to indicate if the formula should be overwritten if it already exists.
     */
    function setFormula(
        uint256 formulaId_,
        Formula calldata formula_,
        bool overwrite_
    ) external;

    /**
     * @notice setAirdropPlan is used to set an airdrop plan for the given airdrop ID.
     * If `overwrite` is set to true, the existing plan for the given ID will be overwritten.
     * If the given plan is empty or a plan already exists for the given ID and `overwrite` is not set to true, the function will revert.
     *
     * @param airdropId_ The ID of the airdrop for which to set the plan.
     * @param plan_ The airdrop plan to set.
     * @param overwrite_ Whether to overwrite an existing plan for the given airdrop ID.
     */
    function setAirdropPlan(
        uint256 airdropId_,
        Uint256Pair[] calldata plan_,
        bool overwrite_
    ) external;

    /**
     * @notice for the purpose of protecting user assets, under extreme conditions,
     * the circulation of all tokens in the contract needs to be frozen.
     * This process is under the supervision of the community.
     */
    function emergencyPause() external;

    /**
     * @notice unpause the contract
     */
    function unpause() external;

    /**
     * @notice sealContract is used to seal the contract.
     */
    function sealContract() external;

    /**
     * @notice isFormulaValid is used to check if a formula is valid.
     * @param formula_ The formula to be checked.
     * @return This function returns true if the formula is valid, otherwise it returns false.
     */
    function isFormulaValid(
        Formula memory formula_
    ) external view returns (bool);

    /**
     * @notice getFormula is used to get a formula.
     * @param formulaId_ The ID of the formula.
     * @return formula_ the formula.
     * @return valid_ a bool indicating whether the formula is valid.
     */
    function getFormula(
        uint256 formulaId_
    ) external view returns (Formula memory formula_, bool valid_);

    /**
     * @notice getAirdropPlan is used to get an airdrop plan.
     * @param airdropId_ The ID of the airdrop.
     * @return This function returns the airdrop plan.
     */
    function getAirdropPlan(
        uint256 airdropId_
    ) external view returns (Uint256Pair[] memory);

    /**
     * @notice uri is used to get the URI corresponding to the tokenId
     * @param tokenId_ token id
     * @return metadata uri corresponding to the token
     */
    function uri(uint256 tokenId_) external view returns (string memory);
}

File 14 of 18 : FlexibleOperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

/**
 * @title FlexibleOperatorFilterer
 * @author BaseLabs
 */
abstract contract FlexibleOperatorFilterer is OperatorFilterer {
    error ErrOnlyOwner();

    address constant DEFAULT_SUBSCRIPTION =
        address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);
    bool public isOperatorFilterRegistryEnabled;
    mapping(address => bool) public operatorFilterWhitelist;

    constructor() OperatorFilterer(DEFAULT_SUBSCRIPTION, true) {}

    modifier onlyAllowedOperator(address from) override {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (
            isOperatorFilterRegistryEnabled &&
            !operatorFilterWhitelist[msg.sender] &&
            address(OPERATOR_FILTER_REGISTRY).code.length > 0
        ) {
            // Allow spending tokens from addresses with balance
            // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
            // from an EOA.
            if (from == msg.sender) {
                _;
                return;
            }
            if (
                !OPERATOR_FILTER_REGISTRY.isOperatorAllowed(
                    address(this),
                    msg.sender
                )
            ) {
                revert OperatorNotAllowed(msg.sender);
            }
        }
        _;
    }

    modifier onlyAllowedOperatorApproval(address operator) override {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (
            isOperatorFilterRegistryEnabled &&
            !operatorFilterWhitelist[operator] &&
            address(OPERATOR_FILTER_REGISTRY).code.length > 0
        ) {
            if (
                !OPERATOR_FILTER_REGISTRY.isOperatorAllowed(
                    address(this),
                    operator
                )
            ) {
                revert OperatorNotAllowed(operator);
            }
        }
        _;
    }

    /**
     * @notice setOperatorFilterRegistryWhitelist is used to set the whitelist of operator filter registry.
     * @param state_ If state_ is true, OperatorFilterRegistry for this address will be disabled.
     */
    function setOperatorFilterRegistryWhitelist(
        address address_,
        bool state_
    ) external {
        if (msg.sender != owner()) {
            revert ErrOnlyOwner();
        }
        operatorFilterWhitelist[address_] = state_;
    }

    /**
     * @notice setOperatorFilterRegistryState is used to update the state of isOperatorFilterRegistryEnabled flag.
     * @param enabled_ If enabled_ is true, OperatorFilterRegistry will be enabled.
     */
    function setOperatorFilterRegistryState(bool enabled_) external {
        if (msg.sender != owner()) {
            revert ErrOnlyOwner();
        }
        isOperatorFilterRegistryEnabled = enabled_;
    }

    /**
     * @dev assume the contract has an owner, but leave specific Ownable implementation up to inheriting contract
     */
    function owner() public view virtual returns (address);
}

File 15 of 18 : IOperatorFilterRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

interface IOperatorFilterRegistry {
    function isOperatorAllowed(address registrant, address operator) external view returns (bool);
    function register(address registrant) external;
    function registerAndSubscribe(address registrant, address subscription) external;
    function registerAndCopyEntries(address registrant, address registrantToCopy) external;
    function unregister(address addr) external;
    function updateOperator(address registrant, address operator, bool filtered) external;
    function updateOperators(address registrant, address[] calldata operators, bool filtered) external;
    function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;
    function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;
    function subscribe(address registrant, address registrantToSubscribe) external;
    function unsubscribe(address registrant, bool copyExistingEntries) external;
    function subscriptionOf(address addr) external returns (address registrant);
    function subscribers(address registrant) external returns (address[] memory);
    function subscriberAt(address registrant, uint256 index) external returns (address);
    function copyEntriesOf(address registrant, address registrantToCopy) external;
    function isOperatorFiltered(address registrant, address operator) external returns (bool);
    function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);
    function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);
    function filteredOperators(address addr) external returns (address[] memory);
    function filteredCodeHashes(address addr) external returns (bytes32[] memory);
    function filteredOperatorAt(address registrant, uint256 index) external returns (address);
    function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);
    function isRegistered(address addr) external returns (bool);
    function codeHashOf(address addr) external returns (bytes32);
}

File 16 of 18 : OperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

/**
 * @title  OperatorFilterer
 * @notice Abstract contract whose constructor automatically registers and optionally subscribes to or copies another
 *         registrant's entries in the OperatorFilterRegistry.
 * @dev    This smart contract is meant to be inherited by token contracts so they can use the following:
 *         - `onlyAllowedOperator` modifier for `transferFrom` and `safeTransferFrom` methods.
 *         - `onlyAllowedOperatorApproval` modifier for `approve` and `setApprovalForAll` methods.
 */
abstract contract OperatorFilterer {
    error OperatorNotAllowed(address operator);

    IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY =
        IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);

    constructor(address subscriptionOrRegistrantToCopy, bool subscribe) {
        // If an inheriting token contract is deployed to a network without the registry deployed, the modifier
        // will not revert, but the contract will need to be registered with the registry once it is deployed in
        // order for the modifier to filter addresses.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            if (subscribe) {
                OPERATOR_FILTER_REGISTRY.registerAndSubscribe(address(this), subscriptionOrRegistrantToCopy);
            } else {
                if (subscriptionOrRegistrantToCopy != address(0)) {
                    OPERATOR_FILTER_REGISTRY.registerAndCopyEntries(address(this), subscriptionOrRegistrantToCopy);
                } else {
                    OPERATOR_FILTER_REGISTRY.register(address(this));
                }
            }
        }
    }

    modifier onlyAllowedOperator(address from) virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            // Allow spending tokens from addresses with balance
            // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
            // from an EOA.
            if (from == msg.sender) {
                _;
                return;
            }
            if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), msg.sender)) {
                revert OperatorNotAllowed(msg.sender);
            }
        }
        _;
    }

    modifier onlyAllowedOperatorApproval(address operator) virtual {
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(OPERATOR_FILTER_REGISTRY).code.length > 0) {
            if (!OPERATOR_FILTER_REGISTRY.isOperatorAllowed(address(this), operator)) {
                revert OperatorNotAllowed(operator);
            }
        }
        _;
    }
}

File 17 of 18 : OnChainRandom.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/**
 * @title OnChainRandom
 * @author BaseLabs
 */
contract OnChainRandom {
    uint256 private _seed;

    /**
     * @notice _unsafeRandom is used to generate a random number by on-chain randomness.
     * Please note that on-chain random is potentially manipulated by miners,
     * so VRF is recommended for most security-sensitive scenarios.
     * @return randomly generated number.
     */
    function _unsafeRandom() internal returns (uint256) {
        unchecked {
            _seed++;
            return
                uint256(
                    keccak256(
                        abi.encodePacked(
                            blockhash(block.number - 1),
                            block.difficulty,
                            block.timestamp,
                            block.coinbase,
                            _seed,
                            tx.origin
                        )
                    )
                );
        }
    }
}

File 18 of 18 : Sealable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

/// @notice define a set of error types

/**
 * @title Sealable
 * @author BaseLabs
 */
contract Sealable {
    error ErrContractSealed();
    event ContractSealed();

    /// @notice whether the contract is sealed
    bool public contractSealed;

    /**
     * @notice when the project is stable enough, the issuer will call sealContract
     * to give up the permission to call emergencyPause and unpause.
     */
    function _sealContract() internal {
        contractSealed = true;
        emit ContractSealed();
    }

    /**
     * @notice function call is only allowed when the contract has not been sealed
     */
    modifier onlyNotSealed() {
        if (contractSealed) revert ErrContractSealed();
        _;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ErrAirdropPlanAlreadyExists","type":"error"},{"inputs":[],"name":"ErrContractPaused","type":"error"},{"inputs":[],"name":"ErrContractSealed","type":"error"},{"inputs":[],"name":"ErrFormulaAlreadyExists","type":"error"},{"inputs":[],"name":"ErrFormulaIsInvalid","type":"error"},{"inputs":[],"name":"ErrInvalidAirdropPlan","type":"error"},{"inputs":[],"name":"ErrInvalidArguments","type":"error"},{"inputs":[],"name":"ErrNotPermitted","type":"error"},{"inputs":[],"name":"ErrOnlyEOA","type":"error"},{"inputs":[],"name":"ErrOnlyOwner","type":"error"},{"inputs":[],"name":"ErrUnreachableCode","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"airdropId","type":"uint256"}],"name":"AirdropPlanUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[],"name":"ContractSealed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"formulaId","type":"uint256"}],"name":"FormulaUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"formulaId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Rerolled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"OPERATOR_FILTER_REGISTRY","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"airdropId_","type":"uint256"},{"internalType":"address[]","name":"addresses_","type":"address[]"},{"internalType":"uint256[]","name":"nums_","type":"uint256[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint256[]","name":"ids_","type":"uint256[]"},{"internalType":"uint256[]","name":"values_","type":"uint256[]"}],"name":"burnBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractSealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"airdropId_","type":"uint256"}],"name":"getAirdropPlan","outputs":[{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"formulaId_","type":"uint256"}],"name":"getFormula","outputs":[{"components":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"input","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"output","type":"tuple[]"}],"internalType":"struct IFPXEmoji.Formula","name":"formula_","type":"tuple"},{"internalType":"bool","name":"valid_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"input","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"output","type":"tuple[]"}],"internalType":"struct IFPXEmoji.Formula","name":"formula_","type":"tuple"}],"name":"isFormulaValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOperatorFilterRegistryEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"formulaId_","type":"uint256"}],"name":"merge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses_","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"uint256[]","name":"nums_","type":"uint256[]"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operatorFilterWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sealContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"airdropId_","type":"uint256"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"plan_","type":"tuple[]"},{"internalType":"bool","name":"overwrite_","type":"bool"}],"name":"setAirdropPlan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"formulaId_","type":"uint256"},{"components":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"input","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"key","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct IFPXEmoji.Uint256Pair[]","name":"output","type":"tuple[]"}],"internalType":"struct IFPXEmoji.Formula","name":"formula_","type":"tuple"},{"internalType":"bool","name":"overwrite_","type":"bool"}],"name":"setFormula","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled_","type":"bool"}],"name":"setOperatorFilterRegistryState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"},{"internalType":"bool","name":"state_","type":"bool"}],"name":"setOperatorFilterRegistryWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"string[]","name":"tokenURIs_","type":"string[]"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenURIs","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b50733cc6cdda760b79bafa08df41ecfa224f810dceb66001604051806020016040528060008152506200004a81620001b260201b60201c565b506003805460ff1916905560016005556200006533620001c4565b6daaeb6d7670e522a718067333cd4e3b15620001aa578015620000f857604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015620000d957600080fd5b505af1158015620000ee573d6000803e3d6000fd5b50505050620001aa565b6001600160a01b03821615620001495760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af290390604401620000be565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b1580156200019057600080fd5b505af1158015620001a5573d6000803e3d6000fd5b505050505b505062000387565b6002620001c08282620002bb565b5050565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200024157607f821691505b6020821081036200026257634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002b657600081815260208120601f850160051c81016020861015620002915750805b601f850160051c820191505b81811015620002b2578281556001016200029d565b5050505b505050565b81516001600160401b03811115620002d757620002d762000216565b620002ef81620002e884546200022c565b8462000268565b602080601f8311600181146200032757600084156200030e5750858301515b600019600386901b1c1916600185901b178555620002b2565b600085815260208120601f198616915b82811015620003585788860151825594840194600190910190840162000337565b5085821015620003775787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b613b5380620003976000396000f3fe608060405234801561001057600080fd5b50600436106102055760003560e01c806368bd580e1161011a578063a22cb465116100ad578063d5516e7f1161007c578063d5516e7f146104b8578063e2b02fef146104cb578063e985e9c5146104de578063f242432a1461051a578063f2fde38b1461052d57600080fd5b8063a22cb4651461045d578063a8bbd93d14610470578063aafb2d4414610491578063b6501637146104a457600080fd5b8063715018a6116100e9578063715018a6146104105780637970ce9f146104185780638da5cb5b1461042b57806395d89b411461043357600080fd5b806368bd580e146103cf5780636b20c454146103d75780636b8a0d14146103ea5780636c8b703f146103fd57600080fd5b80632eb2c2d61161019d57806346ee58691161016c57806346ee5869146103685780634e1273f41461037c57806351858e271461039c5780635bdf7996146103a45780635c975abb146103c457600080fd5b80632eb2c2d61461030d5780633cbefe24146103205780633f4ba83a1461033357806341f434341461033b57600080fd5b80631aefa884116101d95780631aefa884146102af57806324a47aeb146102c457806325a9588a146102d7578063277de3f9146102ea57600080fd5b8062fdd58e1461020a57806301ffc9a71461023057806306fdde03146102535780630e89341c1461029c575b600080fd5b61021d6102183660046128d8565b610540565b6040519081526020015b60405180910390f35b61024361023e366004612918565b6105d9565b6040519015158152602001610227565b61028f6040518060400160405280601981526020017f46505820464c5920782043686565727320555020456d6f6a690000000000000081525081565b6040516102279190612982565b61028f6102aa366004612995565b610603565b6102c26102bd3660046129bc565b6106a5565b005b6102c26102d2366004612995565b610709565b6102436102e5366004612b46565b610839565b6102436102f8366004612bee565b60076020526000908152604090205460ff1681565b6102c261031b366004612ced565b610895565b6102c261032e366004612d96565b6109a8565b6102c26109ff565b6103506daaeb6d7670e522a718067333cd4e81565b6040516001600160a01b039091168152602001610227565b60065461024390600160a81b900460ff1681565b61038f61038a366004612db3565b610a3c565b6040516102279190612eb8565b6102c2610b65565b6103b76103b2366004612995565b610ba0565b6040516102279190612f06565b60035460ff16610243565b6102c2610c26565b6102c26103e5366004612f19565b610c97565b6102c26103f8366004612f8c565b610d02565b61028f61040b366004612995565b610e03565b6102c2610e9d565b6102c2610426366004613036565b610eaf565b610350610fb7565b61028f6040518060400160405280600b81526020016a465058435550454d4f4a4960a81b81525081565b6102c261046b3660046129bc565b610fd0565b61048361047e366004612995565b6110d1565b6040516102279291906130cf565b6102c261049f36600461312e565b611215565b60065461024390600160a01b900460ff1681565b6102c26104c6366004613199565b611363565b6102c26104d9366004613212565b611625565b6102436104ec3660046132a3565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b6102c26105283660046132d6565b6117c3565b6102c261053b366004612bee565b6118c9565b60006001600160a01b0383166105b05760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60006105e48261193f565b806105d357506301ffc9a760e01b6001600160e01b03198316146105d3565b6000818152600a602052604090208054606091906106209061333a565b80601f016020809104026020016040519081016040528092919081815260200182805461064c9061333a565b80156106995780601f1061066e57610100808354040283529160200191610699565b820191906000526020600020905b81548152906001019060200180831161067c57829003601f168201915b50505050509050919050565b6106ad610fb7565b6001600160a01b0316336001600160a01b0316146106de57604051632775e0d560e11b815260040160405180910390fd5b6001600160a01b03919091166000908152600760205260409020805460ff1916911515919091179055565b3233146107295760405163a7520d1160e01b815260040160405180910390fd5b61073161198e565b60008061073d836110d1565b915091508061075f5760405163af8a56ad60e01b815260040160405180910390fd5b60005b8260400151518110156107cc576107bc338460400151838151811061078957610789613374565b602002602001015160000151856040015184815181106107ab576107ab613374565b6020026020010151602001516119e7565b6107c5816133a0565b9050610762565b5060006107dc8360600151611b04565b90506107fa3382600160405180602001604052806000815250611c0d565b6040518190859033907fa96a075915f1bd944e3679ca66bf5b78d3edbaa162d7530ceef7e98320fdfe4590600090a45050506108366001600555565b50565b6000816040015151600014806108525750606082015151155b1561085f57506000919050565b600082602001511180156108765750816020015142115b1561088357506000919050565b8151158015906105d357505051421190565b6006548590600160a81b900460ff1680156108c057503360009081526007602052604090205460ff16155b80156108da57506daaeb6d7670e522a718067333cd4e3b15155b1561099357336001600160a01b03821603610901576108fc8686868686611d27565b6109a0565b604051633185c44d60e21b81523060048201523360248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015610950573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097491906133b9565b61099357604051633b79c77360e21b81523360048201526024016105a7565b6109a08686868686611d27565b505050505050565b6109b0610fb7565b6001600160a01b0316336001600160a01b0316146109e157604051632775e0d560e11b815260040160405180910390fd5b60068054911515600160a81b0260ff60a81b19909216919091179055565b610a07611d6c565b600654600160a01b900460ff1615610a325760405163dfde68b560e01b815260040160405180910390fd5b610a3a611dcb565b565b60608151835114610aa15760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016105a7565b600083516001600160401b03811115610abc57610abc6129f3565b604051908082528060200260200182016040528015610ae5578160200160208202803683370190505b50905060005b8451811015610b5d57610b30858281518110610b0957610b09613374565b6020026020010151858381518110610b2357610b23613374565b6020026020010151610540565b828281518110610b4257610b42613374565b6020908102919091010152610b56816133a0565b9050610aeb565b509392505050565b610b6d611d6c565b600654600160a01b900460ff1615610b985760405163dfde68b560e01b815260040160405180910390fd5b610a3a611e1d565b606060096000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610c1b57838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190610bd5565b505050509050919050565b610c2e611d6c565b600654600160a01b900460ff1615610c595760405163dfde68b560e01b815260040160405180910390fd5b6006805460ff60a01b1916600160a01b1790556040517fa0058887862c892ade184993a48c672897bca2e36ebf7fa2b4703d4805fc3a0190600090a1565b6001600160a01b0383163314801590610cd457506001600160a01b038316600090815260016020908152604080832033845290915290205460ff16155b15610cf2576040516310fee1ab60e11b815260040160405180910390fd5b610cfd838383611e5a565b505050565b610d0a611d6c565b600654600160a01b900460ff1615610d355760405163dfde68b560e01b815260040160405180910390fd5b80610d6a5760008381526008602052604090206002015415610d6a5760405163e66ebedf60e01b815260040160405180910390fd5b610d7760608301836133d6565b15905080610d915750610d8d60408301836133d6565b1590505b15610daf57604051632020e2a760e11b815260040160405180910390fd5b60008381526008602052604090208290610dc982826134da565b50506040518381527fe6b19b2c6617851a0f4c49df91138e172046ffa3fc94114d4a7294d0e4362dd69060200160405180910390a1505050565b600a6020526000908152604090208054610e1c9061333a565b80601f0160208091040260200160405190810160405280929190818152602001828054610e489061333a565b8015610e955780601f10610e6a57610100808354040283529160200191610e95565b820191906000526020600020905b815481529060010190602001808311610e7857829003601f168201915b505050505081565b610ea5611d6c565b610a3a6000611ff6565b610eb7611d6c565b600654600160a01b900460ff1615610ee25760405163dfde68b560e01b815260040160405180910390fd5b610eea61198e565b841580610ef75750848314155b80610f025750848114155b15610f2057604051632020e2a760e11b815260040160405180910390fd5b60005b85811015610fac57610f9c878783818110610f4057610f40613374565b9050602002016020810190610f559190612bee565b868684818110610f6757610f67613374565b90506020020135858585818110610f8057610f80613374565b9050602002013560405180602001604052806000815250611c0d565b610fa5816133a0565b9050610f23565b506109a06001600555565b6000610fcb6006546001600160a01b031690565b905090565b6006548290600160a81b900460ff16801561100457506001600160a01b03811660009081526007602052604090205460ff16155b801561101e57506daaeb6d7670e522a718067333cd4e3b15155b156110c757604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa15801561107b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109f91906133b9565b6110c757604051633b79c77360e21b81526001600160a01b03821660048201526024016105a7565b610cfd8383612048565b6110fc6040518060800160405280600081526020016000815260200160608152602001606081525090565b6000828152600860209081526040808320815160808101835281548152600182015481850152600282018054845181870281018701865281815292959394860193879084015b8282101561118857838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190611142565b50505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b828210156111fb578382906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906111b5565b5050505081525050915061120e82610839565b9050915091565b61121d611d6c565b600654600160a01b900460ff16156112485760405163dfde68b560e01b815260040160405180910390fd5b8215806112555750828114155b1561127357604051632020e2a760e11b815260040160405180910390fd5b60005b8381101561135c57600085858381811061129257611292613374565b90506020020135905060008484848181106112af576112af613374565b90506020028101906112c191906135cd565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250868152600a602052604090209394506113109250849150839050613659565b50817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b826040516113419190612982565b60405180910390a2505080611355906133a0565b9050611276565b5050505050565b61136b611d6c565b600654600160a01b900460ff16156113965760405163dfde68b560e01b815260040160405180910390fd5b61139e61198e565b600085815260096020908152604080832080548251818502810185019093528083529192909190849084015b82821015611410578382906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906113ca565b505082519293505050600081900361143b5760405163d43dd86760e01b815260040160405180910390fd5b6000805b828110156114825783818151811061145957611459613374565b602002602001015160200151826114709190613718565b915061147b816133a0565b905061143f565b5060005b8681101561160d5760008888838181106114a2576114a2613374565b90506020020160208101906114b79190612bee565b905060008787848181106114cd576114cd613374565b90506020020135905060005b818110156115f9576000856114ec612057565b6114f69190613741565b905060008060005b898110156115c6578a818151811061151857611518613374565b6020026020010151602001518361152f9190613718565b9250828410156115b6578a818151811061154b5761154b613374565b6020026020010151602001805180919061156490613763565b9052508861157181613763565b9950506115ad878c838151811061158a5761158a613374565b602002602001015160000151600160405180602001604052806000815250611c0d565b600191506115c6565b6115bf816133a0565b90506114fe565b50806115e5576040516304abfdf560e01b815260040160405180910390fd5b505050806115f2906133a0565b90506114d9565b50505080611606906133a0565b9050611486565b5061161888846120c9565b50505061135c6001600555565b61162d611d6c565b600654600160a01b900460ff16156116585760405163dfde68b560e01b815260040160405180910390fd5b80156116bf576116ba848484808060200260200160405190810160405280939291908181526020016000905b828210156116b0576116a16040830286013681900381019061377a565b81526020019060010190611684565b50505050506120c9565b6117bd565b600084815260096020526040902054156116ec576040516361ea010f60e11b815260040160405180910390fd5b600082900361170e5760405163d43dd86760e01b815260040160405180910390fd5b6000848152600960205260408120905b83811015611787578185858381811061173957611739613374565b835460018101855560009485526020909420604090910292909201926002029091019050611774828281358155602082013560018201555050565b505080611780906133a0565b905061171e565b506040518581527f246a4deb002a4f3f097c7b09395f0f31536425816c55b2f93e7d329ab3bd2edc9060200160405180910390a1505b50505050565b6006548590600160a81b900460ff1680156117ee57503360009081526007602052604090205460ff16155b801561180857506daaeb6d7670e522a718067333cd4e3b15155b156118bc57336001600160a01b0382160361182a576108fc86868686866121a9565b604051633185c44d60e21b81523060048201523360248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015611879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189d91906133b9565b6118bc57604051633b79c77360e21b81523360048201526024016105a7565b6109a086868686866121a9565b6118d1611d6c565b6001600160a01b0381166119365760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105a7565b61083681611ff6565b60006001600160e01b03198216636cdb3d1360e11b14806105e457506001600160e01b031982166303a24d0760e21b14806105d357506301ffc9a760e01b6001600160e01b03198316146105d3565b6002600554036119e05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105a7565b6002600555565b6001600160a01b038316611a0d5760405162461bcd60e51b81526004016105a790613796565b336000611a19846121ee565b90506000611a26846121ee565b9050611a4683876000858560405180602001604052806000815250612239565b6000858152602081815260408083206001600160a01b038a16845290915290205484811015611a875760405162461bcd60e51b81526004016105a7906137d9565b6000868152602081815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46040805160208101909152600090525b50505050505050565b60008151600103611b355781600081518110611b2257611b22613374565b6020026020010151600001519050919050565b6000805b8351811015611b6f57838181518110611b5457611b54613374565b60200260200101516020015182019150806001019050611b39565b50600081611b7b612057565b81611b8857611b8861372b565b0690506000805b8551811015611bf357858181518110611baa57611baa613374565b6020026020010151602001518201915081831015611beb57858181518110611bd457611bd4613374565b602002602001015160000151945050505050919050565b600101611b8f565b506040516304abfdf560e01b815260040160405180910390fd5b6001600160a01b038416611c6d5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b60648201526084016105a7565b336000611c79856121ee565b90506000611c86856121ee565b9050611c9783600089858589612239565b6000868152602081815260408083206001600160a01b038b16845290915281208054879290611cc7908490613718565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4611afb8360008989898961225d565b6001600160a01b038516331480611d435750611d4385336104ec565b611d5f5760405162461bcd60e51b81526004016105a79061381d565b61135c85858585856123b8565b33611d75610fb7565b6001600160a01b031614610a3a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105a7565b611dd361255a565b6003805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b611e256125a3565b6003805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611e003390565b6001600160a01b038316611e805760405162461bcd60e51b81526004016105a790613796565b8051825114611ea15760405162461bcd60e51b81526004016105a79061386b565b6000339050611ec481856000868660405180602001604052806000815250612239565b60005b8351811015611f89576000848281518110611ee457611ee4613374565b602002602001015190506000848381518110611f0257611f02613374565b602090810291909101810151600084815280835260408082206001600160a01b038c168352909352919091205490915081811015611f525760405162461bcd60e51b81526004016105a7906137d9565b6000928352602083815260408085206001600160a01b038b1686529091529092209103905580611f81816133a0565b915050611ec7565b5060006001600160a01b0316846001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051611fda9291906138b3565b60405180910390a46040805160208101909152600090526117bd565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6120533383836125e9565b5050565b6004805460010190819055604080514360001901406020808301919091524482840152426060808401919091526bffffffffffffffffffffffff1941821b81166080850152609484019590955232901b90931660b4820152815180820360a801815260c8909101909152805191012090565b8051600083815260096020526040902054146120f857604051632020e2a760e11b815260040160405180910390fd5b60005b81518110156121715781818151811061211657612116613374565b602002602001015160096000858152602001908152602001600020828154811061214257612142613374565b6000918252602091829020835160029092020190815591015160019091015561216a816133a0565b90506120fb565b506040518281527f246a4deb002a4f3f097c7b09395f0f31536425816c55b2f93e7d329ab3bd2edc9060200160405180910390a15050565b6001600160a01b0385163314806121c557506121c585336104ec565b6121e15760405162461bcd60e51b81526004016105a79061381d565b61135c85858585856126c9565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061222857612228613374565b602090810291909101015292915050565b60035460ff16156109a057604051638ac5553d60e01b815260040160405180910390fd5b6001600160a01b0384163b156109a05760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906122a190899089908890889088906004016138e1565b6020604051808303816000875af19250505080156122dc575060408051601f3d908101601f191682019092526122d991810190613926565b60015b612388576122e8613943565b806308c379a00361232157506122fc61395f565b806123075750612323565b8060405162461bcd60e51b81526004016105a79190612982565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016105a7565b6001600160e01b0319811663f23a6e6160e01b14611afb5760405162461bcd60e51b81526004016105a7906139e8565b81518351146123d95760405162461bcd60e51b81526004016105a79061386b565b6001600160a01b0384166123ff5760405162461bcd60e51b81526004016105a790613a30565b3361240e818787878787612239565b60005b84518110156124f457600085828151811061242e5761242e613374565b60200260200101519050600085838151811061244c5761244c613374565b602090810291909101810151600084815280835260408082206001600160a01b038e16835290935291909120549091508181101561249c5760405162461bcd60e51b81526004016105a790613a75565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906124d9908490613718565b92505081905550505050806124ed906133a0565b9050612411565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb87876040516125449291906138b3565b60405180910390a46109a0818787878787612801565b60035460ff16610a3a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016105a7565b60035460ff1615610a3a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016105a7565b816001600160a01b0316836001600160a01b03160361265c5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016105a7565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166126ef5760405162461bcd60e51b81526004016105a790613a30565b3360006126fb856121ee565b90506000612708856121ee565b9050612718838989858589612239565b6000868152602081815260408083206001600160a01b038c168452909152902054858110156127595760405162461bcd60e51b81526004016105a790613a75565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290612796908490613718565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46127f6848a8a8a8a8a61225d565b505050505050505050565b6001600160a01b0384163b156109a05760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906128459089908990889088908890600401613abf565b6020604051808303816000875af1925050508015612880575060408051601f3d908101601f1916820190925261287d91810190613926565b60015b61288c576122e8613943565b6001600160e01b0319811663bc197c8160e01b14611afb5760405162461bcd60e51b81526004016105a7906139e8565b80356001600160a01b03811681146128d357600080fd5b919050565b600080604083850312156128eb57600080fd5b6128f4836128bc565b946020939093013593505050565b6001600160e01b03198116811461083657600080fd5b60006020828403121561292a57600080fd5b813561293581612902565b9392505050565b6000815180845260005b8181101561296257602081850181015186830182015201612946565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000612935602083018461293c565b6000602082840312156129a757600080fd5b5035919050565b801515811461083657600080fd5b600080604083850312156129cf57600080fd5b6129d8836128bc565b915060208301356129e8816129ae565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b0382111715612a2857612a286129f3565b60405250565b601f8201601f191681016001600160401b0381118282101715612a5357612a536129f3565b6040525050565b60006001600160401b03821115612a7357612a736129f3565b5060051b60200190565b600060408284031215612a8f57600080fd5b604051604081018181106001600160401b0382111715612ab157612ab16129f3565b604052823581526020928301359281019290925250919050565b600082601f830112612adc57600080fd5b81356020612ae982612a5a565b60408051612af78382612a2e565b84815260069490941b8601830193838101925087851115612b1757600080fd5b8387015b85811015612b3a57612b2d8982612a7d565b8452928401928201612b1b565b50979650505050505050565b600060208284031215612b5857600080fd5b81356001600160401b0380821115612b6f57600080fd5b9083019060808286031215612b8357600080fd5b604051612b8f81612a09565b8235815260208301356020820152604083013582811115612baf57600080fd5b612bbb87828601612acb565b604083015250606083013582811115612bd357600080fd5b612bdf87828601612acb565b60608301525095945050505050565b600060208284031215612c0057600080fd5b612935826128bc565b600082601f830112612c1a57600080fd5b81356020612c2782612a5a565b604051612c348282612a2e565b83815260059390931b8501820192828101915086841115612c5457600080fd5b8286015b84811015612c6f5780358352918301918301612c58565b509695505050505050565b600082601f830112612c8b57600080fd5b81356001600160401b03811115612ca457612ca46129f3565b604051612cbb601f8301601f191660200182612a2e565b818152846020838601011115612cd057600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612d0557600080fd5b612d0e866128bc565b9450612d1c602087016128bc565b935060408601356001600160401b0380821115612d3857600080fd5b612d4489838a01612c09565b94506060880135915080821115612d5a57600080fd5b612d6689838a01612c09565b93506080880135915080821115612d7c57600080fd5b50612d8988828901612c7a565b9150509295509295909350565b600060208284031215612da857600080fd5b8135612935816129ae565b60008060408385031215612dc657600080fd5b82356001600160401b0380821115612ddd57600080fd5b818501915085601f830112612df157600080fd5b81356020612dfe82612a5a565b604051612e0b8282612a2e565b83815260059390931b8501820192828101915089841115612e2b57600080fd5b948201945b83861015612e5057612e41866128bc565b82529482019490820190612e30565b96505086013592505080821115612e6657600080fd5b50612e7385828601612c09565b9150509250929050565b600081518084526020808501945080840160005b83811015612ead57815187529582019590820190600101612e91565b509495945050505050565b6020815260006129356020830184612e7d565b600081518084526020808501945080840160005b83811015612ead578151805188528301518388015260409096019590820190600101612edf565b6020815260006129356020830184612ecb565b600080600060608486031215612f2e57600080fd5b612f37846128bc565b925060208401356001600160401b0380821115612f5357600080fd5b612f5f87838801612c09565b93506040860135915080821115612f7557600080fd5b50612f8286828701612c09565b9150509250925092565b600080600060608486031215612fa157600080fd5b8335925060208401356001600160401b03811115612fbe57600080fd5b840160808187031215612fd057600080fd5b91506040840135612fe0816129ae565b809150509250925092565b60008083601f840112612ffd57600080fd5b5081356001600160401b0381111561301457600080fd5b6020830191508360208260051b850101111561302f57600080fd5b9250929050565b6000806000806000806060878903121561304f57600080fd5b86356001600160401b038082111561306657600080fd5b6130728a838b01612feb565b9098509650602089013591508082111561308b57600080fd5b6130978a838b01612feb565b909650945060408901359150808211156130b057600080fd5b506130bd89828a01612feb565b979a9699509497509295939492505050565b604081528251604082015260208301516060820152600060408401516080808401526130fe60c0840182612ecb565b90506060850151603f198483030160a085015261311b8282612ecb565b9250505082151560208301529392505050565b6000806000806040858703121561314457600080fd5b84356001600160401b038082111561315b57600080fd5b61316788838901612feb565b9096509450602087013591508082111561318057600080fd5b5061318d87828801612feb565b95989497509550505050565b6000806000806000606086880312156131b157600080fd5b8535945060208601356001600160401b03808211156131cf57600080fd5b6131db89838a01612feb565b909650945060408801359150808211156131f457600080fd5b5061320188828901612feb565b969995985093965092949392505050565b6000806000806060858703121561322857600080fd5b8435935060208501356001600160401b038082111561324657600080fd5b818701915087601f83011261325a57600080fd5b81358181111561326957600080fd5b8860208260061b850101111561327e57600080fd5b6020830195508094505050506040850135613298816129ae565b939692955090935050565b600080604083850312156132b657600080fd5b6132bf836128bc565b91506132cd602084016128bc565b90509250929050565b600080600080600060a086880312156132ee57600080fd5b6132f7866128bc565b9450613305602087016128bc565b9350604086013592506060860135915060808601356001600160401b0381111561332e57600080fd5b612d8988828901612c7a565b600181811c9082168061334e57607f821691505b60208210810361336e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016133b2576133b261338a565b5060010190565b6000602082840312156133cb57600080fd5b8151612935816129ae565b6000808335601e198436030181126133ed57600080fd5b8301803591506001600160401b0382111561340757600080fd5b6020019150600681901b360382131561302f57600080fd5b600160401b831115613433576134336129f3565b8054838255808410156134a15760016001600160ff1b03828116831461345b5761345b61338a565b808616861461346c5761346c61338a565b5060008381526020812086831b81019084841b015b8082101561349c578282558284830155600282019150613481565b505050505b5060008181526020812083915b858110156109a057823582556020830135600183015560409290920191600291909101906001016134ae565b813581556001602083013581830155600280830160406134fc818701876133d6565b600160401b811115613510576135106129f3565b83548185558082101561357a576001600160ff1b0381811682146135365761353661338a565b80831683146135475761354761338a565b5060008581526020812083891b810190838a1b015b8082101561357657828255828a830155888201915061355c565b5050505b50600093845260208420935b818110156135ab57823585556020830135600186015593850193918301918601613586565b505050505050506135bf60608301836133d6565b6117bd81836003860161341f565b6000808335601e198436030181126135e457600080fd5b8301803591506001600160401b038211156135fe57600080fd5b60200191503681900382131561302f57600080fd5b601f821115610cfd57600081815260208120601f850160051c8101602086101561363a5750805b601f850160051c820191505b818110156109a057828155600101613646565b81516001600160401b03811115613672576136726129f3565b61368681613680845461333a565b84613613565b602080601f8311600181146136bb57600084156136a35750858301515b600019600386901b1c1916600185901b1785556109a0565b600085815260208120601f198616915b828110156136ea578886015182559484019460019091019084016136cb565b50858210156137085787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156105d3576105d361338a565b634e487b7160e01b600052601260045260246000fd5b60008261375e57634e487b7160e01b600052601260045260246000fd5b500690565b6000816137725761377261338a565b506000190190565b60006040828403121561378c57600080fd5b6129358383612a7d565b60208082526023908201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526024908201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604082015263616e636560e01b606082015260800190565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b6040815260006138c66040830185612e7d565b82810360208401526138d88185612e7d565b95945050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061391b9083018461293c565b979650505050505050565b60006020828403121561393857600080fd5b815161293581612902565b600060033d111561395c5760046000803e5060005160e01c5b90565b600060443d101561396d5790565b6040516003193d81016004833e81513d6001600160401b03816024840111818411171561399c57505050505090565b82850191508151818111156139b45750505050505090565b843d87010160208285010111156139ce5750505050505090565b6139dd60208286010187612a2e565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b6001600160a01b0386811682528516602082015260a060408201819052600090613aeb90830186612e7d565b8281036060840152613afd8186612e7d565b90508281036080840152613b11818561293c565b9897505050505050505056fea264697066735822122053e28f2fe0997046694d6721b3f38b5c4009c08b2490f2965ced52b2cb5d8d0864736f6c63430008110033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102055760003560e01c806368bd580e1161011a578063a22cb465116100ad578063d5516e7f1161007c578063d5516e7f146104b8578063e2b02fef146104cb578063e985e9c5146104de578063f242432a1461051a578063f2fde38b1461052d57600080fd5b8063a22cb4651461045d578063a8bbd93d14610470578063aafb2d4414610491578063b6501637146104a457600080fd5b8063715018a6116100e9578063715018a6146104105780637970ce9f146104185780638da5cb5b1461042b57806395d89b411461043357600080fd5b806368bd580e146103cf5780636b20c454146103d75780636b8a0d14146103ea5780636c8b703f146103fd57600080fd5b80632eb2c2d61161019d57806346ee58691161016c57806346ee5869146103685780634e1273f41461037c57806351858e271461039c5780635bdf7996146103a45780635c975abb146103c457600080fd5b80632eb2c2d61461030d5780633cbefe24146103205780633f4ba83a1461033357806341f434341461033b57600080fd5b80631aefa884116101d95780631aefa884146102af57806324a47aeb146102c457806325a9588a146102d7578063277de3f9146102ea57600080fd5b8062fdd58e1461020a57806301ffc9a71461023057806306fdde03146102535780630e89341c1461029c575b600080fd5b61021d6102183660046128d8565b610540565b6040519081526020015b60405180910390f35b61024361023e366004612918565b6105d9565b6040519015158152602001610227565b61028f6040518060400160405280601981526020017f46505820464c5920782043686565727320555020456d6f6a690000000000000081525081565b6040516102279190612982565b61028f6102aa366004612995565b610603565b6102c26102bd3660046129bc565b6106a5565b005b6102c26102d2366004612995565b610709565b6102436102e5366004612b46565b610839565b6102436102f8366004612bee565b60076020526000908152604090205460ff1681565b6102c261031b366004612ced565b610895565b6102c261032e366004612d96565b6109a8565b6102c26109ff565b6103506daaeb6d7670e522a718067333cd4e81565b6040516001600160a01b039091168152602001610227565b60065461024390600160a81b900460ff1681565b61038f61038a366004612db3565b610a3c565b6040516102279190612eb8565b6102c2610b65565b6103b76103b2366004612995565b610ba0565b6040516102279190612f06565b60035460ff16610243565b6102c2610c26565b6102c26103e5366004612f19565b610c97565b6102c26103f8366004612f8c565b610d02565b61028f61040b366004612995565b610e03565b6102c2610e9d565b6102c2610426366004613036565b610eaf565b610350610fb7565b61028f6040518060400160405280600b81526020016a465058435550454d4f4a4960a81b81525081565b6102c261046b3660046129bc565b610fd0565b61048361047e366004612995565b6110d1565b6040516102279291906130cf565b6102c261049f36600461312e565b611215565b60065461024390600160a01b900460ff1681565b6102c26104c6366004613199565b611363565b6102c26104d9366004613212565b611625565b6102436104ec3660046132a3565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b6102c26105283660046132d6565b6117c3565b6102c261053b366004612bee565b6118c9565b60006001600160a01b0383166105b05760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000818152602081815260408083206001600160a01b03861684529091529020545b92915050565b60006105e48261193f565b806105d357506301ffc9a760e01b6001600160e01b03198316146105d3565b6000818152600a602052604090208054606091906106209061333a565b80601f016020809104026020016040519081016040528092919081815260200182805461064c9061333a565b80156106995780601f1061066e57610100808354040283529160200191610699565b820191906000526020600020905b81548152906001019060200180831161067c57829003601f168201915b50505050509050919050565b6106ad610fb7565b6001600160a01b0316336001600160a01b0316146106de57604051632775e0d560e11b815260040160405180910390fd5b6001600160a01b03919091166000908152600760205260409020805460ff1916911515919091179055565b3233146107295760405163a7520d1160e01b815260040160405180910390fd5b61073161198e565b60008061073d836110d1565b915091508061075f5760405163af8a56ad60e01b815260040160405180910390fd5b60005b8260400151518110156107cc576107bc338460400151838151811061078957610789613374565b602002602001015160000151856040015184815181106107ab576107ab613374565b6020026020010151602001516119e7565b6107c5816133a0565b9050610762565b5060006107dc8360600151611b04565b90506107fa3382600160405180602001604052806000815250611c0d565b6040518190859033907fa96a075915f1bd944e3679ca66bf5b78d3edbaa162d7530ceef7e98320fdfe4590600090a45050506108366001600555565b50565b6000816040015151600014806108525750606082015151155b1561085f57506000919050565b600082602001511180156108765750816020015142115b1561088357506000919050565b8151158015906105d357505051421190565b6006548590600160a81b900460ff1680156108c057503360009081526007602052604090205460ff16155b80156108da57506daaeb6d7670e522a718067333cd4e3b15155b1561099357336001600160a01b03821603610901576108fc8686868686611d27565b6109a0565b604051633185c44d60e21b81523060048201523360248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015610950573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097491906133b9565b61099357604051633b79c77360e21b81523360048201526024016105a7565b6109a08686868686611d27565b505050505050565b6109b0610fb7565b6001600160a01b0316336001600160a01b0316146109e157604051632775e0d560e11b815260040160405180910390fd5b60068054911515600160a81b0260ff60a81b19909216919091179055565b610a07611d6c565b600654600160a01b900460ff1615610a325760405163dfde68b560e01b815260040160405180910390fd5b610a3a611dcb565b565b60608151835114610aa15760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016105a7565b600083516001600160401b03811115610abc57610abc6129f3565b604051908082528060200260200182016040528015610ae5578160200160208202803683370190505b50905060005b8451811015610b5d57610b30858281518110610b0957610b09613374565b6020026020010151858381518110610b2357610b23613374565b6020026020010151610540565b828281518110610b4257610b42613374565b6020908102919091010152610b56816133a0565b9050610aeb565b509392505050565b610b6d611d6c565b600654600160a01b900460ff1615610b985760405163dfde68b560e01b815260040160405180910390fd5b610a3a611e1d565b606060096000838152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015610c1b57838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190610bd5565b505050509050919050565b610c2e611d6c565b600654600160a01b900460ff1615610c595760405163dfde68b560e01b815260040160405180910390fd5b6006805460ff60a01b1916600160a01b1790556040517fa0058887862c892ade184993a48c672897bca2e36ebf7fa2b4703d4805fc3a0190600090a1565b6001600160a01b0383163314801590610cd457506001600160a01b038316600090815260016020908152604080832033845290915290205460ff16155b15610cf2576040516310fee1ab60e11b815260040160405180910390fd5b610cfd838383611e5a565b505050565b610d0a611d6c565b600654600160a01b900460ff1615610d355760405163dfde68b560e01b815260040160405180910390fd5b80610d6a5760008381526008602052604090206002015415610d6a5760405163e66ebedf60e01b815260040160405180910390fd5b610d7760608301836133d6565b15905080610d915750610d8d60408301836133d6565b1590505b15610daf57604051632020e2a760e11b815260040160405180910390fd5b60008381526008602052604090208290610dc982826134da565b50506040518381527fe6b19b2c6617851a0f4c49df91138e172046ffa3fc94114d4a7294d0e4362dd69060200160405180910390a1505050565b600a6020526000908152604090208054610e1c9061333a565b80601f0160208091040260200160405190810160405280929190818152602001828054610e489061333a565b8015610e955780601f10610e6a57610100808354040283529160200191610e95565b820191906000526020600020905b815481529060010190602001808311610e7857829003601f168201915b505050505081565b610ea5611d6c565b610a3a6000611ff6565b610eb7611d6c565b600654600160a01b900460ff1615610ee25760405163dfde68b560e01b815260040160405180910390fd5b610eea61198e565b841580610ef75750848314155b80610f025750848114155b15610f2057604051632020e2a760e11b815260040160405180910390fd5b60005b85811015610fac57610f9c878783818110610f4057610f40613374565b9050602002016020810190610f559190612bee565b868684818110610f6757610f67613374565b90506020020135858585818110610f8057610f80613374565b9050602002013560405180602001604052806000815250611c0d565b610fa5816133a0565b9050610f23565b506109a06001600555565b6000610fcb6006546001600160a01b031690565b905090565b6006548290600160a81b900460ff16801561100457506001600160a01b03811660009081526007602052604090205460ff16155b801561101e57506daaeb6d7670e522a718067333cd4e3b15155b156110c757604051633185c44d60e21b81523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa15801561107b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109f91906133b9565b6110c757604051633b79c77360e21b81526001600160a01b03821660048201526024016105a7565b610cfd8383612048565b6110fc6040518060800160405280600081526020016000815260200160608152602001606081525090565b6000828152600860209081526040808320815160808101835281548152600182015481850152600282018054845181870281018701865281815292959394860193879084015b8282101561118857838290600052602060002090600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190611142565b50505050815260200160038201805480602002602001604051908101604052809291908181526020016000905b828210156111fb578382906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906111b5565b5050505081525050915061120e82610839565b9050915091565b61121d611d6c565b600654600160a01b900460ff16156112485760405163dfde68b560e01b815260040160405180910390fd5b8215806112555750828114155b1561127357604051632020e2a760e11b815260040160405180910390fd5b60005b8381101561135c57600085858381811061129257611292613374565b90506020020135905060008484848181106112af576112af613374565b90506020028101906112c191906135cd565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250868152600a602052604090209394506113109250849150839050613659565b50817f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b826040516113419190612982565b60405180910390a2505080611355906133a0565b9050611276565b5050505050565b61136b611d6c565b600654600160a01b900460ff16156113965760405163dfde68b560e01b815260040160405180910390fd5b61139e61198e565b600085815260096020908152604080832080548251818502810185019093528083529192909190849084015b82821015611410578382906000526020600020906002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906113ca565b505082519293505050600081900361143b5760405163d43dd86760e01b815260040160405180910390fd5b6000805b828110156114825783818151811061145957611459613374565b602002602001015160200151826114709190613718565b915061147b816133a0565b905061143f565b5060005b8681101561160d5760008888838181106114a2576114a2613374565b90506020020160208101906114b79190612bee565b905060008787848181106114cd576114cd613374565b90506020020135905060005b818110156115f9576000856114ec612057565b6114f69190613741565b905060008060005b898110156115c6578a818151811061151857611518613374565b6020026020010151602001518361152f9190613718565b9250828410156115b6578a818151811061154b5761154b613374565b6020026020010151602001805180919061156490613763565b9052508861157181613763565b9950506115ad878c838151811061158a5761158a613374565b602002602001015160000151600160405180602001604052806000815250611c0d565b600191506115c6565b6115bf816133a0565b90506114fe565b50806115e5576040516304abfdf560e01b815260040160405180910390fd5b505050806115f2906133a0565b90506114d9565b50505080611606906133a0565b9050611486565b5061161888846120c9565b50505061135c6001600555565b61162d611d6c565b600654600160a01b900460ff16156116585760405163dfde68b560e01b815260040160405180910390fd5b80156116bf576116ba848484808060200260200160405190810160405280939291908181526020016000905b828210156116b0576116a16040830286013681900381019061377a565b81526020019060010190611684565b50505050506120c9565b6117bd565b600084815260096020526040902054156116ec576040516361ea010f60e11b815260040160405180910390fd5b600082900361170e5760405163d43dd86760e01b815260040160405180910390fd5b6000848152600960205260408120905b83811015611787578185858381811061173957611739613374565b835460018101855560009485526020909420604090910292909201926002029091019050611774828281358155602082013560018201555050565b505080611780906133a0565b905061171e565b506040518581527f246a4deb002a4f3f097c7b09395f0f31536425816c55b2f93e7d329ab3bd2edc9060200160405180910390a1505b50505050565b6006548590600160a81b900460ff1680156117ee57503360009081526007602052604090205460ff16155b801561180857506daaeb6d7670e522a718067333cd4e3b15155b156118bc57336001600160a01b0382160361182a576108fc86868686866121a9565b604051633185c44d60e21b81523060048201523360248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015611879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189d91906133b9565b6118bc57604051633b79c77360e21b81523360048201526024016105a7565b6109a086868686866121a9565b6118d1611d6c565b6001600160a01b0381166119365760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016105a7565b61083681611ff6565b60006001600160e01b03198216636cdb3d1360e11b14806105e457506001600160e01b031982166303a24d0760e21b14806105d357506301ffc9a760e01b6001600160e01b03198316146105d3565b6002600554036119e05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105a7565b6002600555565b6001600160a01b038316611a0d5760405162461bcd60e51b81526004016105a790613796565b336000611a19846121ee565b90506000611a26846121ee565b9050611a4683876000858560405180602001604052806000815250612239565b6000858152602081815260408083206001600160a01b038a16845290915290205484811015611a875760405162461bcd60e51b81526004016105a7906137d9565b6000868152602081815260408083206001600160a01b038b81168086529184528285208a8703905582518b81529384018a90529092908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46040805160208101909152600090525b50505050505050565b60008151600103611b355781600081518110611b2257611b22613374565b6020026020010151600001519050919050565b6000805b8351811015611b6f57838181518110611b5457611b54613374565b60200260200101516020015182019150806001019050611b39565b50600081611b7b612057565b81611b8857611b8861372b565b0690506000805b8551811015611bf357858181518110611baa57611baa613374565b6020026020010151602001518201915081831015611beb57858181518110611bd457611bd4613374565b602002602001015160000151945050505050919050565b600101611b8f565b506040516304abfdf560e01b815260040160405180910390fd5b6001600160a01b038416611c6d5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b60648201526084016105a7565b336000611c79856121ee565b90506000611c86856121ee565b9050611c9783600089858589612239565b6000868152602081815260408083206001600160a01b038b16845290915281208054879290611cc7908490613718565b909155505060408051878152602081018790526001600160a01b03808a1692600092918716917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a4611afb8360008989898961225d565b6001600160a01b038516331480611d435750611d4385336104ec565b611d5f5760405162461bcd60e51b81526004016105a79061381d565b61135c85858585856123b8565b33611d75610fb7565b6001600160a01b031614610a3a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105a7565b611dd361255a565b6003805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b611e256125a3565b6003805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611e003390565b6001600160a01b038316611e805760405162461bcd60e51b81526004016105a790613796565b8051825114611ea15760405162461bcd60e51b81526004016105a79061386b565b6000339050611ec481856000868660405180602001604052806000815250612239565b60005b8351811015611f89576000848281518110611ee457611ee4613374565b602002602001015190506000848381518110611f0257611f02613374565b602090810291909101810151600084815280835260408082206001600160a01b038c168352909352919091205490915081811015611f525760405162461bcd60e51b81526004016105a7906137d9565b6000928352602083815260408085206001600160a01b038b1686529091529092209103905580611f81816133a0565b915050611ec7565b5060006001600160a01b0316846001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051611fda9291906138b3565b60405180910390a46040805160208101909152600090526117bd565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6120533383836125e9565b5050565b6004805460010190819055604080514360001901406020808301919091524482840152426060808401919091526bffffffffffffffffffffffff1941821b81166080850152609484019590955232901b90931660b4820152815180820360a801815260c8909101909152805191012090565b8051600083815260096020526040902054146120f857604051632020e2a760e11b815260040160405180910390fd5b60005b81518110156121715781818151811061211657612116613374565b602002602001015160096000858152602001908152602001600020828154811061214257612142613374565b6000918252602091829020835160029092020190815591015160019091015561216a816133a0565b90506120fb565b506040518281527f246a4deb002a4f3f097c7b09395f0f31536425816c55b2f93e7d329ab3bd2edc9060200160405180910390a15050565b6001600160a01b0385163314806121c557506121c585336104ec565b6121e15760405162461bcd60e51b81526004016105a79061381d565b61135c85858585856126c9565b6040805160018082528183019092526060916000919060208083019080368337019050509050828160008151811061222857612228613374565b602090810291909101015292915050565b60035460ff16156109a057604051638ac5553d60e01b815260040160405180910390fd5b6001600160a01b0384163b156109a05760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906122a190899089908890889088906004016138e1565b6020604051808303816000875af19250505080156122dc575060408051601f3d908101601f191682019092526122d991810190613926565b60015b612388576122e8613943565b806308c379a00361232157506122fc61395f565b806123075750612323565b8060405162461bcd60e51b81526004016105a79190612982565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016105a7565b6001600160e01b0319811663f23a6e6160e01b14611afb5760405162461bcd60e51b81526004016105a7906139e8565b81518351146123d95760405162461bcd60e51b81526004016105a79061386b565b6001600160a01b0384166123ff5760405162461bcd60e51b81526004016105a790613a30565b3361240e818787878787612239565b60005b84518110156124f457600085828151811061242e5761242e613374565b60200260200101519050600085838151811061244c5761244c613374565b602090810291909101810151600084815280835260408082206001600160a01b038e16835290935291909120549091508181101561249c5760405162461bcd60e51b81526004016105a790613a75565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b168252812080548492906124d9908490613718565b92505081905550505050806124ed906133a0565b9050612411565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb87876040516125449291906138b3565b60405180910390a46109a0818787878787612801565b60035460ff16610a3a5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016105a7565b60035460ff1615610a3a5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016105a7565b816001600160a01b0316836001600160a01b03160361265c5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016105a7565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166126ef5760405162461bcd60e51b81526004016105a790613a30565b3360006126fb856121ee565b90506000612708856121ee565b9050612718838989858589612239565b6000868152602081815260408083206001600160a01b038c168452909152902054858110156127595760405162461bcd60e51b81526004016105a790613a75565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a16825281208054889290612796908490613718565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46127f6848a8a8a8a8a61225d565b505050505050505050565b6001600160a01b0384163b156109a05760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906128459089908990889088908890600401613abf565b6020604051808303816000875af1925050508015612880575060408051601f3d908101601f1916820190925261287d91810190613926565b60015b61288c576122e8613943565b6001600160e01b0319811663bc197c8160e01b14611afb5760405162461bcd60e51b81526004016105a7906139e8565b80356001600160a01b03811681146128d357600080fd5b919050565b600080604083850312156128eb57600080fd5b6128f4836128bc565b946020939093013593505050565b6001600160e01b03198116811461083657600080fd5b60006020828403121561292a57600080fd5b813561293581612902565b9392505050565b6000815180845260005b8181101561296257602081850181015186830182015201612946565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000612935602083018461293c565b6000602082840312156129a757600080fd5b5035919050565b801515811461083657600080fd5b600080604083850312156129cf57600080fd5b6129d8836128bc565b915060208301356129e8816129ae565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b0382111715612a2857612a286129f3565b60405250565b601f8201601f191681016001600160401b0381118282101715612a5357612a536129f3565b6040525050565b60006001600160401b03821115612a7357612a736129f3565b5060051b60200190565b600060408284031215612a8f57600080fd5b604051604081018181106001600160401b0382111715612ab157612ab16129f3565b604052823581526020928301359281019290925250919050565b600082601f830112612adc57600080fd5b81356020612ae982612a5a565b60408051612af78382612a2e565b84815260069490941b8601830193838101925087851115612b1757600080fd5b8387015b85811015612b3a57612b2d8982612a7d565b8452928401928201612b1b565b50979650505050505050565b600060208284031215612b5857600080fd5b81356001600160401b0380821115612b6f57600080fd5b9083019060808286031215612b8357600080fd5b604051612b8f81612a09565b8235815260208301356020820152604083013582811115612baf57600080fd5b612bbb87828601612acb565b604083015250606083013582811115612bd357600080fd5b612bdf87828601612acb565b60608301525095945050505050565b600060208284031215612c0057600080fd5b612935826128bc565b600082601f830112612c1a57600080fd5b81356020612c2782612a5a565b604051612c348282612a2e565b83815260059390931b8501820192828101915086841115612c5457600080fd5b8286015b84811015612c6f5780358352918301918301612c58565b509695505050505050565b600082601f830112612c8b57600080fd5b81356001600160401b03811115612ca457612ca46129f3565b604051612cbb601f8301601f191660200182612a2e565b818152846020838601011115612cd057600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215612d0557600080fd5b612d0e866128bc565b9450612d1c602087016128bc565b935060408601356001600160401b0380821115612d3857600080fd5b612d4489838a01612c09565b94506060880135915080821115612d5a57600080fd5b612d6689838a01612c09565b93506080880135915080821115612d7c57600080fd5b50612d8988828901612c7a565b9150509295509295909350565b600060208284031215612da857600080fd5b8135612935816129ae565b60008060408385031215612dc657600080fd5b82356001600160401b0380821115612ddd57600080fd5b818501915085601f830112612df157600080fd5b81356020612dfe82612a5a565b604051612e0b8282612a2e565b83815260059390931b8501820192828101915089841115612e2b57600080fd5b948201945b83861015612e5057612e41866128bc565b82529482019490820190612e30565b96505086013592505080821115612e6657600080fd5b50612e7385828601612c09565b9150509250929050565b600081518084526020808501945080840160005b83811015612ead57815187529582019590820190600101612e91565b509495945050505050565b6020815260006129356020830184612e7d565b600081518084526020808501945080840160005b83811015612ead578151805188528301518388015260409096019590820190600101612edf565b6020815260006129356020830184612ecb565b600080600060608486031215612f2e57600080fd5b612f37846128bc565b925060208401356001600160401b0380821115612f5357600080fd5b612f5f87838801612c09565b93506040860135915080821115612f7557600080fd5b50612f8286828701612c09565b9150509250925092565b600080600060608486031215612fa157600080fd5b8335925060208401356001600160401b03811115612fbe57600080fd5b840160808187031215612fd057600080fd5b91506040840135612fe0816129ae565b809150509250925092565b60008083601f840112612ffd57600080fd5b5081356001600160401b0381111561301457600080fd5b6020830191508360208260051b850101111561302f57600080fd5b9250929050565b6000806000806000806060878903121561304f57600080fd5b86356001600160401b038082111561306657600080fd5b6130728a838b01612feb565b9098509650602089013591508082111561308b57600080fd5b6130978a838b01612feb565b909650945060408901359150808211156130b057600080fd5b506130bd89828a01612feb565b979a9699509497509295939492505050565b604081528251604082015260208301516060820152600060408401516080808401526130fe60c0840182612ecb565b90506060850151603f198483030160a085015261311b8282612ecb565b9250505082151560208301529392505050565b6000806000806040858703121561314457600080fd5b84356001600160401b038082111561315b57600080fd5b61316788838901612feb565b9096509450602087013591508082111561318057600080fd5b5061318d87828801612feb565b95989497509550505050565b6000806000806000606086880312156131b157600080fd5b8535945060208601356001600160401b03808211156131cf57600080fd5b6131db89838a01612feb565b909650945060408801359150808211156131f457600080fd5b5061320188828901612feb565b969995985093965092949392505050565b6000806000806060858703121561322857600080fd5b8435935060208501356001600160401b038082111561324657600080fd5b818701915087601f83011261325a57600080fd5b81358181111561326957600080fd5b8860208260061b850101111561327e57600080fd5b6020830195508094505050506040850135613298816129ae565b939692955090935050565b600080604083850312156132b657600080fd5b6132bf836128bc565b91506132cd602084016128bc565b90509250929050565b600080600080600060a086880312156132ee57600080fd5b6132f7866128bc565b9450613305602087016128bc565b9350604086013592506060860135915060808601356001600160401b0381111561332e57600080fd5b612d8988828901612c7a565b600181811c9082168061334e57607f821691505b60208210810361336e57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016133b2576133b261338a565b5060010190565b6000602082840312156133cb57600080fd5b8151612935816129ae565b6000808335601e198436030181126133ed57600080fd5b8301803591506001600160401b0382111561340757600080fd5b6020019150600681901b360382131561302f57600080fd5b600160401b831115613433576134336129f3565b8054838255808410156134a15760016001600160ff1b03828116831461345b5761345b61338a565b808616861461346c5761346c61338a565b5060008381526020812086831b81019084841b015b8082101561349c578282558284830155600282019150613481565b505050505b5060008181526020812083915b858110156109a057823582556020830135600183015560409290920191600291909101906001016134ae565b813581556001602083013581830155600280830160406134fc818701876133d6565b600160401b811115613510576135106129f3565b83548185558082101561357a576001600160ff1b0381811682146135365761353661338a565b80831683146135475761354761338a565b5060008581526020812083891b810190838a1b015b8082101561357657828255828a830155888201915061355c565b5050505b50600093845260208420935b818110156135ab57823585556020830135600186015593850193918301918601613586565b505050505050506135bf60608301836133d6565b6117bd81836003860161341f565b6000808335601e198436030181126135e457600080fd5b8301803591506001600160401b038211156135fe57600080fd5b60200191503681900382131561302f57600080fd5b601f821115610cfd57600081815260208120601f850160051c8101602086101561363a5750805b601f850160051c820191505b818110156109a057828155600101613646565b81516001600160401b03811115613672576136726129f3565b61368681613680845461333a565b84613613565b602080601f8311600181146136bb57600084156136a35750858301515b600019600386901b1c1916600185901b1785556109a0565b600085815260208120601f198616915b828110156136ea578886015182559484019460019091019084016136cb565b50858210156137085787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156105d3576105d361338a565b634e487b7160e01b600052601260045260246000fd5b60008261375e57634e487b7160e01b600052601260045260246000fd5b500690565b6000816137725761377261338a565b506000190190565b60006040828403121561378c57600080fd5b6129358383612a7d565b60208082526023908201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260408201526265737360e81b606082015260800190565b60208082526024908201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604082015263616e636560e01b606082015260800190565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b60208082526028908201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206040820152670dad2e6dac2e8c6d60c31b606082015260800190565b6040815260006138c66040830185612e7d565b82810360208401526138d88185612e7d565b95945050505050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061391b9083018461293c565b979650505050505050565b60006020828403121561393857600080fd5b815161293581612902565b600060033d111561395c5760046000803e5060005160e01c5b90565b600060443d101561396d5790565b6040516003193d81016004833e81513d6001600160401b03816024840111818411171561399c57505050505090565b82850191508151818111156139b45750505050505090565b843d87010160208285010111156139ce5750505050505090565b6139dd60208286010187612a2e565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b6001600160a01b0386811682528516602082015260a060408201819052600090613aeb90830186612e7d565b8281036060840152613afd8186612e7d565b90508281036080840152613b11818561293c565b9897505050505050505056fea264697066735822122053e28f2fe0997046694d6721b3f38b5c4009c08b2490f2965ced52b2cb5d8d0864736f6c63430008110033

Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.