ETH Price: $3,401.28 (+2.15%)

Token

Coo Genesis (COO)
 

Overview

Max Total Supply

887 COO

Holders

691

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Filtered by Token Holder
0xhoss.eth
Balance
1 COO
0x547d7ef04c005a44a3cc89109d2cc78c85679586
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Carrier is a token and NFT cross-chain bridge built for Web 3 natives. It has several advanced features including concurrent transactions, robust wallet management and a fully functional keyboard interface.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
CooGenesis

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2023-04-18
*/

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol)

// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

/**
 * @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);
}

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

/**
 * @title Interface for CooGenesis ERC721 contract
 * @notice Defines the interface for the ERC721 contract, minting criteria object and the relevant methods.
 */

interface ICooGenesis is IERC721 {
    // === ERC721 ===

    /**
     * @return totalSupply - the number of NFTs minted by the contract
     */
    function totalSupply() external view returns (uint256);

    /**
     * @return maxSupply - the maximum number of NFTs can be minted by the contract
     */
    function maxSupply() external view returns (uint256);

    /**
     * @notice - Mints an NFT, as long as the current supply is less than {{ maxSupply }} and a valid Wormhole VAA is provided
     * @param encodedVm - Signed Wormhole VAA
     */
    function mint(bytes memory encodedVm) external;

    /**
     * @param owner - the address to query tokenId
     * @return tokenId - the tokenID that is owned by the provided address
     */
    function getTokenIdFromAddress(address owner) external view returns (uint256);

    // === MINTING LOGIC INTERFACE ===

    /**
     * @title Wormhole VAA Hash Criterion Definition
     * @notice This object defines the required criterion that the provided Wormhole VAA must meet, to become eligible for NFT Minting.
     * @param intervalBegin - The timestamp when the criterion begins to take effect. It must not be less than {{ startTime }}
     * @param luckyNumber - the numerator - controls magnitude
     * @param bitNum - the number of bits from the most right to match - controls granularity
     */
    struct HashCriterion {
        uint256 intervalBegin;
        uint256 luckyNumber;
        uint256 bitNum;
    }

    /**
     * Verifies minting eligibility for the given Wormhole VAA
     * Eligibility requirements:
     * 1. Wormhole Hash must match with the criterion defined based on the timestamp when the VAA has been produced
     * 2. A recipient is only eligible to mint 1 NFT at max
     * For off-chain calls, msgSender must be explicitly provided to verify for eligibility
     * @param encodedVm - The Wormhole VAA to be verified
     * @return to - eligible address
     */
    function isMintingEligible(bytes memory encodedVm) external view returns (address to);

    /**
     * @return criteria - A list of criteria that have been configured
     * @dev - It is recommended to only use this method for non state-changing functions
     * Otherwise, it may cost a significant amount of gas
     */
    function printAllCriteria() external view returns (HashCriterion[] memory);

    /**
     * @return startTime - Minting is allowed after this timestamp
     */
    function startTime() external view returns (uint256);

    /**
     * @return endTime - Minting is no longer allowed after this timestamp
     */
    function endTime() external view returns (uint256);
}

// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)

// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

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

// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.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;
    }
}

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

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

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `_msgSender()` is missing `role`.
     * Overriding this function changes the behavior of the {onlyRole} modifier.
     *
     * Format of the revert message is described in {_checkRole}.
     *
     * _Available since v4.6._
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(account),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * May emit a {RoleGranted} event.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol)

// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

/**
 * @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);
        }
    }
}

/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

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

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: address zero is not a valid owner");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _ownerOf(tokenId);
        require(owner != address(0), "ERC721: invalid token ID");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        _requireMinted(tokenId);

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overridden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not token owner or approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        _requireMinted(tokenId);

        return _tokenApprovals[tokenId];
    }

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

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

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
        _safeTransfer(from, to, tokenId, data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
     */
    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        return _owners[tokenId];
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _ownerOf(tokenId) != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId, 1);

        // Check that tokenId was not minted by `_beforeTokenTransfer` hook
        require(!_exists(tokenId), "ERC721: token already minted");

        unchecked {
            // Will not overflow unless all 2**256 token ids are minted to the same owner.
            // Given that tokens are minted one by one, it is impossible in practice that
            // this ever happens. Might change if we allow batch minting.
            // The ERC fails to describe this case.
            _balances[to] += 1;
        }

        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId, 1);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     * This is an internal function that does not check if the sender is authorized to operate on the token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId, 1);

        // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
        owner = ERC721.ownerOf(tokenId);

        // Clear approvals
        delete _tokenApprovals[tokenId];

        unchecked {
            // Cannot overflow, as that would require more tokens to be burned/transferred
            // out than the owner initially received through minting and transferring in.
            _balances[owner] -= 1;
        }
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId, 1);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId, 1);

        // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");

        // Clear approvals from the previous owner
        delete _tokenApprovals[tokenId];

        unchecked {
            // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
            // `from`'s balance is the number of token held, which is at least one before the current
            // transfer.
            // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
            // all 2**256 token ids to be minted, which in practice is impossible.
            _balances[from] -= 1;
            _balances[to] += 1;
        }
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId, 1);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits an {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @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, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Reverts if the `tokenId` has not been minted yet.
     */
    function _requireMinted(uint256 tokenId) internal view virtual {
        require(_exists(tokenId), "ERC721: invalid token ID");
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    /// @solidity memory-safe-assembly
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
     * - When `from` is zero, the tokens will be minted for `to`.
     * - When `to` is zero, ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     * - `batchSize` is non-zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256, /* firstTokenId */
        uint256 batchSize
    ) internal virtual {
        if (batchSize > 1) {
            if (from != address(0)) {
                _balances[from] -= batchSize;
            }
            if (to != address(0)) {
                _balances[to] += batchSize;
            }
        }
    }

    /**
     * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
     * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
     * - When `from` is zero, the tokens were minted for `to`.
     * - When `to` is zero, ``from``'s tokens were burned.
     * - `from` and `to` are never both zero.
     * - `batchSize` is non-zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 firstTokenId,
        uint256 batchSize
    ) internal virtual {}
}

// contracts/Messages.sol

interface IWormhole {
    struct GuardianSet {
        address[] keys;
        uint32 expirationTime;
    }

    struct Signature {
        bytes32 r;
        bytes32 s;
        uint8 v;
        uint8 guardianIndex;
    }

    struct VM {
        uint8 version;
        uint32 timestamp;
        uint32 nonce;
        uint16 emitterChainId;
        bytes32 emitterAddress;
        uint64 sequence;
        uint8 consistencyLevel;
        bytes payload;

        uint32 guardianSetIndex;
        Signature[] signatures;

        bytes32 hash;
    }

    struct ContractUpgrade {
        bytes32 module;
        uint8 action;
        uint16 chain;

        address newContract;
    }

    struct GuardianSetUpgrade {
        bytes32 module;
        uint8 action;
        uint16 chain;

        GuardianSet newGuardianSet;
        uint32 newGuardianSetIndex;
    }

    struct SetMessageFee {
        bytes32 module;
        uint8 action;
        uint16 chain;

        uint256 messageFee;
    }

    struct TransferFees {
        bytes32 module;
        uint8 action;
        uint16 chain;

        uint256 amount;
        bytes32 recipient;
    }

    struct RecoverChainId {
        bytes32 module;
        uint8 action;

        uint256 evmChainId;
        uint16 newChainId;
    }

    event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel);
    event ContractUpgraded(address indexed oldContract, address indexed newContract);
    event GuardianSetAdded(uint32 indexed index);

    function publishMessage(
        uint32 nonce,
        bytes memory payload,
        uint8 consistencyLevel
    ) external payable returns (uint64 sequence);

    function initialize() external;

    function parseAndVerifyVM(bytes calldata encodedVM) external view returns (VM memory vm, bool valid, string memory reason);

    function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);

    function verifySignatures(bytes32 hash, Signature[] memory signatures, GuardianSet memory guardianSet) external pure returns (bool valid, string memory reason);

    function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);

    function quorum(uint numGuardians) external pure returns (uint numSignaturesRequiredForQuorum);

    function getGuardianSet(uint32 index) external view returns (GuardianSet memory);

    function getCurrentGuardianSetIndex() external view returns (uint32);

    function getGuardianSetExpiry() external view returns (uint32);

    function governanceActionIsConsumed(bytes32 hash) external view returns (bool);

    function isInitialized(address impl) external view returns (bool);

    function chainId() external view returns (uint16);

    function isFork() external view returns (bool);

    function governanceChainId() external view returns (uint16);

    function governanceContract() external view returns (bytes32);

    function messageFee() external view returns (uint256);

    function evmChainId() external view returns (uint256);

    function nextSequence(address emitter) external view returns (uint64);

    function parseContractUpgrade(bytes memory encodedUpgrade) external pure returns (ContractUpgrade memory cu);

    function parseGuardianSetUpgrade(bytes memory encodedUpgrade) external pure returns (GuardianSetUpgrade memory gsu);

    function parseSetMessageFee(bytes memory encodedSetMessageFee) external pure returns (SetMessageFee memory smf);

    function parseTransferFees(bytes memory encodedTransferFees) external pure returns (TransferFees memory tf);

    function parseRecoverChainId(bytes memory encodedRecoverChainId) external pure returns (RecoverChainId memory rci);

    function submitContractUpgrade(bytes memory _vm) external;

    function submitSetMessageFee(bytes memory _vm) external;

    function submitNewGuardianSet(bytes memory _vm) external;

    function submitTransferFees(bytes memory _vm) external;

    function submitRecoverChainId(bytes memory _vm) external;
}

// contracts/Bridge.sol

// contracts/Bridge.sol

// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

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

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

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

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

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

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

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

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

interface IWETH is IERC20 {
    function deposit() external payable;
    function withdraw(uint amount) external;
}

interface ITokenBridge {
    struct Transfer {
        uint8 payloadID;
        uint256 amount;
        bytes32 tokenAddress;
        uint16 tokenChain;
        bytes32 to;
        uint16 toChain;
        uint256 fee;
    }

    struct TransferWithPayload {
        uint8 payloadID;
        uint256 amount;
        bytes32 tokenAddress;
        uint16 tokenChain;
        bytes32 to;
        uint16 toChain;
        bytes32 fromAddress;
        bytes payload;
    }

    struct AssetMeta {
        uint8 payloadID;
        bytes32 tokenAddress;
        uint16 tokenChain;
        uint8 decimals;
        bytes32 symbol;
        bytes32 name;
    }

    struct RegisterChain {
        bytes32 module;
        uint8 action;
        uint16 chainId;

        uint16 emitterChainID;
        bytes32 emitterAddress;
    }

     struct UpgradeContract {
        bytes32 module;
        uint8 action;
        uint16 chainId;

        bytes32 newContract;
    }

    struct RecoverChainId {
        bytes32 module;
        uint8 action;

        uint256 evmChainId;
        uint16 newChainId;
    }

    event ContractUpgraded(address indexed oldContract, address indexed newContract);

    function _parseTransferCommon(bytes memory encoded) external pure returns (Transfer memory transfer);

    function attestToken(address tokenAddress, uint32 nonce) external payable returns (uint64 sequence);

    function wrapAndTransferETH(uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce) external payable returns (uint64 sequence);

    function wrapAndTransferETHWithPayload(uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload) external payable returns (uint64 sequence);

    function transferTokens(address token, uint256 amount, uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce) external payable returns (uint64 sequence);

    function transferTokensWithPayload(address token, uint256 amount, uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload) external payable returns (uint64 sequence);

    function updateWrapped(bytes memory encodedVm) external returns (address token);

    function createWrapped(bytes memory encodedVm) external returns (address token);

    function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory);

    function completeTransferAndUnwrapETHWithPayload(bytes memory encodedVm) external returns (bytes memory);

    function completeTransfer(bytes memory encodedVm) external;

    function completeTransferAndUnwrapETH(bytes memory encodedVm) external;

    function encodeAssetMeta(AssetMeta memory meta) external pure returns (bytes memory encoded);

    function encodeTransfer(Transfer memory transfer) external pure returns (bytes memory encoded);

    function encodeTransferWithPayload(TransferWithPayload memory transfer) external pure returns (bytes memory encoded);

    function parsePayloadID(bytes memory encoded) external pure returns (uint8 payloadID);

    function parseAssetMeta(bytes memory encoded) external pure returns (AssetMeta memory meta);

    function parseTransfer(bytes memory encoded) external pure returns (Transfer memory transfer);

    function parseTransferWithPayload(bytes memory encoded) external pure returns (TransferWithPayload memory transfer);

    function governanceActionIsConsumed(bytes32 hash) external view returns (bool);

    function isInitialized(address impl) external view returns (bool);

    function isTransferCompleted(bytes32 hash) external view returns (bool);

    function wormhole() external view returns (IWormhole);

    function chainId() external view returns (uint16);

    function evmChainId() external view returns (uint256);

    function isFork() external view returns (bool);

    function governanceChainId() external view returns (uint16);

    function governanceContract() external view returns (bytes32);

    function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) external view returns (address);

    function bridgeContracts(uint16 chainId_) external view returns (bytes32);

    function tokenImplementation() external view returns (address);

    function WETH() external view returns (IWETH);

    function outstandingBridged(address token) external view returns (uint256);

    function isWrappedAsset(address token) external view returns (bool);

    function finality() external view returns (uint8);

    function implementation() external view returns (address);

    function initialize() external;

    function registerChain(bytes memory encodedVM) external;

    function upgrade(bytes memory encodedVM) external;

    function submitRecoverChainId(bytes memory encodedVM) external;

    function parseRegisterChain(bytes memory encoded) external pure returns (RegisterChain memory chain);

    function parseUpgrade(bytes memory encoded) external pure returns (UpgradeContract memory chain);

    function parseRecoverChainId(bytes memory encodedRecoverChainId) external pure returns (RecoverChainId memory rci);
}

// contracts/NFTBridge.sol

interface INFTBridge {
    struct Transfer {
        bytes32 tokenAddress;
        uint16 tokenChain;
        bytes32 symbol;
        bytes32 name;
        uint256 tokenID;
        string uri;
        bytes32 to;
        uint16 toChain;
    }

    struct SPLCache {
        bytes32 name;
        bytes32 symbol;
    }

     struct RegisterChain {
        bytes32 module;
        uint8 action;
        uint16 chainId;

        uint16 emitterChainID;
        bytes32 emitterAddress;
    }

    struct UpgradeContract {
        bytes32 module;
        uint8 action;
        uint16 chainId;

        bytes32 newContract;
    }

    struct RecoverChainId {
        bytes32 module;
        uint8 action;

        uint256 evmChainId;
        uint16 newChainId;
    }

    event ContractUpgraded(address indexed oldContract, address indexed newContract);

    function transferNFT(address token, uint256 tokenID, uint16 recipientChain, bytes32 recipient, uint32 nonce) external payable returns (uint64 sequence);

    function completeTransfer(bytes memory encodeVm) external;

    function encodeTransfer(Transfer memory transfer) external pure returns (bytes memory encoded);

    function parseTransfer(bytes memory encoded) external pure returns (Transfer memory transfer);

    function onERC721Received(address operator, address, uint256, bytes calldata) external view returns (bytes4);

    function governanceActionIsConsumed(bytes32 hash) external view returns (bool);

    function isInitialized(address impl) external view returns (bool);

    function isTransferCompleted(bytes32 hash) external view returns (bool);

    function wormhole() external view returns (IWormhole);

    function chainId() external view returns (uint16);

    function evmChainId() external view returns (uint256);

    function isFork() external view returns (bool);

    function governanceChainId() external view returns (uint16);

    function governanceContract() external view returns (bytes32);

    function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) external view returns (address);

    function bridgeContracts(uint16 chainId_) external view returns (bytes32);

    function tokenImplementation() external view returns (address);

    function isWrappedAsset(address token) external view returns (bool);

    function splCache(uint256 tokenId) external view returns (SPLCache memory);

    function finality() external view returns (uint8);

    function initialize() external;

    function implementation() external view returns (address);

    function registerChain(bytes memory encodedVM) external;

    function upgrade(bytes memory encodedVM) external;

    function submitRecoverChainId(bytes memory encodedVM) external;

    function parseRegisterChain(bytes memory encoded) external pure returns(RegisterChain memory chain);

    function parseUpgrade(bytes memory encoded) external pure returns(UpgradeContract memory chain);

    function parseRecoverChainId(bytes memory encodedRecoverChainId) external pure returns (RecoverChainId memory rci);
}

contract CooGenesis is AccessControl, ERC721, ICooGenesis {
    enum BridgeType {
        UNDEFINED,
        TOKEN,
        NFT
    }

    // === STORAGE ===

    IWormhole immutable wormhole;
    ITokenBridge immutable tokenBridge;
    INFTBridge immutable nftBridge;

    // === Activity Info ===
    uint256 public override startTime;
    uint256 public override endTime;

    //criteria
    HashCriterion[] private _criteria;

    // === ERC721 Token Info ===
    uint256 private _mintedPublic;
    uint256 private _mintedReserve;
    uint256 private _mintedL2;
    uint256 private _resMax;
    uint256 private _pubMax;
    string private _uri;
    uint256 public override maxSupply;
    mapping(address => uint256) private _publicMintRecipientToTokenId;
    mapping(address => uint256) private _l2MintRecipientToTokenId;

    //keccak256("L2_Authority")
    bytes32 public constant L2_ROLLUP_ROLE = 0x87bf82161f347912a342aa475f2fa76a12e8d59a43bda030a18194c8375a4760;

    constructor(
        address _wormhole,
        address _tokenBridge,
        address _nftBridge,
        uint256 _maxSupply,
        uint256 _reserveMax,
        uint256 _publicMax,
        uint256 _start,
        uint256 _end,
        string memory name,
        string memory symbol,
        string memory _baseUri
    ) ERC721(name, symbol) {
        require(_reserveMax <= _maxSupply, "reserveMax cannot be greater than max");
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        wormhole = IWormhole(_wormhole);
        tokenBridge = ITokenBridge(_tokenBridge);
        nftBridge = INFTBridge(_nftBridge);
        _uri = _baseUri;
        maxSupply = _maxSupply;
        _resMax = _reserveMax;
        _pubMax = _publicMax;
        _setStartAndEndTime(_start, _end);
    }

    function _baseURI() internal view override returns (string memory) {
        return _uri;
    }

    function totalSupply() public view override returns (uint256) {
        return _mintedPublic + _mintedReserve + _mintedL2;
    }

    function getTokenIdFromAddress(address owner) external view override returns (uint256) {
        return _publicMintRecipientToTokenId[owner];
    }

    function getL2TokenIdFromAddress(address owner) external view returns (uint256) {
        return _l2MintRecipientToTokenId[owner];
    }

    function isMintingEligible(bytes memory encodedVm) public view override returns (address to) {
        // parse the VAA
        (IWormhole.VM memory parsedVm, bool valid, string memory reason) = wormhole.parseAndVerifyVM(encodedVm);
        if (!valid) {
            revert(reason);
        }

        bool currentTimeIsValid = parsedVm.timestamp >= startTime && parsedVm.timestamp < endTime;
        if (!currentTimeIsValid) {
            revert("current time is invalid");
        }

        // verify source emitter and isTransferCompleted
        BridgeType bridge = _getBridgeFromEmitter(parsedVm.emitterChainId, parsedVm.emitterAddress);
        if (bridge == BridgeType.UNDEFINED) {
            revert("bridge undefined");
        } else {
            bool completed = bridge == BridgeType.TOKEN
                ? tokenBridge.isTransferCompleted(parsedVm.hash)
                : nftBridge.isTransferCompleted(parsedVm.hash);
            require(completed, "asset has not completed transfer");
        }

        // get the current criterion
        HashCriterion memory criterion = _getValidCriterion(parsedVm.timestamp);
        bool matched = _isMatching(parsedVm.hash, criterion.luckyNumber, criterion.bitNum);
        if (!matched) {
            revert("provided hash does not satisfy criterion");
        }

        // get recipient
        to = _getTransferRecipient(bridge, parsedVm.payload);
        require(_publicMintRecipientToTokenId[to] == 0 && to != address(0), "invalid recipient");
    }

    function publicMintAvailable() external view returns (bool) {
        return _mintedPublic < _pubMax;
    }

    function mintInternal(address recipient, uint256 tokenID) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(tokenID <= _resMax && tokenID > 0, "invalid reserve token id");
        require(++_mintedReserve <= _resMax, "internal supply exceeds max");
        _safeMint(recipient, tokenID);
    }

    function mintL2(address recipient, uint256 tokenID) external onlyRole(L2_ROLLUP_ROLE) {
        uint256 resMax = _resMax;
        uint256 publicMax = _pubMax;
        uint256 maxSupplyMem = maxSupply;
        require(recipient != address(0), "invalid recipient");
        require(tokenID > resMax + publicMax && tokenID <= maxSupplyMem, "invalid l2 token id");
        require(++_mintedL2 <= maxSupplyMem - resMax - publicMax, "l2 supply exceeds max");
        require(_l2MintRecipientToTokenId[recipient] == 0, "l2 recipient already has token");

        _l2MintRecipientToTokenId[recipient] = tokenID;
        _safeMint(recipient, tokenID);
    }

    function mint(bytes memory encodedVm) external override {
        uint256 mintedPublic = _mintedPublic + 1;
        require(mintedPublic <= _pubMax, "public supply exceeds max");
        address to = isMintingEligible(encodedVm);
        uint256 current = _resMax + mintedPublic;
        _publicMintRecipientToTokenId[to] = current;
        _mintedPublic = mintedPublic;
        _safeMint(to, current);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(AccessControl, ERC721, IERC165)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function addCriterion(uint256 luckyNumber, uint256 numOfBits) external onlyRole(DEFAULT_ADMIN_ROLE) {
        _addCriterion(luckyNumber, numOfBits);
    }

    function updatePublicMax(uint256 newPublicMax) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(_mintedPublic <= newPublicMax, "cannot reduce max below current minted");
        require(_resMax + newPublicMax <= maxSupply, "exceed max supply");
        _pubMax = newPublicMax;
    }

    // If 2 criteria are added in the same block, the first one will be useless
    function _addCriterion(uint256 luckyNumber, uint256 numOfBits) internal {
        require(numOfBits > 0, "Patterns cannot be empty");
        require(luckyNumber < 2 ** numOfBits, "luckyNumber out of range");

        if (block.timestamp < startTime) {
            _criteria[0].intervalBegin = startTime;
            _criteria[0].luckyNumber = luckyNumber;
            _criteria[0].bitNum = numOfBits;
        } else {
            HashCriterion memory criterion = HashCriterion({
                intervalBegin: _criteria.length == 0 ? startTime : block.timestamp,
                luckyNumber: luckyNumber,
                bitNum: numOfBits
            });
            _criteria.push(criterion);
        }
    }

    function printAllCriteria() external view returns (HashCriterion[] memory) {
        return _criteria;
    }

    function updateStartAndEndTime(uint256 _start, uint256 _end) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (block.timestamp < startTime) {
            _setStartAndEndTime(_start, _end);
            //Update the startTime of the first criterion
            _criteria[0].intervalBegin = _start;
        } else {
            //Do not allow startTime to be updated if the current time is after the startTime
            _setStartAndEndTime(startTime, _end);
        }
    }

    function _safeMint(address to, uint256 tokenId) internal override {
        require(totalSupply() <= maxSupply, "totalSupply > maxSupply");
        super._safeMint(to, tokenId);
    }

    function _setStartAndEndTime(uint256 _start, uint256 _end) private {
        require(_end > _start, "endTime < startTime");
        startTime = _start;
        endTime = _end;
    }

    function _getValidCriterion(uint256 timestamp) private view returns (HashCriterion memory) {
        for (uint256 i = _criteria.length - 1; i >= 0; i--) {
            HashCriterion memory criterion = _criteria[i];
            if (criterion.intervalBegin <= timestamp) {
                return criterion;
            }
        }
        // This should never happen, otherwise it means something is wrong
        revert("no valid criterion");
    }

    function _generateMask(uint256 bitNum) private pure returns (bytes32 mask) {
        require(bitNum > 0 && bitNum <= 32, "invalid bidNum");
        mask = bytes32(uint256(2 ** bitNum) - 1);
    }

    function _isMatching(bytes32 hash, uint256 luckyNumber, uint256 numOfBits) private pure returns (bool) {
        bytes32 mask = _generateMask(numOfBits);
        uint256 res = uint256(hash & mask);
        return (res <= luckyNumber);
    }

    function _getBridgeFromEmitter(uint16 sourceChain, bytes32 sourceEmitter) private view returns (BridgeType) {
        bool isTokenBridge = tokenBridge.bridgeContracts(sourceChain) == sourceEmitter
            || address(uint160(uint256(sourceEmitter))) == address(tokenBridge);
        if (isTokenBridge) {
            return BridgeType.TOKEN;
        }

        bool isNFTBridge = nftBridge.bridgeContracts(sourceChain) == sourceEmitter
            || address(uint160(uint256(sourceEmitter))) == address(nftBridge);
        if (isNFTBridge) {
            return BridgeType.NFT;
        }

        return BridgeType.UNDEFINED;
    }

    function _getTransferRecipient(BridgeType bridge, bytes memory encoded) private pure returns (address to) {
        bytes32 padded;
        if (bridge == BridgeType.TOKEN) {
            // 67 is the start of the `to` field in the TransferWithPayload struct
            uint256 toStartIndex = 67;
            require(encoded.length >= toStartIndex + 32, "invalid payload");
            assembly {
                padded := mload(add(add(encoded, 0x20), toStartIndex))
            }
        } else if (bridge == BridgeType.NFT) {
            uint256 toStartIndex = encoded.length - 34;
            assembly {
                // 67 is the start of the `to` field in the TransferWithPayload struct
                padded := mload(add(add(encoded, 0x20), toStartIndex))
            }
        }
        if (padded != bytes32(0)) {
            to = address(uint160(uint256(padded)));
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_wormhole","type":"address"},{"internalType":"address","name":"_tokenBridge","type":"address"},{"internalType":"address","name":"_nftBridge","type":"address"},{"internalType":"uint256","name":"_maxSupply","type":"uint256"},{"internalType":"uint256","name":"_reserveMax","type":"uint256"},{"internalType":"uint256","name":"_publicMax","type":"uint256"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"_baseUri","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","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":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2_ROLLUP_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"luckyNumber","type":"uint256"},{"internalType":"uint256","name":"numOfBits","type":"uint256"}],"name":"addCriterion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getL2TokenIdFromAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getTokenIdFromAddress","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedVm","type":"bytes"}],"name":"isMintingEligible","outputs":[{"internalType":"address","name":"to","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedVm","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"mintInternal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"mintL2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"printAllCriteria","outputs":[{"components":[{"internalType":"uint256","name":"intervalBegin","type":"uint256"},{"internalType":"uint256","name":"luckyNumber","type":"uint256"},{"internalType":"uint256","name":"bitNum","type":"uint256"}],"internalType":"struct ICooGenesis.HashCriterion[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMintAvailable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","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":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","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":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPublicMax","type":"uint256"}],"name":"updatePublicMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_end","type":"uint256"}],"name":"updateStartAndEndTime","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b50604051620036ae380380620036ae8339810160408190526200003491620003bf565b8251839083906200004d9060019060208501906200022f565b508051620000639060029060208401906200022f565b50505087871115620000ca5760405162461bcd60e51b815260206004820152602560248201527f726573657276654d61782063616e6e6f742062652067726561746572207468616044820152640dc40dac2f60db1b60648201526084015b60405180910390fd5b620000d760003362000132565b6001600160a01b03808c166080528a811660a052891660c05280516200010590600f9060208401906200022f565b506010889055600d879055600e869055620001218585620001d3565b505050505050505050505062000506565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001cf576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200018e3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b818111620002245760405162461bcd60e51b815260206004820152601360248201527f656e6454696d65203c20737461727454696d65000000000000000000000000006044820152606401620000c1565b600791909155600855565b8280546200023d90620004c9565b90600052602060002090601f016020900481019282620002615760008555620002ac565b82601f106200027c57805160ff1916838001178555620002ac565b82800160010185558215620002ac579182015b82811115620002ac5782518255916020019190600101906200028f565b50620002ba929150620002be565b5090565b5b80821115620002ba5760008155600101620002bf565b80516001600160a01b0381168114620002ed57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200031a57600080fd5b81516001600160401b0380821115620003375762000337620002f2565b604051601f8301601f19908116603f01168101908282118183101715620003625762000362620002f2565b816040528381526020925086838588010111156200037f57600080fd5b600091505b83821015620003a3578582018301518183018401529082019062000384565b83821115620003b55760008385830101525b9695505050505050565b60008060008060008060008060008060006101608c8e031215620003e257600080fd5b620003ed8c620002d5565b9a50620003fd60208d01620002d5565b99506200040d60408d01620002d5565b985060608c0151975060808c0151965060a08c0151955060c08c0151945060e08c015193506101008c015160018060401b038111156200044c57600080fd5b6200045a8e828f0162000308565b6101208e015190945090506001600160401b038111156200047a57600080fd5b620004888e828f0162000308565b6101408e015190935090506001600160401b03811115620004a857600080fd5b620004b68e828f0162000308565b9150509295989b509295989b9093969950565b600181811c90821680620004de57607f821691505b602082108114156200050057634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05161315c6200055260003960008181610d8901528181611afc0152611b7f015260008181610e2d01528181611a0a0152611a8d01526000610bab015261315c6000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c806378e9792511610125578063b747172a116100ad578063d4d92b141161007c578063d4d92b1414610491578063d547741f146104a4578063d5abeb01146104b7578063e985e9c5146104c0578063ed88ecac146104fc57600080fd5b8063b747172a1461042f578063b88d4fde14610442578063bf11bf6c14610455578063c87b56dd1461047e57600080fd5b806395d89b41116100f457806395d89b41146103e4578063a217fddf146103ec578063a22cb465146103f4578063a73d62cb14610407578063b479cb661461041c57600080fd5b806378e97925146103a25780637ba0e2e7146103ab5780637c05f811146103be57806391d14854146103d157600080fd5b80632ed3916b116101a857806342842e0e1161017757806342842e0e1461034a578063450da31d1461035d5780634671bb74146103695780636352211e1461037c57806370a082311461038f57600080fd5b80632ed3916b146103085780632f2ff15d1461031b5780633197cbb61461032e57806336568abe1461033757600080fd5b8063095ea7b3116101e4578063095ea7b3146102b557806318160ddd146102ca57806323b872dd146102d2578063248a9ca3146102e557600080fd5b806301ffc9a7146102165780630206e70b1461023e57806306fdde0314610275578063081812fc1461028a575b600080fd5b610229610224366004612661565b610523565b60405190151581526020015b60405180910390f35b61026761024c36600461269a565b6001600160a01b031660009081526011602052604090205490565b604051908152602001610235565b61027d610534565b604051610235919061270d565b61029d610298366004612720565b6105c6565b6040516001600160a01b039091168152602001610235565b6102c86102c3366004612739565b6105ed565b005b610267610708565b6102c86102e0366004612763565b61072c565b6102676102f3366004612720565b60009081526020819052604090206001015490565b6102c861031636600461279f565b61075d565b6102c86103293660046127c1565b610772565b61026760085481565b6102c86103453660046127c1565b610797565b6102c8610358366004612763565b610815565b600e54600a5410610229565b6102c8610377366004612739565b610830565b61029d61038a366004612720565b610a09565b61026761039d36600461269a565b610a69565b61026760075481565b6102c86103b93660046128ff565b610aef565b61029d6103cc3660046128ff565b610ba3565b6102296103df3660046127c1565b61101b565b61027d611044565b610267600081565b6102c8610402366004612942565b611053565b61040f61105e565b6040516102359190612979565b6102c861042a36600461279f565b6110db565b6102c861043d366004612720565b611131565b6102c86104503660046129d2565b6111f6565b61026761046336600461269a565b6001600160a01b031660009081526012602052604090205490565b61027d61048c366004612720565b611228565b6102c861049f366004612739565b61128f565b6102c86104b23660046127c1565b611367565b61026760105481565b6102296104ce366004612a3a565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b6102677f87bf82161f347912a342aa475f2fa76a12e8d59a43bda030a18194c8375a476081565b600061052e8261138c565b92915050565b60606001805461054390612a64565b80601f016020809104026020016040519081016040528092919081815260200182805461056f90612a64565b80156105bc5780601f10610591576101008083540402835291602001916105bc565b820191906000526020600020905b81548152906001019060200180831161059f57829003601f168201915b5050505050905090565b60006105d1826113cc565b506000908152600560205260409020546001600160a01b031690565b60006105f882610a09565b9050806001600160a01b0316836001600160a01b0316141561066b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610687575061068781336104ce565b6106f95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610662565b610703838361142e565b505050565b6000600c54600b54600a5461071d9190612ab5565b6107279190612ab5565b905090565b610736338261149c565b6107525760405162461bcd60e51b815260040161066290612acd565b61070383838361151b565b60006107688161168c565b6107038383611696565b60008281526020819052604090206001015461078d8161168c565b6107038383611896565b6001600160a01b03811633146108075760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610662565b610811828261191a565b5050565b610703838383604051806020016040528060008152506111f6565b7f87bf82161f347912a342aa475f2fa76a12e8d59a43bda030a18194c8375a476061085a8161168c565b600d54600e546010546001600160a01b0386166108ad5760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c9958da5c1a595b9d607a1b6044820152606401610662565b6108b78284612ab5565b851180156108c55750808511155b6109075760405162461bcd60e51b81526020600482015260136024820152721a5b9d985b1a59081b0c881d1bdad95b881a59606a1b6044820152606401610662565b816109128483612b1a565b61091c9190612b1a565b600c6000815461092b90612b31565b918290555011156109765760405162461bcd60e51b81526020600482015260156024820152740d86440e6eae0e0d8f240caf0c6cacac8e640dac2f605b1b6044820152606401610662565b6001600160a01b038616600090815260126020526040902054156109dc5760405162461bcd60e51b815260206004820152601e60248201527f6c3220726563697069656e7420616c72656164792068617320746f6b656e00006044820152606401610662565b6001600160a01b0386166000908152601260205260409020859055610a01868661197f565b505050505050565b6000818152600360205260408120546001600160a01b03168061052e5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610662565b60006001600160a01b038216610ad35760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610662565b506001600160a01b031660009081526004602052604090205490565b6000600a546001610b009190612ab5565b9050600e54811115610b545760405162461bcd60e51b815260206004820152601960248201527f7075626c696320737570706c792065786365656473206d6178000000000000006044820152606401610662565b6000610b5f83610ba3565b9050600082600d54610b719190612ab5565b6001600160a01b0383166000908152601160205260409020819055600a8490559050610b9d828261197f565b50505050565b6000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c0fd8bde866040518263ffffffff1660e01b8152600401610bf5919061270d565b60006040518083038186803b158015610c0d57600080fd5b505afa158015610c21573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c499190810190612cb1565b92509250925081610c6e578060405162461bcd60e51b8152600401610662919061270d565b6000600754846020015163ffffffff1610158015610c975750600854846020015163ffffffff16105b905080610ce65760405162461bcd60e51b815260206004820152601760248201527f63757272656e742074696d6520697320696e76616c69640000000000000000006044820152606401610662565b6000610cfa856060015186608001516119e2565b90506000816002811115610d1057610d10612e09565b1415610d515760405162461bcd60e51b815260206004820152601060248201526f189c9a5919d9481d5b9919599a5b995960821b6044820152606401610662565b60006001826002811115610d6757610d67612e09565b14610e105761014086015160405163aa4efa5b60e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aa4efa5b9060240160206040518083038186803b158015610dd357600080fd5b505afa158015610de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0b9190612e1f565b610eaf565b61014086015160405163aa4efa5b60e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063aa4efa5b9060240160206040518083038186803b158015610e7757600080fd5b505afa158015610e8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eaf9190612e1f565b905080610efe5760405162461bcd60e51b815260206004820181905260248201527f617373657420686173206e6f7420636f6d706c65746564207472616e736665726044820152606401610662565b506000610f14866020015163ffffffff16611bd4565b90506000610f3087610140015183602001518460400151611c80565b905080610f905760405162461bcd60e51b815260206004820152602860248201527f70726f7669646564206861736820646f6573206e6f74207361746973667920636044820152673934ba32b934b7b760c11b6064820152608401610662565b610f9e838860e00151611c9a565b6001600160a01b038116600090815260116020526040902054909850158015610fcf57506001600160a01b03881615155b61100f5760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c9958da5c1a595b9d607a1b6044820152606401610662565b50505050505050919050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606002805461054390612a64565b610811338383611d58565b60606009805480602002602001604051908101604052809291908181526020016000905b828210156110d25783829060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505081526020019060010190611082565b50505050905090565b60006110e68161168c565b600754421015611125576110fa8383611e27565b82600960008154811061110f5761110f612e3c565b6000918252602090912060039091020155505050565b61070360075483611e27565b600061113c8161168c565b81600a54111561119d5760405162461bcd60e51b815260206004820152602660248201527f63616e6e6f7420726564756365206d61782062656c6f772063757272656e74206044820152651b5a5b9d195960d21b6064820152608401610662565b60105482600d546111ae9190612ab5565b11156111f05760405162461bcd60e51b8152602060048201526011602482015270657863656564206d617820737570706c7960781b6044820152606401610662565b50600e55565b611200338361149c565b61121c5760405162461bcd60e51b815260040161066290612acd565b610b9d84848484611e77565b6060611233826113cc565b600061123d611eaa565b9050600081511161125d5760405180602001604052806000815250611288565b8061126784611eb9565b604051602001611278929190612e52565b6040516020818303038152906040525b9392505050565b600061129a8161168c565b600d5482111580156112ac5750600082115b6112f85760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964207265736572766520746f6b656e20696400000000000000006044820152606401610662565b600d54600b6000815461130a90612b31565b9182905550111561135d5760405162461bcd60e51b815260206004820152601b60248201527f696e7465726e616c20737570706c792065786365656473206d617800000000006044820152606401610662565b610703838361197f565b6000828152602081905260409020600101546113828161168c565b610703838361191a565b60006001600160e01b031982166380ac58cd60e01b14806113bd57506001600160e01b03198216635b5e139f60e01b145b8061052e575061052e82611f56565b6000818152600360205260409020546001600160a01b031661142b5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610662565b50565b600081815260056020526040902080546001600160a01b0319166001600160a01b038416908117909155819061146382610a09565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000806114a883610a09565b9050806001600160a01b0316846001600160a01b031614806114ef57506001600160a01b0380821660009081526006602090815260408083209388168352929052205460ff165b806115135750836001600160a01b0316611508846105c6565b6001600160a01b0316145b949350505050565b826001600160a01b031661152e82610a09565b6001600160a01b0316146115545760405162461bcd60e51b815260040161066290612e81565b6001600160a01b0382166115b65760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610662565b6115c38383836001611f8b565b826001600160a01b03166115d682610a09565b6001600160a01b0316146115fc5760405162461bcd60e51b815260040161066290612e81565b600081815260056020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260048552838620805460001901905590871680865283862080546001019055868652600390945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61142b8133612013565b600081116116e65760405162461bcd60e51b815260206004820152601860248201527f5061747465726e732063616e6e6f7420626520656d70747900000000000000006044820152606401610662565b6116f1816002612faa565b821061173f5760405162461bcd60e51b815260206004820152601860248201527f6c75636b794e756d626572206f7574206f662072616e676500000000000000006044820152606401610662565b6007544210156117cd57600754600960008154811061176057611760612e3c565b90600052602060002090600302016000018190555081600960008154811061178a5761178a612e3c565b9060005260206000209060030201600101819055508060096000815481106117b4576117b4612e3c565b9060005260206000209060030201600201819055505050565b600060405180606001604052806009805490506000146117ed57426117f1565b6007545b81526020808201869052604091820185905260098054600181018255600091909152835160039091027f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af810191909155908301517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b08201559101517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b190910155505050565b6118a0828261101b565b610811576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556118d63390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b611924828261101b565b15610811576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60105461198a610708565b11156119d85760405162461bcd60e51b815260206004820152601760248201527f746f74616c537570706c79203e206d6178537570706c790000000000000000006044820152606401610662565b610811828261206c565b60405163ad66a5f160e01b815261ffff83166004820152600090819083906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ad66a5f19060240160206040518083038186803b158015611a4c57600080fd5b505afa158015611a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a849190612fb6565b1480611ac457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168360001c6001600160a01b0316145b90508015611ad657600191505061052e565b60405163ad66a5f160e01b815261ffff8516600482015260009084906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ad66a5f19060240160206040518083038186803b158015611b3e57600080fd5b505afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612fb6565b1480611bb657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168460001c6001600160a01b0316145b90508015611bc95760029250505061052e565b506000949350505050565b611bf860405180606001604052806000815260200160008152602001600081525090565b600954600090611c0a90600190612b1a565b90505b600060098281548110611c2257611c22612e3c565b90600052602060002090600302016040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816000015111611c6d579392505050565b5080611c7881612fcf565b915050611c0d565b600080611c8c83612086565b909416909210159392505050565b6000806001846002811115611cb157611cb1612e09565b1415611d13576043611cc4816020612ab5565b84511015611d065760405162461bcd60e51b815260206004820152600f60248201526e1a5b9d985b1a59081c185e5b1bd859608a1b6044820152606401610662565b8301602001519050611d47565b6002846002811115611d2757611d27612e09565b1415611d4757600060228451611d3d9190612b1a565b8401602001519150505b8015611d51579050805b5092915050565b816001600160a01b0316836001600160a01b03161415611dba5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610662565b6001600160a01b03838116600081815260066020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b818111611e6c5760405162461bcd60e51b8152602060048201526013602482015272656e6454696d65203c20737461727454696d6560681b6044820152606401610662565b600791909155600855565b611e8284848461151b565b611e8e848484846120ec565b610b9d5760405162461bcd60e51b815260040161066290612fe6565b6060600f805461054390612a64565b60606000611ec6836121f9565b600101905060008167ffffffffffffffff811115611ee657611ee66127ed565b6040519080825280601f01601f191660200182016040528015611f10576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611f4957611f4e565b611f1a565b509392505050565b60006001600160e01b03198216637965db0b60e01b148061052e57506301ffc9a760e01b6001600160e01b031983161461052e565b6001811115610b9d576001600160a01b03841615611fd1576001600160a01b03841660009081526004602052604081208054839290611fcb908490612b1a565b90915550505b6001600160a01b03831615610b9d576001600160a01b03831660009081526004602052604081208054839290612008908490612ab5565b909155505050505050565b61201d828261101b565b6108115761202a816122d1565b6120358360206122e3565b604051602001612046929190613038565b60408051601f198184030181529082905262461bcd60e51b82526106629160040161270d565b61081182826040518060200160405280600081525061247f565b60008082118015612098575060208211155b6120d55760405162461bcd60e51b815260206004820152600e60248201526d696e76616c6964206269644e756d60901b6044820152606401610662565b60016120e2836002612faa565b61052e9190612b1a565b60006001600160a01b0384163b156121ee57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906121309033908990889088906004016130ad565b602060405180830381600087803b15801561214a57600080fd5b505af192505050801561217a575060408051601f3d908101601f19168201909252612177918101906130ea565b60015b6121d4573d8080156121a8576040519150601f19603f3d011682016040523d82523d6000602084013e6121ad565b606091505b5080516121cc5760405162461bcd60e51b815260040161066290612fe6565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611513565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106122385772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612264576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061228257662386f26fc10000830492506010015b6305f5e100831061229a576305f5e100830492506008015b61271083106122ae57612710830492506004015b606483106122c0576064830492506002015b600a831061052e5760010192915050565b606061052e6001600160a01b03831660145b606060006122f2836002613107565b6122fd906002612ab5565b67ffffffffffffffff811115612315576123156127ed565b6040519080825280601f01601f19166020018201604052801561233f576020820181803683370190505b509050600360fc1b8160008151811061235a5761235a612e3c565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061238957612389612e3c565b60200101906001600160f81b031916908160001a90535060006123ad846002613107565b6123b8906001612ab5565b90505b6001811115612430576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106123ec576123ec612e3c565b1a60f81b82828151811061240257612402612e3c565b60200101906001600160f81b031916908160001a90535060049490941c9361242981612fcf565b90506123bb565b5083156112885760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610662565b61248983836124b2565b61249660008484846120ec565b6107035760405162461bcd60e51b815260040161066290612fe6565b6001600160a01b0382166125085760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610662565b6000818152600360205260409020546001600160a01b03161561256d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610662565b61257b600083836001611f8b565b6000818152600360205260409020546001600160a01b0316156125e05760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610662565b6001600160a01b038216600081815260046020908152604080832080546001019055848352600390915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160e01b03198116811461142b57600080fd5b60006020828403121561267357600080fd5b81356112888161264b565b80356001600160a01b038116811461269557600080fd5b919050565b6000602082840312156126ac57600080fd5b6112888261267e565b60005b838110156126d05781810151838201526020016126b8565b83811115610b9d5750506000910152565b600081518084526126f98160208601602086016126b5565b601f01601f19169290920160200192915050565b60208152600061128860208301846126e1565b60006020828403121561273257600080fd5b5035919050565b6000806040838503121561274c57600080fd5b6127558361267e565b946020939093013593505050565b60008060006060848603121561277857600080fd5b6127818461267e565b925061278f6020850161267e565b9150604084013590509250925092565b600080604083850312156127b257600080fd5b50508035926020909101359150565b600080604083850312156127d457600080fd5b823591506127e46020840161267e565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715612826576128266127ed565b60405290565b604051610160810167ffffffffffffffff81118282101715612826576128266127ed565b604051601f8201601f1916810167ffffffffffffffff81118282101715612879576128796127ed565b604052919050565b600067ffffffffffffffff82111561289b5761289b6127ed565b50601f01601f191660200190565b600082601f8301126128ba57600080fd5b81356128cd6128c882612881565b612850565b8181528460208386010111156128e257600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561291157600080fd5b813567ffffffffffffffff81111561292857600080fd5b611513848285016128a9565b801515811461142b57600080fd5b6000806040838503121561295557600080fd5b61295e8361267e565b9150602083013561296e81612934565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156129c55781518051855286810151878601528501518585015260609093019290850190600101612996565b5091979650505050505050565b600080600080608085870312156129e857600080fd5b6129f18561267e565b93506129ff6020860161267e565b925060408501359150606085013567ffffffffffffffff811115612a2257600080fd5b612a2e878288016128a9565b91505092959194509250565b60008060408385031215612a4d57600080fd5b612a568361267e565b91506127e46020840161267e565b600181811c90821680612a7857607f821691505b60208210811415612a9957634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612ac857612ac8612a9f565b500190565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b600082821015612b2c57612b2c612a9f565b500390565b6000600019821415612b4557612b45612a9f565b5060010190565b805160ff8116811461269557600080fd5b805163ffffffff8116811461269557600080fd5b805161ffff8116811461269557600080fd5b805167ffffffffffffffff8116811461269557600080fd5b600082601f830112612bac57600080fd5b8151612bba6128c882612881565b818152846020838601011115612bcf57600080fd5b6115138260208301602087016126b5565b600082601f830112612bf157600080fd5b8151602067ffffffffffffffff821115612c0d57612c0d6127ed565b612c1b818360051b01612850565b82815260079290921b84018101918181019086841115612c3a57600080fd5b8286015b84811015612c9b5760808189031215612c575760008081fd5b612c5f612803565b8151815284820151858201526040612c78818401612b4c565b908201526060612c89838201612b4c565b90820152835291830191608001612c3e565b509695505050505050565b805161269581612934565b600080600060608486031215612cc657600080fd5b835167ffffffffffffffff80821115612cde57600080fd5b908501906101608288031215612cf357600080fd5b612cfb61282c565b612d0483612b4c565b8152612d1260208401612b5d565b6020820152612d2360408401612b5d565b6040820152612d3460608401612b71565b606082015260808301516080820152612d4f60a08401612b83565b60a0820152612d6060c08401612b4c565b60c082015260e083015182811115612d7757600080fd5b612d8389828601612b9b565b60e083015250610100612d97818501612b5d565b908201526101208381015183811115612daf57600080fd5b612dbb8a828701612be0565b918301919091525061014083810151908201529450612ddc60208701612ca6565b93506040860151915080821115612df257600080fd5b50612dff86828701612b9b565b9150509250925092565b634e487b7160e01b600052602160045260246000fd5b600060208284031215612e3157600080fd5b815161128881612934565b634e487b7160e01b600052603260045260246000fd5b60008351612e648184602088016126b5565b835190830190612e788183602088016126b5565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b600181815b80851115612f01578160001904821115612ee757612ee7612a9f565b80851615612ef457918102915b93841c9390800290612ecb565b509250929050565b600082612f185750600161052e565b81612f255750600061052e565b8160018114612f3b5760028114612f4557612f61565b600191505061052e565b60ff841115612f5657612f56612a9f565b50506001821b61052e565b5060208310610133831016604e8410600b8410161715612f84575081810a61052e565b612f8e8383612ec6565b8060001904821115612fa257612fa2612a9f565b029392505050565b60006112888383612f09565b600060208284031215612fc857600080fd5b5051919050565b600081612fde57612fde612a9f565b506000190190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516130708160178501602088016126b5565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516130a18160288401602088016126b5565b01602801949350505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906130e0908301846126e1565b9695505050505050565b6000602082840312156130fc57600080fd5b81516112888161264b565b600081600019048311821515161561312157613121612a9f565b50029056fea26469706673582212202a9df8a93f387568118176b4a3866ad044ecbc1d09b6bfd47c0291981220142e64736f6c6343000809003300000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa5850000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe00000000000000000000000000000000000000000000000000000000000004bc0000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000643fd7c00000000000000000000000000000000000000000000000000000000064524cc0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000b436f6f2047656e657369730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003434f4f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f626166796265696636346a7776656b777a61336f72733433373770686a68776165676570377336677269687936636566356b72336a7266376e73612f0000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102115760003560e01c806378e9792511610125578063b747172a116100ad578063d4d92b141161007c578063d4d92b1414610491578063d547741f146104a4578063d5abeb01146104b7578063e985e9c5146104c0578063ed88ecac146104fc57600080fd5b8063b747172a1461042f578063b88d4fde14610442578063bf11bf6c14610455578063c87b56dd1461047e57600080fd5b806395d89b41116100f457806395d89b41146103e4578063a217fddf146103ec578063a22cb465146103f4578063a73d62cb14610407578063b479cb661461041c57600080fd5b806378e97925146103a25780637ba0e2e7146103ab5780637c05f811146103be57806391d14854146103d157600080fd5b80632ed3916b116101a857806342842e0e1161017757806342842e0e1461034a578063450da31d1461035d5780634671bb74146103695780636352211e1461037c57806370a082311461038f57600080fd5b80632ed3916b146103085780632f2ff15d1461031b5780633197cbb61461032e57806336568abe1461033757600080fd5b8063095ea7b3116101e4578063095ea7b3146102b557806318160ddd146102ca57806323b872dd146102d2578063248a9ca3146102e557600080fd5b806301ffc9a7146102165780630206e70b1461023e57806306fdde0314610275578063081812fc1461028a575b600080fd5b610229610224366004612661565b610523565b60405190151581526020015b60405180910390f35b61026761024c36600461269a565b6001600160a01b031660009081526011602052604090205490565b604051908152602001610235565b61027d610534565b604051610235919061270d565b61029d610298366004612720565b6105c6565b6040516001600160a01b039091168152602001610235565b6102c86102c3366004612739565b6105ed565b005b610267610708565b6102c86102e0366004612763565b61072c565b6102676102f3366004612720565b60009081526020819052604090206001015490565b6102c861031636600461279f565b61075d565b6102c86103293660046127c1565b610772565b61026760085481565b6102c86103453660046127c1565b610797565b6102c8610358366004612763565b610815565b600e54600a5410610229565b6102c8610377366004612739565b610830565b61029d61038a366004612720565b610a09565b61026761039d36600461269a565b610a69565b61026760075481565b6102c86103b93660046128ff565b610aef565b61029d6103cc3660046128ff565b610ba3565b6102296103df3660046127c1565b61101b565b61027d611044565b610267600081565b6102c8610402366004612942565b611053565b61040f61105e565b6040516102359190612979565b6102c861042a36600461279f565b6110db565b6102c861043d366004612720565b611131565b6102c86104503660046129d2565b6111f6565b61026761046336600461269a565b6001600160a01b031660009081526012602052604090205490565b61027d61048c366004612720565b611228565b6102c861049f366004612739565b61128f565b6102c86104b23660046127c1565b611367565b61026760105481565b6102296104ce366004612a3a565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205460ff1690565b6102677f87bf82161f347912a342aa475f2fa76a12e8d59a43bda030a18194c8375a476081565b600061052e8261138c565b92915050565b60606001805461054390612a64565b80601f016020809104026020016040519081016040528092919081815260200182805461056f90612a64565b80156105bc5780601f10610591576101008083540402835291602001916105bc565b820191906000526020600020905b81548152906001019060200180831161059f57829003601f168201915b5050505050905090565b60006105d1826113cc565b506000908152600560205260409020546001600160a01b031690565b60006105f882610a09565b9050806001600160a01b0316836001600160a01b0316141561066b5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b0382161480610687575061068781336104ce565b6106f95760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152608401610662565b610703838361142e565b505050565b6000600c54600b54600a5461071d9190612ab5565b6107279190612ab5565b905090565b610736338261149c565b6107525760405162461bcd60e51b815260040161066290612acd565b61070383838361151b565b60006107688161168c565b6107038383611696565b60008281526020819052604090206001015461078d8161168c565b6107038383611896565b6001600160a01b03811633146108075760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610662565b610811828261191a565b5050565b610703838383604051806020016040528060008152506111f6565b7f87bf82161f347912a342aa475f2fa76a12e8d59a43bda030a18194c8375a476061085a8161168c565b600d54600e546010546001600160a01b0386166108ad5760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c9958da5c1a595b9d607a1b6044820152606401610662565b6108b78284612ab5565b851180156108c55750808511155b6109075760405162461bcd60e51b81526020600482015260136024820152721a5b9d985b1a59081b0c881d1bdad95b881a59606a1b6044820152606401610662565b816109128483612b1a565b61091c9190612b1a565b600c6000815461092b90612b31565b918290555011156109765760405162461bcd60e51b81526020600482015260156024820152740d86440e6eae0e0d8f240caf0c6cacac8e640dac2f605b1b6044820152606401610662565b6001600160a01b038616600090815260126020526040902054156109dc5760405162461bcd60e51b815260206004820152601e60248201527f6c3220726563697069656e7420616c72656164792068617320746f6b656e00006044820152606401610662565b6001600160a01b0386166000908152601260205260409020859055610a01868661197f565b505050505050565b6000818152600360205260408120546001600160a01b03168061052e5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610662565b60006001600160a01b038216610ad35760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152608401610662565b506001600160a01b031660009081526004602052604090205490565b6000600a546001610b009190612ab5565b9050600e54811115610b545760405162461bcd60e51b815260206004820152601960248201527f7075626c696320737570706c792065786365656473206d6178000000000000006044820152606401610662565b6000610b5f83610ba3565b9050600082600d54610b719190612ab5565b6001600160a01b0383166000908152601160205260409020819055600a8490559050610b9d828261197f565b50505050565b6000806000807f00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b6001600160a01b031663c0fd8bde866040518263ffffffff1660e01b8152600401610bf5919061270d565b60006040518083038186803b158015610c0d57600080fd5b505afa158015610c21573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610c499190810190612cb1565b92509250925081610c6e578060405162461bcd60e51b8152600401610662919061270d565b6000600754846020015163ffffffff1610158015610c975750600854846020015163ffffffff16105b905080610ce65760405162461bcd60e51b815260206004820152601760248201527f63757272656e742074696d6520697320696e76616c69640000000000000000006044820152606401610662565b6000610cfa856060015186608001516119e2565b90506000816002811115610d1057610d10612e09565b1415610d515760405162461bcd60e51b815260206004820152601060248201526f189c9a5919d9481d5b9919599a5b995960821b6044820152606401610662565b60006001826002811115610d6757610d67612e09565b14610e105761014086015160405163aa4efa5b60e01b815260048101919091527f0000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe6001600160a01b03169063aa4efa5b9060240160206040518083038186803b158015610dd357600080fd5b505afa158015610de7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0b9190612e1f565b610eaf565b61014086015160405163aa4efa5b60e01b815260048101919091527f0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa5856001600160a01b03169063aa4efa5b9060240160206040518083038186803b158015610e7757600080fd5b505afa158015610e8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eaf9190612e1f565b905080610efe5760405162461bcd60e51b815260206004820181905260248201527f617373657420686173206e6f7420636f6d706c65746564207472616e736665726044820152606401610662565b506000610f14866020015163ffffffff16611bd4565b90506000610f3087610140015183602001518460400151611c80565b905080610f905760405162461bcd60e51b815260206004820152602860248201527f70726f7669646564206861736820646f6573206e6f74207361746973667920636044820152673934ba32b934b7b760c11b6064820152608401610662565b610f9e838860e00151611c9a565b6001600160a01b038116600090815260116020526040902054909850158015610fcf57506001600160a01b03881615155b61100f5760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c9958da5c1a595b9d607a1b6044820152606401610662565b50505050505050919050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60606002805461054390612a64565b610811338383611d58565b60606009805480602002602001604051908101604052809291908181526020016000905b828210156110d25783829060005260206000209060030201604051806060016040529081600082015481526020016001820154815260200160028201548152505081526020019060010190611082565b50505050905090565b60006110e68161168c565b600754421015611125576110fa8383611e27565b82600960008154811061110f5761110f612e3c565b6000918252602090912060039091020155505050565b61070360075483611e27565b600061113c8161168c565b81600a54111561119d5760405162461bcd60e51b815260206004820152602660248201527f63616e6e6f7420726564756365206d61782062656c6f772063757272656e74206044820152651b5a5b9d195960d21b6064820152608401610662565b60105482600d546111ae9190612ab5565b11156111f05760405162461bcd60e51b8152602060048201526011602482015270657863656564206d617820737570706c7960781b6044820152606401610662565b50600e55565b611200338361149c565b61121c5760405162461bcd60e51b815260040161066290612acd565b610b9d84848484611e77565b6060611233826113cc565b600061123d611eaa565b9050600081511161125d5760405180602001604052806000815250611288565b8061126784611eb9565b604051602001611278929190612e52565b6040516020818303038152906040525b9392505050565b600061129a8161168c565b600d5482111580156112ac5750600082115b6112f85760405162461bcd60e51b815260206004820152601860248201527f696e76616c6964207265736572766520746f6b656e20696400000000000000006044820152606401610662565b600d54600b6000815461130a90612b31565b9182905550111561135d5760405162461bcd60e51b815260206004820152601b60248201527f696e7465726e616c20737570706c792065786365656473206d617800000000006044820152606401610662565b610703838361197f565b6000828152602081905260409020600101546113828161168c565b610703838361191a565b60006001600160e01b031982166380ac58cd60e01b14806113bd57506001600160e01b03198216635b5e139f60e01b145b8061052e575061052e82611f56565b6000818152600360205260409020546001600160a01b031661142b5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b6044820152606401610662565b50565b600081815260056020526040902080546001600160a01b0319166001600160a01b038416908117909155819061146382610a09565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000806114a883610a09565b9050806001600160a01b0316846001600160a01b031614806114ef57506001600160a01b0380821660009081526006602090815260408083209388168352929052205460ff165b806115135750836001600160a01b0316611508846105c6565b6001600160a01b0316145b949350505050565b826001600160a01b031661152e82610a09565b6001600160a01b0316146115545760405162461bcd60e51b815260040161066290612e81565b6001600160a01b0382166115b65760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608401610662565b6115c38383836001611f8b565b826001600160a01b03166115d682610a09565b6001600160a01b0316146115fc5760405162461bcd60e51b815260040161066290612e81565b600081815260056020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260048552838620805460001901905590871680865283862080546001019055868652600390945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b61142b8133612013565b600081116116e65760405162461bcd60e51b815260206004820152601860248201527f5061747465726e732063616e6e6f7420626520656d70747900000000000000006044820152606401610662565b6116f1816002612faa565b821061173f5760405162461bcd60e51b815260206004820152601860248201527f6c75636b794e756d626572206f7574206f662072616e676500000000000000006044820152606401610662565b6007544210156117cd57600754600960008154811061176057611760612e3c565b90600052602060002090600302016000018190555081600960008154811061178a5761178a612e3c565b9060005260206000209060030201600101819055508060096000815481106117b4576117b4612e3c565b9060005260206000209060030201600201819055505050565b600060405180606001604052806009805490506000146117ed57426117f1565b6007545b81526020808201869052604091820185905260098054600181018255600091909152835160039091027f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af810191909155908301517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b08201559101517f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7b190910155505050565b6118a0828261101b565b610811576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556118d63390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b611924828261101b565b15610811576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60105461198a610708565b11156119d85760405162461bcd60e51b815260206004820152601760248201527f746f74616c537570706c79203e206d6178537570706c790000000000000000006044820152606401610662565b610811828261206c565b60405163ad66a5f160e01b815261ffff83166004820152600090819083906001600160a01b037f0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585169063ad66a5f19060240160206040518083038186803b158015611a4c57600080fd5b505afa158015611a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a849190612fb6565b1480611ac457507f0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa5856001600160a01b03168360001c6001600160a01b0316145b90508015611ad657600191505061052e565b60405163ad66a5f160e01b815261ffff8516600482015260009084906001600160a01b037f0000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe169063ad66a5f19060240160206040518083038186803b158015611b3e57600080fd5b505afa158015611b52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b769190612fb6565b1480611bb657507f0000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe6001600160a01b03168460001c6001600160a01b0316145b90508015611bc95760029250505061052e565b506000949350505050565b611bf860405180606001604052806000815260200160008152602001600081525090565b600954600090611c0a90600190612b1a565b90505b600060098281548110611c2257611c22612e3c565b90600052602060002090600302016040518060600160405290816000820154815260200160018201548152602001600282015481525050905083816000015111611c6d579392505050565b5080611c7881612fcf565b915050611c0d565b600080611c8c83612086565b909416909210159392505050565b6000806001846002811115611cb157611cb1612e09565b1415611d13576043611cc4816020612ab5565b84511015611d065760405162461bcd60e51b815260206004820152600f60248201526e1a5b9d985b1a59081c185e5b1bd859608a1b6044820152606401610662565b8301602001519050611d47565b6002846002811115611d2757611d27612e09565b1415611d4757600060228451611d3d9190612b1a565b8401602001519150505b8015611d51579050805b5092915050565b816001600160a01b0316836001600160a01b03161415611dba5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610662565b6001600160a01b03838116600081815260066020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b818111611e6c5760405162461bcd60e51b8152602060048201526013602482015272656e6454696d65203c20737461727454696d6560681b6044820152606401610662565b600791909155600855565b611e8284848461151b565b611e8e848484846120ec565b610b9d5760405162461bcd60e51b815260040161066290612fe6565b6060600f805461054390612a64565b60606000611ec6836121f9565b600101905060008167ffffffffffffffff811115611ee657611ee66127ed565b6040519080825280601f01601f191660200182016040528015611f10576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611f4957611f4e565b611f1a565b509392505050565b60006001600160e01b03198216637965db0b60e01b148061052e57506301ffc9a760e01b6001600160e01b031983161461052e565b6001811115610b9d576001600160a01b03841615611fd1576001600160a01b03841660009081526004602052604081208054839290611fcb908490612b1a565b90915550505b6001600160a01b03831615610b9d576001600160a01b03831660009081526004602052604081208054839290612008908490612ab5565b909155505050505050565b61201d828261101b565b6108115761202a816122d1565b6120358360206122e3565b604051602001612046929190613038565b60408051601f198184030181529082905262461bcd60e51b82526106629160040161270d565b61081182826040518060200160405280600081525061247f565b60008082118015612098575060208211155b6120d55760405162461bcd60e51b815260206004820152600e60248201526d696e76616c6964206269644e756d60901b6044820152606401610662565b60016120e2836002612faa565b61052e9190612b1a565b60006001600160a01b0384163b156121ee57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906121309033908990889088906004016130ad565b602060405180830381600087803b15801561214a57600080fd5b505af192505050801561217a575060408051601f3d908101601f19168201909252612177918101906130ea565b60015b6121d4573d8080156121a8576040519150601f19603f3d011682016040523d82523d6000602084013e6121ad565b606091505b5080516121cc5760405162461bcd60e51b815260040161066290612fe6565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611513565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106122385772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612264576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061228257662386f26fc10000830492506010015b6305f5e100831061229a576305f5e100830492506008015b61271083106122ae57612710830492506004015b606483106122c0576064830492506002015b600a831061052e5760010192915050565b606061052e6001600160a01b03831660145b606060006122f2836002613107565b6122fd906002612ab5565b67ffffffffffffffff811115612315576123156127ed565b6040519080825280601f01601f19166020018201604052801561233f576020820181803683370190505b509050600360fc1b8160008151811061235a5761235a612e3c565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061238957612389612e3c565b60200101906001600160f81b031916908160001a90535060006123ad846002613107565b6123b8906001612ab5565b90505b6001811115612430576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106123ec576123ec612e3c565b1a60f81b82828151811061240257612402612e3c565b60200101906001600160f81b031916908160001a90535060049490941c9361242981612fcf565b90506123bb565b5083156112885760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610662565b61248983836124b2565b61249660008484846120ec565b6107035760405162461bcd60e51b815260040161066290612fe6565b6001600160a01b0382166125085760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610662565b6000818152600360205260409020546001600160a01b03161561256d5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610662565b61257b600083836001611f8b565b6000818152600360205260409020546001600160a01b0316156125e05760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610662565b6001600160a01b038216600081815260046020908152604080832080546001019055848352600390915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6001600160e01b03198116811461142b57600080fd5b60006020828403121561267357600080fd5b81356112888161264b565b80356001600160a01b038116811461269557600080fd5b919050565b6000602082840312156126ac57600080fd5b6112888261267e565b60005b838110156126d05781810151838201526020016126b8565b83811115610b9d5750506000910152565b600081518084526126f98160208601602086016126b5565b601f01601f19169290920160200192915050565b60208152600061128860208301846126e1565b60006020828403121561273257600080fd5b5035919050565b6000806040838503121561274c57600080fd5b6127558361267e565b946020939093013593505050565b60008060006060848603121561277857600080fd5b6127818461267e565b925061278f6020850161267e565b9150604084013590509250925092565b600080604083850312156127b257600080fd5b50508035926020909101359150565b600080604083850312156127d457600080fd5b823591506127e46020840161267e565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715612826576128266127ed565b60405290565b604051610160810167ffffffffffffffff81118282101715612826576128266127ed565b604051601f8201601f1916810167ffffffffffffffff81118282101715612879576128796127ed565b604052919050565b600067ffffffffffffffff82111561289b5761289b6127ed565b50601f01601f191660200190565b600082601f8301126128ba57600080fd5b81356128cd6128c882612881565b612850565b8181528460208386010111156128e257600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561291157600080fd5b813567ffffffffffffffff81111561292857600080fd5b611513848285016128a9565b801515811461142b57600080fd5b6000806040838503121561295557600080fd5b61295e8361267e565b9150602083013561296e81612934565b809150509250929050565b602080825282518282018190526000919060409081850190868401855b828110156129c55781518051855286810151878601528501518585015260609093019290850190600101612996565b5091979650505050505050565b600080600080608085870312156129e857600080fd5b6129f18561267e565b93506129ff6020860161267e565b925060408501359150606085013567ffffffffffffffff811115612a2257600080fd5b612a2e878288016128a9565b91505092959194509250565b60008060408385031215612a4d57600080fd5b612a568361267e565b91506127e46020840161267e565b600181811c90821680612a7857607f821691505b60208210811415612a9957634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612ac857612ac8612a9f565b500190565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b600082821015612b2c57612b2c612a9f565b500390565b6000600019821415612b4557612b45612a9f565b5060010190565b805160ff8116811461269557600080fd5b805163ffffffff8116811461269557600080fd5b805161ffff8116811461269557600080fd5b805167ffffffffffffffff8116811461269557600080fd5b600082601f830112612bac57600080fd5b8151612bba6128c882612881565b818152846020838601011115612bcf57600080fd5b6115138260208301602087016126b5565b600082601f830112612bf157600080fd5b8151602067ffffffffffffffff821115612c0d57612c0d6127ed565b612c1b818360051b01612850565b82815260079290921b84018101918181019086841115612c3a57600080fd5b8286015b84811015612c9b5760808189031215612c575760008081fd5b612c5f612803565b8151815284820151858201526040612c78818401612b4c565b908201526060612c89838201612b4c565b90820152835291830191608001612c3e565b509695505050505050565b805161269581612934565b600080600060608486031215612cc657600080fd5b835167ffffffffffffffff80821115612cde57600080fd5b908501906101608288031215612cf357600080fd5b612cfb61282c565b612d0483612b4c565b8152612d1260208401612b5d565b6020820152612d2360408401612b5d565b6040820152612d3460608401612b71565b606082015260808301516080820152612d4f60a08401612b83565b60a0820152612d6060c08401612b4c565b60c082015260e083015182811115612d7757600080fd5b612d8389828601612b9b565b60e083015250610100612d97818501612b5d565b908201526101208381015183811115612daf57600080fd5b612dbb8a828701612be0565b918301919091525061014083810151908201529450612ddc60208701612ca6565b93506040860151915080821115612df257600080fd5b50612dff86828701612b9b565b9150509250925092565b634e487b7160e01b600052602160045260246000fd5b600060208284031215612e3157600080fd5b815161128881612934565b634e487b7160e01b600052603260045260246000fd5b60008351612e648184602088016126b5565b835190830190612e788183602088016126b5565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b600181815b80851115612f01578160001904821115612ee757612ee7612a9f565b80851615612ef457918102915b93841c9390800290612ecb565b509250929050565b600082612f185750600161052e565b81612f255750600061052e565b8160018114612f3b5760028114612f4557612f61565b600191505061052e565b60ff841115612f5657612f56612a9f565b50506001821b61052e565b5060208310610133831016604e8410600b8410161715612f84575081810a61052e565b612f8e8383612ec6565b8060001904821115612fa257612fa2612a9f565b029392505050565b60006112888383612f09565b600060208284031215612fc857600080fd5b5051919050565b600081612fde57612fde612a9f565b506000190190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516130708160178501602088016126b5565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516130a18160288401602088016126b5565b01602801949350505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906130e0908301846126e1565b9695505050505050565b6000602082840312156130fc57600080fd5b81516112888161264b565b600081600019048311821515161561312157613121612a9f565b50029056fea26469706673582212202a9df8a93f387568118176b4a3866ad044ecbc1d09b6bfd47c0291981220142e64736f6c63430008090033

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

00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa5850000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe00000000000000000000000000000000000000000000000000000000000004bc0000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000643fd7c00000000000000000000000000000000000000000000000000000000064524cc0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000000b436f6f2047656e657369730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003434f4f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f626166796265696636346a7776656b777a61336f72733433373770686a68776165676570377336677269687936636566356b72336a7266376e73612f0000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _wormhole (address): 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B
Arg [1] : _tokenBridge (address): 0x3ee18B2214AFF97000D974cf647E7C347E8fa585
Arg [2] : _nftBridge (address): 0x6FFd7EdE62328b3Af38FCD61461Bbfc52F5651fE
Arg [3] : _maxSupply (uint256): 1212
Arg [4] : _reserveMax (uint256): 112
Arg [5] : _publicMax (uint256): 600
Arg [6] : _start (uint256): 1681905600
Arg [7] : _end (uint256): 1683115200
Arg [8] : name (string): Coo Genesis
Arg [9] : symbol (string): COO
Arg [10] : _baseUri (string): ipfs://bafybeif64jwvekwza3ors4377phjhwaegep7s6grihy6cef5kr3jrf7nsa/

-----Encoded View---------------
19 Constructor Arguments found :
Arg [0] : 00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b
Arg [1] : 0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585
Arg [2] : 0000000000000000000000006ffd7ede62328b3af38fcd61461bbfc52f5651fe
Arg [3] : 00000000000000000000000000000000000000000000000000000000000004bc
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000070
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000258
Arg [6] : 00000000000000000000000000000000000000000000000000000000643fd7c0
Arg [7] : 0000000000000000000000000000000000000000000000000000000064524cc0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [9] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [10] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [11] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [12] : 436f6f2047656e65736973000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [14] : 434f4f0000000000000000000000000000000000000000000000000000000000
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000043
Arg [16] : 697066733a2f2f626166796265696636346a7776656b777a61336f7273343337
Arg [17] : 3770686a68776165676570377336677269687936636566356b72336a7266376e
Arg [18] : 73612f0000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

80407:10434:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85850:218;;;;;;:::i;:::-;;:::i;:::-;;;565:14:1;;558:22;540:41;;528:2;513:18;85850:218:0;;;;;;;;82477:149;;;;;;:::i;:::-;-1:-1:-1;;;;;82582:36:0;82555:7;82582:36;;;:29;:36;;;;;;;82477:149;;;;1107:25:1;;;1095:2;1080:18;82477:149:0;961:177:1;49890:100:0;;;:::i;:::-;;;;;;;:::i;51402:171::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;2243:32:1;;;2225:51;;2213:2;2198:18;51402:171:0;2079:203:1;50920:416:0;;;;;;:::i;:::-;;:::i;:::-;;82339:130;;;:::i;52102:335::-;;;;;;:::i;:::-;;:::i;32809:131::-;;;;;;:::i;:::-;32883:7;32910:12;;;;;;;;;;:22;;;;32809:131;86076:156;;;;;;:::i;:::-;;:::i;33250:147::-;;;;;;:::i;:::-;;:::i;80764:31::-;;;;;;34394:218;;;;;;:::i;:::-;;:::i;52508:185::-;;;;;;:::i;:::-;;:::i;84331:109::-;84425:7;;84409:13;;:23;84331:109;;84759:659;;;;;;:::i;:::-;;:::i;49600:223::-;;;;;;:::i;:::-;;:::i;49331:207::-;;;;;;:::i;:::-;;:::i;80724:33::-;;;;;;85426:416;;;;;;:::i;:::-;;:::i;82780:1543::-;;;;;;:::i;:::-;;:::i;31282:147::-;;;;;;:::i;:::-;;:::i;50059:104::-;;;:::i;30387:49::-;;30432:4;30387:49;;51645:155;;;;;;:::i;:::-;;:::i;87356:110::-;;;:::i;:::-;;;;;;;:::i;87474:483::-;;;;;;:::i;:::-;;:::i;86240:293::-;;;;;;:::i;:::-;;:::i;52764:322::-;;;;;;:::i;:::-;;:::i;82634:138::-;;;;;;:::i;:::-;-1:-1:-1;;;;;82732:32:0;82705:7;82732:32;;;:25;:32;;;;;;;82634:138;50234:281;;;;;;:::i;:::-;;:::i;84448:303::-;;;;;;:::i;:::-;;:::i;33690:149::-;;;;;;:::i;:::-;;:::i;81087:33::-;;;;;;51871:164;;;;;;:::i;:::-;-1:-1:-1;;;;;51992:25:0;;;51968:4;51992:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;51871:164;81302:107;;81343:66;81302:107;;85850:218;85995:4;86024:36;86048:11;86024:23;:36::i;:::-;86017:43;85850:218;-1:-1:-1;;85850:218:0:o;49890:100::-;49944:13;49977:5;49970:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49890:100;:::o;51402:171::-;51478:7;51498:23;51513:7;51498:14;:23::i;:::-;-1:-1:-1;51541:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;51541:24:0;;51402:171::o;50920:416::-;51001:13;51017:23;51032:7;51017:14;:23::i;:::-;51001:39;;51065:5;-1:-1:-1;;;;;51059:11:0;:2;-1:-1:-1;;;;;51059:11:0;;;51051:57;;;;-1:-1:-1;;;51051:57:0;;8366:2:1;51051:57:0;;;8348:21:1;8405:2;8385:18;;;8378:30;8444:34;8424:18;;;8417:62;-1:-1:-1;;;8495:18:1;;;8488:31;8536:19;;51051:57:0;;;;;;;;;12491:10;-1:-1:-1;;;;;51143:21:0;;;;:62;;-1:-1:-1;51168:37:0;51185:5;12491:10;51871:164;:::i;51168:37::-;51121:173;;;;-1:-1:-1;;;51121:173:0;;8768:2:1;51121:173:0;;;8750:21:1;8807:2;8787:18;;;8780:30;8846:34;8826:18;;;8819:62;8917:31;8897:18;;;8890:59;8966:19;;51121:173:0;8566:425:1;51121:173:0;51307:21;51316:2;51320:7;51307:8;:21::i;:::-;50990:346;50920:416;;:::o;82339:130::-;82392:7;82452:9;;82435:14;;82419:13;;:30;;;;:::i;:::-;:42;;;;:::i;:::-;82412:49;;82339:130;:::o;52102:335::-;52297:41;12491:10;52330:7;52297:18;:41::i;:::-;52289:99;;;;-1:-1:-1;;;52289:99:0;;;;;;;:::i;:::-;52401:28;52411:4;52417:2;52421:7;52401:9;:28::i;86076:156::-;30432:4;30878:16;30432:4;30878:10;:16::i;:::-;86187:37:::1;86201:11;86214:9;86187:13;:37::i;33250:147::-:0;32883:7;32910:12;;;;;;;;;;:22;;;30878:16;30889:4;30878:10;:16::i;:::-;33364:25:::1;33375:4;33381:7;33364:10;:25::i;34394:218::-:0;-1:-1:-1;;;;;34490:23:0;;12491:10;34490:23;34482:83;;;;-1:-1:-1;;;34482:83:0;;9877:2:1;34482:83:0;;;9859:21:1;9916:2;9896:18;;;9889:30;9955:34;9935:18;;;9928:62;-1:-1:-1;;;10006:18:1;;;9999:45;10061:19;;34482:83:0;9675:411:1;34482:83:0;34578:26;34590:4;34596:7;34578:11;:26::i;:::-;34394:218;;:::o;52508:185::-;52646:39;52663:4;52669:2;52673:7;52646:39;;;;;;;;;;;;:16;:39::i;84759:659::-;81343:66;30878:16;81343:66;30878:10;:16::i;:::-;84873:7:::1;::::0;84911::::1;::::0;84952:9:::1;::::0;-1:-1:-1;;;;;84980:23:0;::::1;84972:53;;;::::0;-1:-1:-1;;;84972:53:0;;10293:2:1;84972:53:0::1;::::0;::::1;10275:21:1::0;10332:2;10312:18;;;10305:30;-1:-1:-1;;;10351:18:1;;;10344:47;10408:18;;84972:53:0::1;10091:341:1::0;84972:53:0::1;85054:18;85063:9:::0;85054:6;:18:::1;:::i;:::-;85044:7;:28;:55;;;;;85087:12;85076:7;:23;;85044:55;85036:87;;;::::0;-1:-1:-1;;;85036:87:0;;10639:2:1;85036:87:0::1;::::0;::::1;10621:21:1::0;10678:2;10658:18;;;10651:30;-1:-1:-1;;;10697:18:1;;;10690:49;10756:18;;85036:87:0::1;10437:343:1::0;85036:87:0::1;85181:9:::0;85157:21:::1;85172:6:::0;85157:12;:21:::1;:::i;:::-;:33;;;;:::i;:::-;85144:9;;85142:11;;;;;:::i;:::-;::::0;;;;-1:-1:-1;85142:48:0::1;;85134:82;;;::::0;-1:-1:-1;;;85134:82:0;;11257:2:1;85134:82:0::1;::::0;::::1;11239:21:1::0;11296:2;11276:18;;;11269:30;-1:-1:-1;;;11315:18:1;;;11308:51;11376:18;;85134:82:0::1;11055:345:1::0;85134:82:0::1;-1:-1:-1::0;;;;;85235:36:0;::::1;;::::0;;;:25:::1;:36;::::0;;;;;:41;85227:84:::1;;;::::0;-1:-1:-1;;;85227:84:0;;11607:2:1;85227:84:0::1;::::0;::::1;11589:21:1::0;11646:2;11626:18;;;11619:30;11685:32;11665:18;;;11658:60;11735:18;;85227:84:0::1;11405:354:1::0;85227:84:0::1;-1:-1:-1::0;;;;;85324:36:0;::::1;;::::0;;;:25:::1;:36;::::0;;;;:46;;;85381:29:::1;85350:9:::0;85363:7;85381:9:::1;:29::i;:::-;84845:573;;;84759:659:::0;;;:::o;49600:223::-;49672:7;54487:16;;;:7;:16;;;;;;-1:-1:-1;;;;;54487:16:0;;49736:56;;;;-1:-1:-1;;;49736:56:0;;11966:2:1;49736:56:0;;;11948:21:1;12005:2;11985:18;;;11978:30;-1:-1:-1;;;12024:18:1;;;12017:54;12088:18;;49736:56:0;11764:348:1;49331:207:0;49403:7;-1:-1:-1;;;;;49431:19:0;;49423:73;;;;-1:-1:-1;;;49423:73:0;;12319:2:1;49423:73:0;;;12301:21:1;12358:2;12338:18;;;12331:30;12397:34;12377:18;;;12370:62;-1:-1:-1;;;12448:18:1;;;12441:39;12497:19;;49423:73:0;12117:405:1;49423:73:0;-1:-1:-1;;;;;;49514:16:0;;;;;:9;:16;;;;;;;49331:207::o;85426:416::-;85493:20;85516:13;;85532:1;85516:17;;;;:::i;:::-;85493:40;;85568:7;;85552:12;:23;;85544:61;;;;-1:-1:-1;;;85544:61:0;;12729:2:1;85544:61:0;;;12711:21:1;12768:2;12748:18;;;12741:30;12807:27;12787:18;;;12780:55;12852:18;;85544:61:0;12527:349:1;85544:61:0;85616:10;85629:28;85647:9;85629:17;:28::i;:::-;85616:41;;85668:15;85696:12;85686:7;;:22;;;;:::i;:::-;-1:-1:-1;;;;;85719:33:0;;;;;;:29;:33;;;;;:43;;;85773:13;:28;;;85668:40;-1:-1:-1;85812:22:0;85749:2;85668:40;85812:9;:22::i;:::-;85482:360;;;85426:416;:::o;82780:1543::-;82861:10;82911:28;82941:10;82953:20;82977:8;-1:-1:-1;;;;;82977:25:0;;83003:9;82977:36;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;82977:36:0;;;;;;;;;;;;:::i;:::-;82910:103;;;;;;83029:5;83024:53;;83058:6;83051:14;;-1:-1:-1;;;83051:14:0;;;;;;;;:::i;83024:53::-;83089:23;83137:9;;83115:8;:18;;;:31;;;;:63;;;;;83171:7;;83150:8;:18;;;:28;;;83115:63;83089:89;;83194:18;83189:85;;83229:33;;-1:-1:-1;;;83229:33:0;;17532:2:1;83229:33:0;;;17514:21:1;17571:2;17551:18;;;17544:30;17610:25;17590:18;;;17583:53;17653:18;;83229:33:0;17330:347:1;83189:85:0;83344:17;83364:71;83386:8;:23;;;83411:8;:23;;;83364:21;:71::i;:::-;83344:91;-1:-1:-1;83460:20:0;83450:6;:30;;;;;;;;:::i;:::-;;83446:364;;;83497:26;;-1:-1:-1;;;83497:26:0;;18016:2:1;83497:26:0;;;17998:21:1;18055:2;18035:18;;;18028:30;-1:-1:-1;;;18074:18:1;;;18067:46;18130:18;;83497:26:0;17814:340:1;83446:364:0;83556:14;83583:16;83573:6;:26;;;;;;;;:::i;:::-;;:156;;83715:13;;;;83685:44;;-1:-1:-1;;;83685:44:0;;;;;1107:25:1;;;;83685:9:0;-1:-1:-1;;;;;83685:29:0;;;;1080:18:1;;83685:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83573:156;;;83651:13;;;;83619:46;;-1:-1:-1;;;83619:46:0;;;;;1107:25:1;;;;83619:11:0;-1:-1:-1;;;;;83619:31:0;;;;1080:18:1;;83619:46:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83556:173;;83752:9;83744:54;;;;-1:-1:-1;;;83744:54:0;;18611:2:1;83744:54:0;;;18593:21:1;;;18630:18;;;18623:30;18689:34;18669:18;;;18662:62;18741:18;;83744:54:0;18409:356:1;83744:54:0;83541:269;83860:30;83893:38;83912:8;:18;;;83893:38;;:18;:38::i;:::-;83860:71;;83942:12;83957:67;83969:8;:13;;;83984:9;:21;;;84007:9;:16;;;83957:11;:67::i;:::-;83942:82;;84040:7;84035:91;;84064:50;;-1:-1:-1;;;84064:50:0;;18972:2:1;84064:50:0;;;18954:21:1;19011:2;18991:18;;;18984:30;19050:34;19030:18;;;19023:62;-1:-1:-1;;;19101:18:1;;;19094:38;19149:19;;84064:50:0;18770:404:1;84035:91:0;84169:47;84191:6;84199:8;:16;;;84169:21;:47::i;:::-;-1:-1:-1;;;;;84235:33:0;;;;;;:29;:33;;;;;;84164:52;;-1:-1:-1;84235:38:0;:58;;;;-1:-1:-1;;;;;;84277:16:0;;;;84235:58;84227:88;;;;-1:-1:-1;;;84227:88:0;;10293:2:1;84227:88:0;;;10275:21:1;10332:2;10312:18;;;10305:30;-1:-1:-1;;;10351:18:1;;;10344:47;10408:18;;84227:88:0;10091:341:1;84227:88:0;82873:1450;;;;;;;82780:1543;;;:::o;31282:147::-;31368:4;31392:12;;;;;;;;;;;-1:-1:-1;;;;;31392:29:0;;;;;;;;;;;;;;;31282:147::o;50059:104::-;50115:13;50148:7;50141:14;;;;;:::i;51645:155::-;51740:52;12491:10;51773:8;51783;51740:18;:52::i;87356:110::-;87407:22;87449:9;87442:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;87356:110;:::o;87474:483::-;30432:4;30878:16;30432:4;30878:10;:16::i;:::-;87606:9:::1;;87588:15;:27;87584:366;;;87632:33;87652:6;87660:4;87632:19;:33::i;:::-;87768:6;87739:9;87749:1;87739:12;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;;::::1;;:35:::0;50990:346;50920:416;;:::o;87584:366::-:1;87902:36;87922:9;;87933:4;87902:19;:36::i;86240:293::-:0;30432:4;30878:16;30432:4;30878:10;:16::i;:::-;86361:12:::1;86344:13;;:29;;86336:80;;;::::0;-1:-1:-1;;;86336:80:0;;19513:2:1;86336:80:0::1;::::0;::::1;19495:21:1::0;19552:2;19532:18;;;19525:30;19591:34;19571:18;;;19564:62;-1:-1:-1;;;19642:18:1;;;19635:36;19688:19;;86336:80:0::1;19311:402:1::0;86336:80:0::1;86461:9;;86445:12;86435:7;;:22;;;;:::i;:::-;:35;;86427:65;;;::::0;-1:-1:-1;;;86427:65:0;;19920:2:1;86427:65:0::1;::::0;::::1;19902:21:1::0;19959:2;19939:18;;;19932:30;-1:-1:-1;;;19978:18:1;;;19971:47;20035:18;;86427:65:0::1;19718:341:1::0;86427:65:0::1;-1:-1:-1::0;86503:7:0::1;:22:::0;86240:293::o;52764:322::-;52938:41;12491:10;52971:7;52938:18;:41::i;:::-;52930:99;;;;-1:-1:-1;;;52930:99:0;;;;;;;:::i;:::-;53040:38;53054:4;53060:2;53064:7;53073:4;53040:13;:38::i;50234:281::-;50307:13;50333:23;50348:7;50333:14;:23::i;:::-;50369:21;50393:10;:8;:10::i;:::-;50369:34;;50445:1;50427:7;50421:21;:25;:86;;;;;;;;;;;;;;;;;50473:7;50482:18;:7;:16;:18::i;:::-;50456:45;;;;;;;;;:::i;:::-;;;;;;;;;;;;;50421:86;50414:93;50234:281;-1:-1:-1;;;50234:281:0:o;84448:303::-;30432:4;30878:16;30432:4;30878:10;:16::i;:::-;84574:7:::1;;84563;:18;;:33;;;;;84595:1;84585:7;:11;84563:33;84555:70;;;::::0;-1:-1:-1;;;84555:70:0;;20741:2:1;84555:70:0::1;::::0;::::1;20723:21:1::0;20780:2;20760:18;;;20753:30;20819:26;20799:18;;;20792:54;20863:18;;84555:70:0::1;20539:348:1::0;84555:70:0::1;84664:7;;84646:14;;84644:16;;;;;:::i;:::-;::::0;;;;-1:-1:-1;84644:27:0::1;;84636:67;;;::::0;-1:-1:-1;;;84636:67:0;;21094:2:1;84636:67:0::1;::::0;::::1;21076:21:1::0;21133:2;21113:18;;;21106:30;21172:29;21152:18;;;21145:57;21219:18;;84636:67:0::1;20892:351:1::0;84636:67:0::1;84714:29;84724:9;84735:7;84714:9;:29::i;33690:149::-:0;32883:7;32910:12;;;;;;;;;;:22;;;30878:16;30889:4;30878:10;:16::i;:::-;33805:26:::1;33817:4;33823:7;33805:11;:26::i;48962:305::-:0;49064:4;-1:-1:-1;;;;;;49101:40:0;;-1:-1:-1;;;49101:40:0;;:105;;-1:-1:-1;;;;;;;49158:48:0;;-1:-1:-1;;;49158:48:0;49101:105;:158;;;;49223:36;49247:11;49223:23;:36::i;61221:135::-;54889:4;54487:16;;;:7;:16;;;;;;-1:-1:-1;;;;;54487:16:0;61295:53;;;;-1:-1:-1;;;61295:53:0;;11966:2:1;61295:53:0;;;11948:21:1;12005:2;11985:18;;;11978:30;-1:-1:-1;;;12024:18:1;;;12017:54;12088:18;;61295:53:0;11764:348:1;61295:53:0;61221:135;:::o;60500:174::-;60575:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;60575:29:0;-1:-1:-1;;;;;60575:29:0;;;;;;;;:24;;60629:23;60575:24;60629:14;:23::i;:::-;-1:-1:-1;;;;;60620:46:0;;;;;;;;;;;60500:174;;:::o;55119:264::-;55212:4;55229:13;55245:23;55260:7;55245:14;:23::i;:::-;55229:39;;55298:5;-1:-1:-1;;;;;55287:16:0;:7;-1:-1:-1;;;;;55287:16:0;;:52;;;-1:-1:-1;;;;;;51992:25:0;;;51968:4;51992:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;55307:32;55287:87;;;;55367:7;-1:-1:-1;;;;;55343:31:0;:20;55355:7;55343:11;:20::i;:::-;-1:-1:-1;;;;;55343:31:0;;55287:87;55279:96;55119:264;-1:-1:-1;;;;55119:264:0:o;59118:1263::-;59277:4;-1:-1:-1;;;;;59250:31:0;:23;59265:7;59250:14;:23::i;:::-;-1:-1:-1;;;;;59250:31:0;;59242:81;;;;-1:-1:-1;;;59242:81:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;59342:16:0;;59334:65;;;;-1:-1:-1;;;59334:65:0;;21856:2:1;59334:65:0;;;21838:21:1;21895:2;21875:18;;;21868:30;21934:34;21914:18;;;21907:62;-1:-1:-1;;;21985:18:1;;;21978:34;22029:19;;59334:65:0;21654:400:1;59334:65:0;59412:42;59433:4;59439:2;59443:7;59452:1;59412:20;:42::i;:::-;59584:4;-1:-1:-1;;;;;59557:31:0;:23;59572:7;59557:14;:23::i;:::-;-1:-1:-1;;;;;59557:31:0;;59549:81;;;;-1:-1:-1;;;59549:81:0;;;;;;;:::i;:::-;59702:24;;;;:15;:24;;;;;;;;59695:31;;-1:-1:-1;;;;;;59695:31:0;;;;;;-1:-1:-1;;;;;60178:15:0;;;;;;:9;:15;;;;;:20;;-1:-1:-1;;60178:20:0;;;60213:13;;;;;;;;;:18;;59695:31;60213:18;;;60253:16;;;:7;:16;;;;;;:21;;;;;;;;;;60292:27;;59718:7;;60292:27;;;50990:346;50920:416;;:::o;31733:105::-;31800:30;31811:4;12491:10;31800;:30::i;86622:726::-;86725:1;86713:9;:13;86705:50;;;;-1:-1:-1;;;86705:50:0;;22261:2:1;86705:50:0;;;22243:21:1;22300:2;22280:18;;;22273:30;22339:26;22319:18;;;22312:54;22383:18;;86705:50:0;22059:348:1;86705:50:0;86788:14;86793:9;86788:1;:14;:::i;:::-;86774:11;:28;86766:65;;;;-1:-1:-1;;;86766:65:0;;23988:2:1;86766:65:0;;;23970:21:1;24027:2;24007:18;;;24000:30;24066:26;24046:18;;;24039:54;24110:18;;86766:65:0;23786:348:1;86766:65:0;86866:9;;86848:15;:27;86844:497;;;86921:9;;86892;86902:1;86892:12;;;;;;;;:::i;:::-;;;;;;;;;;;:26;;:38;;;;86972:11;86945:9;86955:1;86945:12;;;;;;;;:::i;:::-;;;;;;;;;;;:24;;:38;;;;87020:9;86998;87008:1;86998:12;;;;;;;;:::i;:::-;;;;;;;;;;;:19;;:31;;;;34394:218;;:::o;86844:497::-;87062:30;87095:194;;;;;;;;87143:9;:16;;;;87163:1;87143:21;:51;;87179:15;87143:51;;;87167:9;;87143:51;87095:194;;;;;;;;;;;;;;;;87304:9;:25;;;;;;;-1:-1:-1;87304:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;86622:726:0;;:::o;35991:238::-;36075:22;36083:4;36089:7;36075;:22::i;:::-;36070:152;;36114:6;:12;;;;;;;;;;;-1:-1:-1;;;;;36114:29:0;;;;;;;;;:36;;-1:-1:-1;;36114:36:0;36146:4;36114:36;;;36197:12;12491:10;;12411:98;36197:12;-1:-1:-1;;;;;36170:40:0;36188:7;-1:-1:-1;;;;;36170:40:0;36182:4;36170:40;;;;;;;;;;35991:238;;:::o;36409:239::-;36493:22;36501:4;36507:7;36493;:22::i;:::-;36489:152;;;36564:5;36532:12;;;;;;;;;;;-1:-1:-1;;;;;36532:29:0;;;;;;;;;;:37;;-1:-1:-1;;36532:37:0;;;36589:40;12491:10;;36532:12;;36589:40;;36564:5;36589:40;36409:239;;:::o;87965:186::-;88067:9;;88050:13;:11;:13::i;:::-;:26;;88042:62;;;;-1:-1:-1;;;88042:62:0;;24341:2:1;88042:62:0;;;24323:21:1;24380:2;24360:18;;;24353:30;24419:25;24399:18;;;24392:53;24462:18;;88042:62:0;24139:347:1;88042:62:0;88115:28;88131:2;88135:7;88115:15;:28::i;89273:646::-;89413:40;;-1:-1:-1;;;89413:40:0;;24665:6:1;24653:19;;89413:40:0;;;24635:38:1;89369:10:0;;;;89457:13;;-1:-1:-1;;;;;89413:11:0;:27;;;;24608:18:1;;89413:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:57;:138;;;;89539:11;-1:-1:-1;;;;;89487:64:0;89511:13;89503:22;;-1:-1:-1;;;;;89487:64:0;;89413:138;89392:159;;89566:13;89562:69;;;89603:16;89596:23;;;;;89562:69;89662:38;;-1:-1:-1;;;89662:38:0;;24665:6:1;24653:19;;89662:38:0;;;24635::1;89643:16:0;;89704:13;;-1:-1:-1;;;;;89662:9:0;:25;;;;24608:18:1;;89662:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:55;:134;;;;89786:9;-1:-1:-1;;;;;89734:62:0;89758:13;89750:22;;-1:-1:-1;;;;;89734:62:0;;89662:134;89643:153;;89811:11;89807:65;;;89846:14;89839:21;;;;;;89807:65;-1:-1:-1;89891:20:0;;89273:646;-1:-1:-1;;;;89273:646:0:o;88352:455::-;88421:20;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;88421:20:0;88471:9;:16;88459:9;;88471:20;;88490:1;;88471:20;:::i;:::-;88459:32;;88454:231;88521:30;88554:9;88564:1;88554:12;;;;;;;;:::i;:::-;;;;;;;;;;;88521:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;88612:9;88585;:23;;;:36;88581:93;;88649:9;88352:455;-1:-1:-1;;;88352:455:0:o;88581:93::-;-1:-1:-1;88501:3:0;;;;:::i;:::-;;;;88454:231;;89021:244;89118:4;89135:12;89150:24;89164:9;89150:13;:24::i;:::-;89207:11;;;-1:-1:-1;;;89238:18:0;;89021:244;-1:-1:-1;;;89021:244:0:o;89927:911::-;90021:10;;90083:16;90073:6;:26;;;;;;;;:::i;:::-;;90069:661;;;90223:2;90266:17;90223:2;90281;90266:17;:::i;:::-;90248:7;:14;:35;;90240:63;;;;-1:-1:-1;;;90240:63:0;;25563:2:1;90240:63:0;;;25545:21:1;25602:2;25582:18;;;25575:30;-1:-1:-1;;;25621:18:1;;;25614:45;25676:18;;90240:63:0;25361:339:1;90240:63:0;90362:37;;90379:4;90362:37;90356:44;;-1:-1:-1;90069:661:0;;;90446:14;90436:6;:24;;;;;;;;:::i;:::-;;90432:298;;;90477:20;90517:2;90500:7;:14;:19;;;;:::i;:::-;90666:37;;90683:4;90666:37;90660:44;;-1:-1:-1;;90432:298:0;90744:20;;90740:91;;90810:6;-1:-1:-1;90810:6:0;90740:91;90033:805;89927:911;;;;:::o;60817:315::-;60972:8;-1:-1:-1;;;;;60963:17:0;:5;-1:-1:-1;;;;;60963:17:0;;;60955:55;;;;-1:-1:-1;;;60955:55:0;;25907:2:1;60955:55:0;;;25889:21:1;25946:2;25926:18;;;25919:30;25985:27;25965:18;;;25958:55;26030:18;;60955:55:0;25705:349:1;60955:55:0;-1:-1:-1;;;;;61021:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;61021:46:0;;;;;;;;;;61083:41;;540::1;;;61083::0;;513:18:1;61083:41:0;;;;;;;60817:315;;;:::o;88159:185::-;88252:6;88245:4;:13;88237:45;;;;-1:-1:-1;;;88237:45:0;;26261:2:1;88237:45:0;;;26243:21:1;26300:2;26280:18;;;26273:30;-1:-1:-1;;;26319:18:1;;;26312:49;26378:18;;88237:45:0;26059:343:1;88237:45:0;88293:9;:18;;;;88322:7;:14;88159:185::o;53967:313::-;54123:28;54133:4;54139:2;54143:7;54123:9;:28::i;:::-;54170:47;54193:4;54199:2;54203:7;54212:4;54170:22;:47::i;:::-;54162:110;;;;-1:-1:-1;;;54162:110:0;;;;;;;:::i;82234:97::-;82286:13;82319:4;82312:11;;;;;:::i;25760:716::-;25816:13;25867:14;25884:17;25895:5;25884:10;:17::i;:::-;25904:1;25884:21;25867:38;;25920:20;25954:6;25943:18;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;25943:18:0;-1:-1:-1;25920:41:0;-1:-1:-1;26085:28:0;;;26101:2;26085:28;26142:288;-1:-1:-1;;26174:5:0;-1:-1:-1;;;26311:2:0;26300:14;;26295:30;26174:5;26282:44;26372:2;26363:11;;;-1:-1:-1;26397:10:0;26393:21;;26409:5;;26393:21;26142:288;;;-1:-1:-1;26451:6:0;25760:716;-1:-1:-1;;;25760:716:0:o;30986:204::-;31071:4;-1:-1:-1;;;;;;31095:47:0;;-1:-1:-1;;;31095:47:0;;:87;;-1:-1:-1;;;;;;;;;;28530:40:0;;;31146:36;28421:157;63505:410;63695:1;63683:9;:13;63679:229;;;-1:-1:-1;;;;;63717:18:0;;;63713:87;;-1:-1:-1;;;;;63756:15:0;;;;;;:9;:15;;;;;:28;;63775:9;;63756:15;:28;;63775:9;;63756:28;:::i;:::-;;;;-1:-1:-1;;63713:87:0;-1:-1:-1;;;;;63818:16:0;;;63814:83;;-1:-1:-1;;;;;63855:13:0;;;;;;:9;:13;;;;;:26;;63872:9;;63855:13;:26;;63872:9;;63855:26;:::i;:::-;;;;-1:-1:-1;;63505:410:0;;;;:::o;32128:492::-;32217:22;32225:4;32231:7;32217;:22::i;:::-;32212:401;;32405:28;32425:7;32405:19;:28::i;:::-;32506:38;32534:4;32541:2;32506:19;:38::i;:::-;32310:257;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;32310:257:0;;;;;;;;;;-1:-1:-1;;;32256:345:0;;;;;;;:::i;55725:110::-;55801:26;55811:2;55815:7;55801:26;;;;;;;;;;;;:9;:26::i;88815:198::-;88876:12;88918:1;88909:6;:10;:26;;;;;88933:2;88923:6;:12;;88909:26;88901:53;;;;-1:-1:-1;;;88901:53:0;;27951:2:1;88901:53:0;;;27933:21:1;27990:2;27970:18;;;27963:30;-1:-1:-1;;;28009:18:1;;;28002:44;28063:18;;88901:53:0;27749:338:1;88901:53:0;89003:1;88988:11;88993:6;88988:1;:11;:::i;:::-;88980:24;;;;:::i;61920:853::-;62074:4;-1:-1:-1;;;;;62095:13:0;;39835:19;:23;62091:675;;62131:71;;-1:-1:-1;;;62131:71:0;;-1:-1:-1;;;;;62131:36:0;;;;;:71;;12491:10;;62182:4;;62188:7;;62197:4;;62131:71;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62131:71:0;;;;;;;;-1:-1:-1;;62131:71:0;;;;;;;;;;;;:::i;:::-;;;62127:584;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;62372:13:0;;62368:328;;62415:60;;-1:-1:-1;;;62415:60:0;;;;;;;:::i;62368:328::-;62646:6;62640:13;62631:6;62627:2;62623:15;62616:38;62127:584;-1:-1:-1;;;;;;62253:51:0;-1:-1:-1;;;62253:51:0;;-1:-1:-1;62246:58:0;;62091:675;-1:-1:-1;62750:4:0;61920:853;;;;;;:::o;22782:922::-;22835:7;;-1:-1:-1;;;22913:15:0;;22909:102;;-1:-1:-1;;;22949:15:0;;;-1:-1:-1;22993:2:0;22983:12;22909:102;23038:6;23029:5;:15;23025:102;;23074:6;23065:15;;;-1:-1:-1;23109:2:0;23099:12;23025:102;23154:6;23145:5;:15;23141:102;;23190:6;23181:15;;;-1:-1:-1;23225:2:0;23215:12;23141:102;23270:5;23261;:14;23257:99;;23305:5;23296:14;;;-1:-1:-1;23339:1:0;23329:11;23257:99;23383:5;23374;:14;23370:99;;23418:5;23409:14;;;-1:-1:-1;23452:1:0;23442:11;23370:99;23496:5;23487;:14;23483:99;;23531:5;23522:14;;;-1:-1:-1;23565:1:0;23555:11;23483:99;23609:5;23600;:14;23596:66;;23645:1;23635:11;23690:6;22782:922;-1:-1:-1;;22782:922:0:o;27496:151::-;27554:13;27587:52;-1:-1:-1;;;;;27599:22:0;;25651:2;26892:447;26967:13;26993:19;27025:10;27029:6;27025:1;:10;:::i;:::-;:14;;27038:1;27025:14;:::i;:::-;27015:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;27015:25:0;;26993:47;;-1:-1:-1;;;27051:6:0;27058:1;27051:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;27051:15:0;;;;;;;;;-1:-1:-1;;;27077:6:0;27084:1;27077:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;27077:15:0;;;;;;;;-1:-1:-1;27108:9:0;27120:10;27124:6;27120:1;:10;:::i;:::-;:14;;27133:1;27120:14;:::i;:::-;27108:26;;27103:131;27140:1;27136;:5;27103:131;;;-1:-1:-1;;;27184:5:0;27192:3;27184:11;27175:21;;;;;;;:::i;:::-;;;;27163:6;27170:1;27163:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;27163:33:0;;;;;;;;-1:-1:-1;27221:1:0;27211:11;;;;;27143:3;;;:::i;:::-;;;27103:131;;;-1:-1:-1;27252:10:0;;27244:55;;;;-1:-1:-1;;;27244:55:0;;29215:2:1;27244:55:0;;;29197:21:1;;;29234:18;;;29227:30;29293:34;29273:18;;;29266:62;29345:18;;27244:55:0;29013:356:1;56062:319:0;56191:18;56197:2;56201:7;56191:5;:18::i;:::-;56242:53;56273:1;56277:2;56281:7;56290:4;56242:22;:53::i;:::-;56220:153;;;;-1:-1:-1;;;56220:153:0;;;;;;;:::i;56717:942::-;-1:-1:-1;;;;;56797:16:0;;56789:61;;;;-1:-1:-1;;;56789:61:0;;29576:2:1;56789:61:0;;;29558:21:1;;;29595:18;;;29588:30;29654:34;29634:18;;;29627:62;29706:18;;56789:61:0;29374:356:1;56789:61:0;54889:4;54487:16;;;:7;:16;;;;;;-1:-1:-1;;;;;54487:16:0;54913:31;56861:58;;;;-1:-1:-1;;;56861:58:0;;29937:2:1;56861:58:0;;;29919:21:1;29976:2;29956:18;;;29949:30;30015;29995:18;;;29988:58;30063:18;;56861:58:0;29735:352:1;56861:58:0;56932:48;56961:1;56965:2;56969:7;56978:1;56932:20;:48::i;:::-;54889:4;54487:16;;;:7;:16;;;;;;-1:-1:-1;;;;;54487:16:0;54913:31;57070:58;;;;-1:-1:-1;;;57070:58:0;;29937:2:1;57070:58:0;;;29919:21:1;29976:2;29956:18;;;29949:30;30015;29995:18;;;29988:58;30063:18;;57070:58:0;29735:352:1;57070:58:0;-1:-1:-1;;;;;57477:13:0;;;;;;:9;:13;;;;;;;;:18;;57494:1;57477:18;;;57519:16;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;57519:21:0;;;;;57558:33;57527:7;;57477:13;;57558:33;;57477:13;;57558:33;34394:218;;:::o;14:131:1:-;-1:-1:-1;;;;;;88:32:1;;78:43;;68:71;;135:1;132;125:12;150:245;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;592:173::-;660:20;;-1:-1:-1;;;;;709:31:1;;699:42;;689:70;;755:1;752;745:12;689:70;592:173;;;:::o;770:186::-;829:6;882:2;870:9;861:7;857:23;853:32;850:52;;;898:1;895;888:12;850:52;921:29;940:9;921:29;:::i;1143:258::-;1215:1;1225:113;1239:6;1236:1;1233:13;1225:113;;;1315:11;;;1309:18;1296:11;;;1289:39;1261:2;1254:10;1225:113;;;1356:6;1353:1;1350:13;1347:48;;;-1:-1:-1;;1391:1:1;1373:16;;1366:27;1143:258::o;1406:::-;1448:3;1486:5;1480:12;1513:6;1508:3;1501:19;1529:63;1585:6;1578:4;1573:3;1569:14;1562:4;1555:5;1551:16;1529:63;:::i;:::-;1646:2;1625:15;-1:-1:-1;;1621:29:1;1612:39;;;;1653:4;1608:50;;1406:258;-1:-1:-1;;1406:258:1:o;1669:220::-;1818:2;1807:9;1800:21;1781:4;1838:45;1879:2;1868:9;1864:18;1856:6;1838:45;:::i;1894:180::-;1953:6;2006:2;1994:9;1985:7;1981:23;1977:32;1974:52;;;2022:1;2019;2012:12;1974:52;-1:-1:-1;2045:23:1;;1894:180;-1:-1:-1;1894:180:1:o;2287:254::-;2355:6;2363;2416:2;2404:9;2395:7;2391:23;2387:32;2384:52;;;2432:1;2429;2422:12;2384:52;2455:29;2474:9;2455:29;:::i;:::-;2445:39;2531:2;2516:18;;;;2503:32;;-1:-1:-1;;;2287:254:1:o;2546:328::-;2623:6;2631;2639;2692:2;2680:9;2671:7;2667:23;2663:32;2660:52;;;2708:1;2705;2698:12;2660:52;2731:29;2750:9;2731:29;:::i;:::-;2721:39;;2779:38;2813:2;2802:9;2798:18;2779:38;:::i;:::-;2769:48;;2864:2;2853:9;2849:18;2836:32;2826:42;;2546:328;;;;;:::o;3246:248::-;3314:6;3322;3375:2;3363:9;3354:7;3350:23;3346:32;3343:52;;;3391:1;3388;3381:12;3343:52;-1:-1:-1;;3414:23:1;;;3484:2;3469:18;;;3456:32;;-1:-1:-1;3246:248:1:o;3499:254::-;3567:6;3575;3628:2;3616:9;3607:7;3603:23;3599:32;3596:52;;;3644:1;3641;3634:12;3596:52;3680:9;3667:23;3657:33;;3709:38;3743:2;3732:9;3728:18;3709:38;:::i;:::-;3699:48;;3499:254;;;;;:::o;3758:127::-;3819:10;3814:3;3810:20;3807:1;3800:31;3850:4;3847:1;3840:15;3874:4;3871:1;3864:15;3890:253;3962:2;3956:9;4004:4;3992:17;;4039:18;4024:34;;4060:22;;;4021:62;4018:88;;;4086:18;;:::i;:::-;4122:2;4115:22;3890:253;:::o;4148:255::-;4220:2;4214:9;4262:6;4250:19;;4299:18;4284:34;;4320:22;;;4281:62;4278:88;;;4346:18;;:::i;4408:275::-;4479:2;4473:9;4544:2;4525:13;;-1:-1:-1;;4521:27:1;4509:40;;4579:18;4564:34;;4600:22;;;4561:62;4558:88;;;4626:18;;:::i;:::-;4662:2;4655:22;4408:275;;-1:-1:-1;4408:275:1:o;4688:186::-;4736:4;4769:18;4761:6;4758:30;4755:56;;;4791:18;;:::i;:::-;-1:-1:-1;4857:2:1;4836:15;-1:-1:-1;;4832:29:1;4863:4;4828:40;;4688:186::o;4879:462::-;4921:5;4974:3;4967:4;4959:6;4955:17;4951:27;4941:55;;4992:1;4989;4982:12;4941:55;5028:6;5015:20;5059:48;5075:31;5103:2;5075:31;:::i;:::-;5059:48;:::i;:::-;5132:2;5123:7;5116:19;5178:3;5171:4;5166:2;5158:6;5154:15;5150:26;5147:35;5144:55;;;5195:1;5192;5185:12;5144:55;5260:2;5253:4;5245:6;5241:17;5234:4;5225:7;5221:18;5208:55;5308:1;5283:16;;;5301:4;5279:27;5272:38;;;;5287:7;4879:462;-1:-1:-1;;;4879:462:1:o;5346:320::-;5414:6;5467:2;5455:9;5446:7;5442:23;5438:32;5435:52;;;5483:1;5480;5473:12;5435:52;5523:9;5510:23;5556:18;5548:6;5545:30;5542:50;;;5588:1;5585;5578:12;5542:50;5611:49;5652:7;5643:6;5632:9;5628:22;5611:49;:::i;5671:118::-;5757:5;5750:13;5743:21;5736:5;5733:32;5723:60;;5779:1;5776;5769:12;5794:315;5859:6;5867;5920:2;5908:9;5899:7;5895:23;5891:32;5888:52;;;5936:1;5933;5926:12;5888:52;5959:29;5978:9;5959:29;:::i;:::-;5949:39;;6038:2;6027:9;6023:18;6010:32;6051:28;6073:5;6051:28;:::i;:::-;6098:5;6088:15;;;5794:315;;;;;:::o;6114:853::-;6345:2;6397:21;;;6467:13;;6370:18;;;6489:22;;;6316:4;;6345:2;6530;;6548:18;;;;6589:15;;;6316:4;6632:309;6646:6;6643:1;6640:13;6632:309;;;6705:13;;6743:9;;6731:22;;6793:11;;;6787:18;6773:12;;;6766:40;6846:11;;6840:18;6826:12;;;6819:40;6888:4;6879:14;;;;6916:15;;;;6668:1;6661:9;6632:309;;;-1:-1:-1;6958:3:1;;6114:853;-1:-1:-1;;;;;;;6114:853:1:o;6972:537::-;7067:6;7075;7083;7091;7144:3;7132:9;7123:7;7119:23;7115:33;7112:53;;;7161:1;7158;7151:12;7112:53;7184:29;7203:9;7184:29;:::i;:::-;7174:39;;7232:38;7266:2;7255:9;7251:18;7232:38;:::i;:::-;7222:48;;7317:2;7306:9;7302:18;7289:32;7279:42;;7372:2;7361:9;7357:18;7344:32;7399:18;7391:6;7388:30;7385:50;;;7431:1;7428;7421:12;7385:50;7454:49;7495:7;7486:6;7475:9;7471:22;7454:49;:::i;:::-;7444:59;;;6972:537;;;;;;;:::o;7514:260::-;7582:6;7590;7643:2;7631:9;7622:7;7618:23;7614:32;7611:52;;;7659:1;7656;7649:12;7611:52;7682:29;7701:9;7682:29;:::i;:::-;7672:39;;7730:38;7764:2;7753:9;7749:18;7730:38;:::i;7779:380::-;7858:1;7854:12;;;;7901;;;7922:61;;7976:4;7968:6;7964:17;7954:27;;7922:61;8029:2;8021:6;8018:14;7998:18;7995:38;7992:161;;;8075:10;8070:3;8066:20;8063:1;8056:31;8110:4;8107:1;8100:15;8138:4;8135:1;8128:15;7992:161;;7779:380;;;:::o;8996:127::-;9057:10;9052:3;9048:20;9045:1;9038:31;9088:4;9085:1;9078:15;9112:4;9109:1;9102:15;9128:128;9168:3;9199:1;9195:6;9192:1;9189:13;9186:39;;;9205:18;;:::i;:::-;-1:-1:-1;9241:9:1;;9128:128::o;9261:409::-;9463:2;9445:21;;;9502:2;9482:18;;;9475:30;9541:34;9536:2;9521:18;;9514:62;-1:-1:-1;;;9607:2:1;9592:18;;9585:43;9660:3;9645:19;;9261:409::o;10785:125::-;10825:4;10853:1;10850;10847:8;10844:34;;;10858:18;;:::i;:::-;-1:-1:-1;10895:9:1;;10785:125::o;10915:135::-;10954:3;-1:-1:-1;;10975:17:1;;10972:43;;;10995:18;;:::i;:::-;-1:-1:-1;11042:1:1;11031:13;;10915:135::o;13104:160::-;13181:13;;13234:4;13223:16;;13213:27;;13203:55;;13254:1;13251;13244:12;13269:167;13347:13;;13400:10;13389:22;;13379:33;;13369:61;;13426:1;13423;13416:12;13441:163;13519:13;;13572:6;13561:18;;13551:29;;13541:57;;13594:1;13591;13584:12;13609:175;13687:13;;13740:18;13729:30;;13719:41;;13709:69;;13774:1;13771;13764:12;13789:428;13842:5;13895:3;13888:4;13880:6;13876:17;13872:27;13862:55;;13913:1;13910;13903:12;13862:55;13942:6;13936:13;13973:48;13989:31;14017:2;13989:31;:::i;13973:48::-;14046:2;14037:7;14030:19;14092:3;14085:4;14080:2;14072:6;14068:15;14064:26;14061:35;14058:55;;;14109:1;14106;14099:12;14058:55;14122:64;14183:2;14176:4;14167:7;14163:18;14156:4;14148:6;14144:17;14122:64;:::i;14222:1177::-;14296:5;14349:3;14342:4;14334:6;14330:17;14326:27;14316:55;;14367:1;14364;14357:12;14316:55;14396:6;14390:13;14422:4;14445:18;14441:2;14438:26;14435:52;;;14467:18;;:::i;:::-;14507:36;14539:2;14534;14531:1;14527:10;14523:19;14507:36;:::i;:::-;14577:15;;;14663:1;14659:10;;;;14647:23;;14643:32;;;14608:12;;;;14687:15;;;14684:35;;;14715:1;14712;14705:12;14684:35;14751:2;14743:6;14739:15;14763:607;14779:6;14774:3;14771:15;14763:607;;;14857:4;14851:3;14846;14842:13;14838:24;14835:114;;;14903:1;14932:2;14928;14921:14;14835:114;14975:22;;:::i;:::-;15030:3;15024:10;15017:5;15010:25;15086:2;15081:3;15077:12;15071:19;15066:2;15059:5;15055:14;15048:43;15114:2;15152:41;15189:2;15184:3;15180:12;15152:41;:::i;:::-;15136:14;;;15129:65;15217:2;15255:41;15283:12;;;15255:41;:::i;:::-;15239:14;;;15232:65;15310:18;;15348:12;;;;14805:4;14796:14;14763:607;;;-1:-1:-1;15388:5:1;14222:1177;-1:-1:-1;;;;;;14222:1177:1:o;15404:132::-;15480:13;;15502:28;15480:13;15502:28;:::i;15541:1784::-;15656:6;15664;15672;15725:2;15713:9;15704:7;15700:23;15696:32;15693:52;;;15741:1;15738;15731:12;15693:52;15774:9;15768:16;15803:18;15844:2;15836:6;15833:14;15830:34;;;15860:1;15857;15850:12;15830:34;15883:22;;;;15939:6;15921:16;;;15917:29;15914:49;;;15959:1;15956;15949:12;15914:49;15985:22;;:::i;:::-;16030:31;16058:2;16030:31;:::i;:::-;16023:5;16016:46;16094:41;16131:2;16127;16123:11;16094:41;:::i;:::-;16089:2;16082:5;16078:14;16071:65;16168:41;16205:2;16201;16197:11;16168:41;:::i;:::-;16163:2;16156:5;16152:14;16145:65;16242:41;16279:2;16275;16271:11;16242:41;:::i;:::-;16237:2;16230:5;16226:14;16219:65;16331:3;16327:2;16323:12;16317:19;16311:3;16304:5;16300:15;16293:44;16370:42;16407:3;16403:2;16399:12;16370:42;:::i;:::-;16364:3;16357:5;16353:15;16346:67;16446:41;16482:3;16478:2;16474:12;16446:41;:::i;:::-;16440:3;16433:5;16429:15;16422:66;16527:3;16523:2;16519:12;16513:19;16557:2;16547:8;16544:16;16541:36;;;16573:1;16570;16563:12;16541:36;16610:55;16657:7;16646:8;16642:2;16638:17;16610:55;:::i;:::-;16604:3;16597:5;16593:15;16586:80;;16685:3;16720:41;16757:2;16753;16749:11;16720:41;:::i;:::-;16704:14;;;16697:65;16781:3;16815:11;;;16809:18;16839:16;;;16836:36;;;16868:1;16865;16858:12;16836:36;16904:76;16972:7;16961:8;16957:2;16953:17;16904:76;:::i;:::-;16888:14;;;16881:100;;;;-1:-1:-1;17000:3:1;17041:11;;;17035:18;17019:14;;;17012:42;16892:5;-1:-1:-1;17097:46:1;17139:2;17124:18;;17097:46;:::i;:::-;17087:56;;17189:2;17178:9;17174:18;17168:25;17152:41;;17218:2;17208:8;17205:16;17202:36;;;17234:1;17231;17224:12;17202:36;;17257:62;17311:7;17300:8;17289:9;17285:24;17257:62;:::i;:::-;17247:72;;;15541:1784;;;;;:::o;17682:127::-;17743:10;17738:3;17734:20;17731:1;17724:31;17774:4;17771:1;17764:15;17798:4;17795:1;17788:15;18159:245;18226:6;18279:2;18267:9;18258:7;18254:23;18250:32;18247:52;;;18295:1;18292;18285:12;18247:52;18327:9;18321:16;18346:28;18368:5;18346:28;:::i;19179:127::-;19240:10;19235:3;19231:20;19228:1;19221:31;19271:4;19268:1;19261:15;19295:4;19292:1;19285:15;20064:470;20243:3;20281:6;20275:13;20297:53;20343:6;20338:3;20331:4;20323:6;20319:17;20297:53;:::i;:::-;20413:13;;20372:16;;;;20435:57;20413:13;20372:16;20469:4;20457:17;;20435:57;:::i;:::-;20508:20;;20064:470;-1:-1:-1;;;;20064:470:1:o;21248:401::-;21450:2;21432:21;;;21489:2;21469:18;;;21462:30;21528:34;21523:2;21508:18;;21501:62;-1:-1:-1;;;21594:2:1;21579:18;;21572:35;21639:3;21624:19;;21248:401::o;22412:422::-;22501:1;22544:5;22501:1;22558:270;22579:7;22569:8;22566:21;22558:270;;;22638:4;22634:1;22630:6;22626:17;22620:4;22617:27;22614:53;;;22647:18;;:::i;:::-;22697:7;22687:8;22683:22;22680:55;;;22717:16;;;;22680:55;22796:22;;;;22756:15;;;;22558:270;;;22562:3;22412:422;;;;;:::o;22839:806::-;22888:5;22918:8;22908:80;;-1:-1:-1;22959:1:1;22973:5;;22908:80;23007:4;22997:76;;-1:-1:-1;23044:1:1;23058:5;;22997:76;23089:4;23107:1;23102:59;;;;23175:1;23170:130;;;;23082:218;;23102:59;23132:1;23123:10;;23146:5;;;23170:130;23207:3;23197:8;23194:17;23191:43;;;23214:18;;:::i;:::-;-1:-1:-1;;23270:1:1;23256:16;;23285:5;;23082:218;;23384:2;23374:8;23371:16;23365:3;23359:4;23356:13;23352:36;23346:2;23336:8;23333:16;23328:2;23322:4;23319:12;23315:35;23312:77;23309:159;;;-1:-1:-1;23421:19:1;;;23453:5;;23309:159;23500:34;23525:8;23519:4;23500:34;:::i;:::-;23570:6;23566:1;23562:6;23558:19;23549:7;23546:32;23543:58;;;23581:18;;:::i;:::-;23619:20;;22839:806;-1:-1:-1;;;22839:806:1:o;23650:131::-;23710:5;23739:36;23766:8;23760:4;23739:36;:::i;24684:184::-;24754:6;24807:2;24795:9;24786:7;24782:23;24778:32;24775:52;;;24823:1;24820;24813:12;24775:52;-1:-1:-1;24846:16:1;;24684:184;-1:-1:-1;24684:184:1:o;24873:136::-;24912:3;24940:5;24930:39;;24949:18;;:::i;:::-;-1:-1:-1;;;24985:18:1;;24873:136::o;26407:414::-;26609:2;26591:21;;;26648:2;26628:18;;;26621:30;26687:34;26682:2;26667:18;;26660:62;-1:-1:-1;;;26753:2:1;26738:18;;26731:48;26811:3;26796:19;;26407:414::o;26958:786::-;27369:25;27364:3;27357:38;27339:3;27424:6;27418:13;27440:62;27495:6;27490:2;27485:3;27481:12;27474:4;27466:6;27462:17;27440:62;:::i;:::-;-1:-1:-1;;;27561:2:1;27521:16;;;27553:11;;;27546:40;27611:13;;27633:63;27611:13;27682:2;27674:11;;27667:4;27655:17;;27633:63;:::i;:::-;27716:17;27735:2;27712:26;;26958:786;-1:-1:-1;;;;26958:786:1:o;28092:489::-;-1:-1:-1;;;;;28361:15:1;;;28343:34;;28413:15;;28408:2;28393:18;;28386:43;28460:2;28445:18;;28438:34;;;28508:3;28503:2;28488:18;;28481:31;;;28286:4;;28529:46;;28555:19;;28547:6;28529:46;:::i;:::-;28521:54;28092:489;-1:-1:-1;;;;;;28092:489:1:o;28586:249::-;28655:6;28708:2;28696:9;28687:7;28683:23;28679:32;28676:52;;;28724:1;28721;28714:12;28676:52;28756:9;28750:16;28775:30;28799:5;28775:30;:::i;28840:168::-;28880:7;28946:1;28942;28938:6;28934:14;28931:1;28928:21;28923:1;28916:9;28909:17;28905:45;28902:71;;;28953:18;;:::i;:::-;-1:-1:-1;28993:9:1;;28840:168::o

Swarm Source

ipfs://2a9df8a93f387568118176b4a3866ad044ecbc1d09b6bfd47c0291981220142e
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.