ETH Price: $3,026.90 (+3.78%)
 

Overview

Max Total Supply

0 PCC

Holders

13

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
Null: 0x000...000
Balance
0 PCC
0x0000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
ProticoChattingChip

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-12-04
*/

// File: @openzeppelin/contracts/utils/Counters.sol


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

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol


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

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/security/ReentrancyGuard.sol


// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

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

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

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

// File: @openzeppelin/contracts/interfaces/IERC1271.sol


// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 *
 * _Available since v4.1._
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

// File: @openzeppelin/contracts/utils/Address.sol


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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol


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

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol


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

pragma solidity ^0.8.0;


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

// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol


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

pragma solidity ^0.8.0;


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

// File: @openzeppelin/contracts/utils/introspection/ERC165.sol


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

pragma solidity ^0.8.0;


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

// File: @openzeppelin/contracts/utils/math/Math.sol


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

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/utils/Strings.sol


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

pragma solidity ^0.8.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);
    }
}

// File: @openzeppelin/contracts/utils/cryptography/ECDSA.sol


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

pragma solidity ^0.8.0;


/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

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

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

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

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

// File: @openzeppelin/contracts/utils/cryptography/SignatureChecker.sol


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

pragma solidity ^0.8.0;




/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Gnosis Safe.
 *
 * _Available since v4.1._
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
        if (error == ECDSA.RecoverError.NoError && recovered == signer) {
            return true;
        }

        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
        );
        return (success &&
            result.length == 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

// File: @openzeppelin/contracts/utils/Context.sol


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

pragma solidity ^0.8.0;

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

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

// File: @openzeppelin/contracts/token/ERC721/ERC721.sol


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

pragma solidity ^0.8.0;








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

// File: @openzeppelin/contracts/access/IAccessControl.sol


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

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/access/AccessControl.sol


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

pragma solidity ^0.8.0;





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

// File: contracts/Easter Egg.sol

//SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.0;






library AddressMap {
  struct Map {
    address[] keys;
    mapping(address => bool) values;
    mapping(address => uint) indexOf;
  }

  function get(Map storage map, address key) public view returns (bool) {
    return map.values[key];
  }

  function getKeyAtIndex(Map storage map, uint index) public view returns (address) {
    return map.keys[index];
  }

  function size(Map storage map) public view returns (uint) {
    return map.keys.length;
  }

  function set(
    Map storage map,
    address key
  ) public {
      if (!map.values[key]) {
        map.values[key] = true;
        map.indexOf[key] = map.keys.length;
        map.keys.push(key);
      }
  }

  function remove(Map storage map, address key) public {
    if (!map.values[key]) {
      return;
    }

    delete map.values[key];

    uint index = map.indexOf[key];
    uint lastIndex = map.keys.length - 1;
    address lastKey = map.keys[lastIndex];

    map.indexOf[lastKey] = index;
    delete map.indexOf[key];

    map.keys[index] = lastKey;
    map.keys.pop();
  }
}

contract ProticoChattingChip is ERC721, ReentrancyGuard, AccessControl {
  using SignatureChecker for address;
  using Counters for Counters.Counter;
  using AddressMap for AddressMap.Map;
  Counters.Counter private _tokenIdCounter;
  uint256 constant MaxSupply = 30000;
  uint256 constant MaxPerDomain = 1000;
  bytes32[30] private _sites = [
    bytes32(0x9649c7eb6df175f417fcfb2eeeaf6e39367ec7a45034048a3d5cff5e2ea8519f),
    bytes32(0x45a2112d850d7101c902a913c185ba0d28e0ecdcfd1d540e2497f2750714f69a),
    bytes32(0x0445d458f1aa05b40e476e9a57218b91110ad2174ae15f7057715e84693f7100),
    bytes32(0xeb867819c51fbf7d44c73a332082c0b6142546289310c6ff4fac832120012ed3),
    bytes32(0x89ae9c604bc971f8b6a5aee73a1c4e71c952d16a3bcf995e1642f2db167bc5a7),
    bytes32(0x9f514643ee17437be8788be62d7db6953296791a2ad0db024063a20a97a08682),
    bytes32(0x94d13d04140fd5b04a3196ba600a958460fc847c28b74d6e9c1f26bb50c56b45),
    bytes32(0x9e01a36b730e791ed57eabb8379758d7601ffc79b6d613cb7744191938672887),
    bytes32(0x1345e844ae191c4c9f5ed685ecca259e4530dec934838661f002fc3ac3c3b83c),
    bytes32(0x588e7f25cc1ab5b40a3b6770561d285a5299071e36dbffe3cba46f5360110f5d),
    bytes32(0x6449d685d467441665612dc60098ae2a5f0e16d0e60f1d9d0b63e3c037c5df8d),
    bytes32(0xc9fc5126b89092478eb63279a7cd259ea24c24bc945b91b5c8366967b05ee6d1),
    bytes32(0x574014404853e93615346db284ca5bd068542f139762d459e11e64fee33e7abd),
    bytes32(0x0e84102fc2bc70ee46419905395f8fb46f7c0be0c9e694e4e699b087cde9be16),
    bytes32(0xd14db021bc6bdaf39de490427d6a1e0e265463ff19e83094dc76f0d3150fc716),
    bytes32(0x4c85a4f44366822767ab3fa89b6b2a8cf6b30a44a96152d7c26a77f634f9cbe0),
    bytes32(0xf0ca7fdd544d43a37b1fd3242551a298fbfed3edb8403c9e925c4cde8c19fe8e),
    bytes32(0x207eeb1c4a1ac75d8ac74d64bfabb5e81199384099507fa4233771c134adad72),
    bytes32(0x131e81156f0505f36093d6b4d5e6f14643b9f367da7fd717f3239c1599c620a8),
    bytes32(0x2ccc2d85ad9b8899ddbad3cef1c367ed84bf8d19014acd04588e48f6e837436e),
    bytes32(0x702c587833b68bf050b53037adba2bb8f7f93d875c5a372389d8d6987074f503),
    bytes32(0xb0af795fa00c85296c52b9fa3873a6acb561de2ac8e8ae0a84338bfbbcb6a3d7),
    bytes32(0xa57c78e6f3324d0ef1b1412366a8b123674f9423dd1effc63656d7e48d05bc30),
    bytes32(0xf7f00296c339c4e3d3b2aa84cbe9a6cadb9d8aabd2eb784064fb12ecf2029b0e),
    bytes32(0xbf9c1eb5724df6704047f4b9f5ddb73e21e53efedd725685ab9d9820c5dc99b2),
    bytes32(0xcc57ea92f884c55cc87b03761c95b7d99a2324f4baec0a72a0df10cbab77911b),
    bytes32(0xdc6ab7e871c6a47b07c00e6bbd11ee902e47d00afc2191d614116b87900973dc),
    bytes32(0xf2e4f0dcb4243c2dc76aeee61f15ba1d87db55775678f6d67d7a49130db786e4),
    bytes32(0x3a95202072e7adc1c3e2598fd97fd22472790fb26ec4f768f6b77c4c12995fb2),
    bytes32(0x6ce43a2f8178c89cac275597661b9ce9f6b7ef6a93e8c97b0ccf437dad1e511e)
  ];

  mapping(bytes32 => AddressMap.Map) private _list;
  mapping(bytes32 => bool) private _siteExists;
  string private _tokenURI;

  constructor() ERC721("Protico Chatting Chip", "PCC") {
      _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
      _tokenURI = "ipfs://QmWn9Lcv4PhFq1FEXXQjphkQyVaY4ewv1g1cxdYd4fTzBr";

      for (uint i; i < _sites.length; i++) {
        _siteExists[_sites[i]] = true;
      }
  }

  function mint(
    string memory _http,
    bytes memory _signature
  ) external nonReentrant {
    uint256 tokenId = _tokenIdCounter.current();
    require(tokenId < MaxSupply, "Not claimable");

    bytes32 hashedDomain = keccak256(abi.encodePacked(_http));
    require(_siteExists[hashedDomain], "Domain is not claimable.");
    require(_list[hashedDomain].size() < MaxPerDomain, "Domain is not claimable.");
    require(isSignatureValid(_http, _signature), "Invalid signature");

    bool hasMinted = _list[hashedDomain].get(msg.sender);
    require(!hasMinted, "Address already has the token on this domain.");
    _list[hashedDomain].set(msg.sender);
    _tokenIdCounter.increment();
    _safeMint(msg.sender, tokenId);
  }

  function isSignatureValid(string memory _http, bytes memory _signature) internal view returns (bool) {
      bytes32 result = keccak256(abi.encodePacked(msg.sender, _http));
      bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", result));
      return msg.sender.isValidSignatureNow(hash, _signature);
  }

  function setTokenURI(string memory _uri) external virtual onlyRole(DEFAULT_ADMIN_ROLE) {
    _tokenURI = _uri;
  }

  function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
    _requireMinted(tokenId);

    return _tokenURI;
  }

  function getMinted(string memory _http) external view onlyRole(DEFAULT_ADMIN_ROLE) returns (address[] memory) {
    bytes32 hashedDomain = keccak256(abi.encodePacked(_http));
    return _list[hashedDomain].keys;
  }

  function isValidDomain(string memory _http) external view returns (bool) {
    bytes32 hashedDomain = keccak256(abi.encodePacked(_http));

    return _siteExists[hashedDomain];
  }

  function claimable(string memory _http) external view returns (bool) {
    bytes32 hashedDomain = keccak256(abi.encodePacked(_http));
    uint256 tokenId = _tokenIdCounter.current();
    bool hasMinted = _list[hashedDomain].get(msg.sender);

    return tokenId < MaxSupply && _siteExists[hashedDomain] && _list[hashedDomain].size() < MaxPerDomain && !hasMinted;
  }

  // The following functions are overrides required by Solidity.

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

Contract Security Audit

Contract ABI

[{"inputs":[],"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":[{"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":[{"internalType":"string","name":"_http","type":"string"}],"name":"claimable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"string","name":"_http","type":"string"}],"name":"getMinted","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"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":"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":"string","name":"_http","type":"string"}],"name":"isValidDomain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_http","type":"string"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"mint","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":[{"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":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"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"}]

6104406040527f9649c7eb6df175f417fcfb2eeeaf6e39367ec7a45034048a3d5cff5e2ea8519f60809081527f45a2112d850d7101c902a913c185ba0d28e0ecdcfd1d540e2497f2750714f69a60a0527f0445d458f1aa05b40e476e9a57218b91110ad2174ae15f7057715e84693f710060c0527feb867819c51fbf7d44c73a332082c0b6142546289310c6ff4fac832120012ed360e0527f89ae9c604bc971f8b6a5aee73a1c4e71c952d16a3bcf995e1642f2db167bc5a7610100527f9f514643ee17437be8788be62d7db6953296791a2ad0db024063a20a97a08682610120527f94d13d04140fd5b04a3196ba600a958460fc847c28b74d6e9c1f26bb50c56b45610140527f9e01a36b730e791ed57eabb8379758d7601ffc79b6d613cb7744191938672887610160527f1345e844ae191c4c9f5ed685ecca259e4530dec934838661f002fc3ac3c3b83c610180527f588e7f25cc1ab5b40a3b6770561d285a5299071e36dbffe3cba46f5360110f5d6101a0527f6449d685d467441665612dc60098ae2a5f0e16d0e60f1d9d0b63e3c037c5df8d6101c0527fc9fc5126b89092478eb63279a7cd259ea24c24bc945b91b5c8366967b05ee6d16101e0527f574014404853e93615346db284ca5bd068542f139762d459e11e64fee33e7abd610200527f0e84102fc2bc70ee46419905395f8fb46f7c0be0c9e694e4e699b087cde9be16610220527fd14db021bc6bdaf39de490427d6a1e0e265463ff19e83094dc76f0d3150fc716610240527f4c85a4f44366822767ab3fa89b6b2a8cf6b30a44a96152d7c26a77f634f9cbe0610260527ff0ca7fdd544d43a37b1fd3242551a298fbfed3edb8403c9e925c4cde8c19fe8e610280527f207eeb1c4a1ac75d8ac74d64bfabb5e81199384099507fa4233771c134adad726102a0527f131e81156f0505f36093d6b4d5e6f14643b9f367da7fd717f3239c1599c620a86102c0527f2ccc2d85ad9b8899ddbad3cef1c367ed84bf8d19014acd04588e48f6e837436e6102e0527f702c587833b68bf050b53037adba2bb8f7f93d875c5a372389d8d6987074f503610300527fb0af795fa00c85296c52b9fa3873a6acb561de2ac8e8ae0a84338bfbbcb6a3d7610320527fa57c78e6f3324d0ef1b1412366a8b123674f9423dd1effc63656d7e48d05bc30610340527ff7f00296c339c4e3d3b2aa84cbe9a6cadb9d8aabd2eb784064fb12ecf2029b0e610360527fbf9c1eb5724df6704047f4b9f5ddb73e21e53efedd725685ab9d9820c5dc99b2610380527fcc57ea92f884c55cc87b03761c95b7d99a2324f4baec0a72a0df10cbab77911b6103a0527fdc6ab7e871c6a47b07c00e6bbd11ee902e47d00afc2191d614116b87900973dc6103c0527ff2e4f0dcb4243c2dc76aeee61f15ba1d87db55775678f6d67d7a49130db786e46103e0527f3a95202072e7adc1c3e2598fd97fd22472790fb26ec4f768f6b77c4c12995fb2610400527f6ce43a2f8178c89cac275597661b9ce9f6b7ef6a93e8c97b0ccf437dad1e511e610420526200046990600990601e6200064e565b503480156200047757600080fd5b50604080518082018252601581527f50726f7469636f204368617474696e672043686970000000000000000000000060208083019182528351808501909452600384526250434360e81b908401528151919291620004d89160009162000691565b508051620004ee90600190602084019062000691565b5050600160065550620005036000336200059a565b60405180606001604052806035815260200162002c5b603591398051620005339160299160209091019062000691565b5060005b601e8110156200059357600160286000600984601e81106200055d576200055d6200078b565b015481526020810191909152604001600020805460ff1916911515919091179055806200058a8162000761565b91505062000537565b50620007a1565b620005a68282620005aa565b5050565b60008281526007602090815260408083206001600160a01b038516845290915290205460ff16620005a65760008281526007602090815260408083206001600160a01b03851684529091529020805460ff191660011790556200060a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b82601e81019282156200067f579160200282015b828111156200067f57825182559160200191906001019062000662565b506200068d9291506200070d565b5090565b8280546200069f9062000724565b90600052602060002090601f016020900481019282620006c357600085556200067f565b82601f10620006de57805160ff19168380011785556200067f565b828001600101855582156200067f57918201828111156200067f57825182559160200191906001019062000662565b5b808211156200068d57600081556001016200070e565b600181811c908216806200073957607f821691505b602082108114156200075b57634e487b7160e01b600052602260045260246000fd5b50919050565b60006000198214156200078457634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b6124aa80620007b16000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c80636352211e116100c3578063a22cb4651161007c578063a22cb465146102f9578063b88d4fde1461030c578063c87b56dd1461031f578063d547741f14610332578063e0df5b6f14610345578063e985e9c51461035857600080fd5b80636352211e1461029057806370a08231146102a3578063821c48a4146102b657806391d14854146102d657806395d89b41146102e9578063a217fddf146102f157600080fd5b80632f2ff15d116101155780632f2ff15d1461021e57806336568abe146102315780633f4962ec1461024457806342842e0e146102575780634737576e1461026a578063484ba3921461027d57600080fd5b806301ffc9a71461015d57806306fdde0314610185578063081812fc1461019a578063095ea7b3146101c557806323b872dd146101da578063248a9ca3146101ed575b600080fd5b61017061016b366004611fd0565b610394565b60405190151581526020015b60405180910390f35b61018d6103a5565b60405161017c919061223b565b6101ad6101a8366004611f7b565b610437565b6040516001600160a01b03909116815260200161017c565b6101d86101d3366004611f34565b61045e565b005b6101d86101e8366004611e59565b610579565b6102106101fb366004611f7b565b60009081526007602052604090206001015490565b60405190815260200161017c565b6101d861022c366004611fad565b6105aa565b6101d861023f366004611fad565b6105cf565b61017061025236600461200a565b61064d565b6101d8610265366004611e59565b6107f9565b6101d861027836600461203f565b610814565b61017061028b36600461200a565b610bb9565b6101ad61029e366004611f7b565b610bfc565b6102106102b1366004611e0b565b610c5c565b6102c96102c436600461200a565b610ce2565b60405161017c91906121d5565b6101706102e4366004611fad565b610d82565b61018d610dad565b610210600081565b6101d8610307366004611efd565b610dbc565b6101d861031a366004611e95565b610dc7565b61018d61032d366004611f7b565b610dff565b6101d8610340366004611fad565b610e9c565b6101d861035336600461200a565b610ec1565b610170610366366004611e26565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600061039f82610edf565b92915050565b6060600080546103b4906123c3565b80601f01602080910402602001604051908101604052809291908181526020018280546103e0906123c3565b801561042d5780601f106104025761010080835404028352916020019161042d565b820191906000526020600020905b81548152906001019060200180831161041057829003601f168201915b5050505050905090565b600061044282610f04565b506000908152600460205260409020546001600160a01b031690565b600061046982610bfc565b9050806001600160a01b0316836001600160a01b031614156104dc5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806104f857506104f88133610366565b61056a5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016104d3565b6105748383610f66565b505050565b6105833382610fd4565b61059f5760405162461bcd60e51b81526004016104d39061224e565b610574838383611053565b6000828152600760205260409020600101546105c5816111c4565b61057483836111ce565b6001600160a01b038116331461063f5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016104d3565b6106498282611254565b5050565b600080826040516020016106619190612107565b604051602081830303815290604052805190602001209050600061068460085490565b600083815260276020526040808220905163cf1d8fd560e01b8152600481019190915233602482015291925090738828d87c8e53910485320e93e090c59715a4b2229063cf1d8fd59060440160206040518083038186803b1580156106e857600080fd5b505af41580156106fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107209190611f5e565b905061753082108015610741575060008381526028602052604090205460ff165b80156107e65750600083815260276020526040908190209051633775465d60e11b81526103e891738828d87c8e53910485320e93e090c59715a4b22291636eea8cba916107949160040190815260200190565b60206040518083038186803b1580156107ac57600080fd5b505af41580156107c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e49190611f94565b105b80156107f0575080155b95945050505050565b61057483838360405180602001604052806000815250610dc7565b61081c6112bb565b600061082760085490565b9050617530811061086a5760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420636c61696d61626c6560981b60448201526064016104d3565b60008360405160200161087d9190612107565b60408051601f1981840301815291815281516020928301206000818152602890935291205490915060ff166108ef5760405162461bcd60e51b81526020600482015260186024820152772237b6b0b4b71034b9903737ba1031b630b4b6b0b136329760411b60448201526064016104d3565b600081815260276020526040908190209051633775465d60e11b81526103e891738828d87c8e53910485320e93e090c59715a4b22291636eea8cba9161093b9160040190815260200190565b60206040518083038186803b15801561095357600080fd5b505af4158015610967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098b9190611f94565b106109d35760405162461bcd60e51b81526020600482015260186024820152772237b6b0b4b71034b9903737ba1031b630b4b6b0b136329760411b60448201526064016104d3565b6109dd8484611315565b610a1d5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b60448201526064016104d3565b600081815260276020526040808220905163cf1d8fd560e01b81526004810191909152336024820152738828d87c8e53910485320e93e090c59715a4b2229063cf1d8fd59060440160206040518083038186803b158015610a7d57600080fd5b505af4158015610a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab59190611f5e565b90508015610b1b5760405162461bcd60e51b815260206004820152602d60248201527f4164647265737320616c7265616479206861732074686520746f6b656e206f6e60448201526c103a3434b9903237b6b0b4b71760991b60648201526084016104d3565b6000828152602760205260409081902090516301a7282160e21b81526004810191909152336024820152738828d87c8e53910485320e93e090c59715a4b2229063069ca0849060440160006040518083038186803b158015610b7c57600080fd5b505af4158015610b90573d6000803e3d6000fd5b50505050610ba2600880546001019055565b610bac33846113a7565b5050506106496001600655565b60008082604051602001610bcd9190612107565b60408051601f1981840301815291815281516020928301206000908152602890925290205460ff169392505050565b6000818152600260205260408120546001600160a01b03168061039f5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016104d3565b60006001600160a01b038216610cc65760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016104d3565b506001600160a01b031660009081526003602052604090205490565b60606000610cef816111c4565b600083604051602001610d029190612107565b60408051601f1981840301815282825280516020918201206000818152602783528390208054808402860184019094528385529094509190830182828015610d7357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610d55575b50505050509250505b50919050565b60009182526007602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6060600180546103b4906123c3565b6106493383836113c1565b610dd13383610fd4565b610ded5760405162461bcd60e51b81526004016104d39061224e565b610df984848484611490565b50505050565b6060610e0a82610f04565b60298054610e17906123c3565b80601f0160208091040260200160405190810160405280929190818152602001828054610e43906123c3565b8015610e905780601f10610e6557610100808354040283529160200191610e90565b820191906000526020600020905b815481529060010190602001808311610e7357829003601f168201915b50505050509050919050565b600082815260076020526040902060010154610eb7816111c4565b6105748383611254565b6000610ecc816111c4565b8151610574906029906020850190611cc9565b60006001600160e01b03198216637965db0b60e01b148061039f575061039f826114c3565b6000818152600260205260409020546001600160a01b0316610f635760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016104d3565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610f9b82610bfc565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080610fe083610bfc565b9050806001600160a01b0316846001600160a01b0316148061102757506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b8061104b5750836001600160a01b031661104084610437565b6001600160a01b0316145b949350505050565b826001600160a01b031661106682610bfc565b6001600160a01b03161461108c5760405162461bcd60e51b81526004016104d3906122ed565b6001600160a01b0382166110ee5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016104d3565b6110fb8383836001611513565b826001600160a01b031661110e82610bfc565b6001600160a01b0316146111345760405162461bcd60e51b81526004016104d3906122ed565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b610f63813361159b565b6111d88282610d82565b6106495760008281526007602090815260408083206001600160a01b03851684529091529020805460ff191660011790556112103390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61125e8282610d82565b156106495760008281526007602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6002600654141561130e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104d3565b6002600655565b600080338460405160200161132b9291906120cf565b60405160208183030381529060405280519060200120905060008160405160200161138291907f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b60408051601f19818403018152919052805160209091012090506107f03382866115f4565b610649828260405180602001604052806000815250611738565b816001600160a01b0316836001600160a01b031614156114235760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016104d3565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61149b848484611053565b6114a78484848461176b565b610df95760405162461bcd60e51b81526004016104d39061229b565b60006001600160e01b031982166380ac58cd60e01b14806114f457506001600160e01b03198216635b5e139f60e01b145b8061039f57506301ffc9a760e01b6001600160e01b031983161461039f565b6001811115610df9576001600160a01b03841615611559576001600160a01b03841660009081526003602052604081208054839290611553908490612369565b90915550505b6001600160a01b03831615610df9576001600160a01b03831660009081526003602052604081208054839290611590908490612332565b909155505050505050565b6115a58282610d82565b610649576115b281611878565b6115bd83602061188a565b6040516020016115ce929190612123565b60408051601f198184030181529082905262461bcd60e51b82526104d39160040161223b565b60008060006116038585611a26565b9092509050600081600481111561161c5761161c61240e565b14801561163a5750856001600160a01b0316826001600160a01b0316145b1561164a57600192505050611731565b600080876001600160a01b0316631626ba7e60e01b8888604051602401611672929190612222565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516116b09190612107565b600060405180830381855afa9150503d80600081146116eb576040519150601f19603f3d011682016040523d82523d6000602084013e6116f0565b606091505b5091509150818015611703575080516020145b801561172a57508051630b135d3f60e11b906117289083016020908101908401611f94565b145b9450505050505b9392505050565b6117428383611a6c565b61174f600084848461176b565b6105745760405162461bcd60e51b81526004016104d39061229b565b60006001600160a01b0384163b1561186d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906117af903390899088908890600401612198565b602060405180830381600087803b1580156117c957600080fd5b505af19250505080156117f9575060408051601f3d908101601f191682019092526117f691810190611fed565b60015b611853573d808015611827576040519150601f19603f3d011682016040523d82523d6000602084013e61182c565b606091505b50805161184b5760405162461bcd60e51b81526004016104d39061229b565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061104b565b506001949350505050565b606061039f6001600160a01b03831660145b6060600061189983600261234a565b6118a4906002612332565b67ffffffffffffffff8111156118bc576118bc61243a565b6040519080825280601f01601f1916602001820160405280156118e6576020820181803683370190505b509050600360fc1b8160008151811061190157611901612424565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061193057611930612424565b60200101906001600160f81b031916908160001a905350600061195484600261234a565b61195f906001612332565b90505b60018111156119d7576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061199357611993612424565b1a60f81b8282815181106119a9576119a9612424565b60200101906001600160f81b031916908160001a90535060049490941c936119d0816123ac565b9050611962565b5083156117315760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104d3565b600080825160411415611a5d5760208301516040840151606085015160001a611a5187828585611c05565b94509450505050611a65565b506000905060025b9250929050565b6001600160a01b038216611ac25760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f206164647265737360448201526064016104d3565b6000818152600260205260409020546001600160a01b031615611b275760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060448201526064016104d3565b611b35600083836001611513565b6000818152600260205260409020546001600160a01b031615611b9a5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060448201526064016104d3565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611c3c5750600090506003611cc0565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611c90573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611cb957600060019250925050611cc0565b9150600090505b94509492505050565b828054611cd5906123c3565b90600052602060002090601f016020900481019282611cf75760008555611d3d565b82601f10611d1057805160ff1916838001178555611d3d565b82800160010185558215611d3d579182015b82811115611d3d578251825591602001919060010190611d22565b50611d49929150611d4d565b5090565b5b80821115611d495760008155600101611d4e565b80356001600160a01b0381168114611d7957600080fd5b919050565b600082601f830112611d8f57600080fd5b813567ffffffffffffffff80821115611daa57611daa61243a565b604051601f8301601f19908116603f01168101908282118183101715611dd257611dd261243a565b81604052838152866020858801011115611deb57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215611e1d57600080fd5b61173182611d62565b60008060408385031215611e3957600080fd5b611e4283611d62565b9150611e5060208401611d62565b90509250929050565b600080600060608486031215611e6e57600080fd5b611e7784611d62565b9250611e8560208501611d62565b9150604084013590509250925092565b60008060008060808587031215611eab57600080fd5b611eb485611d62565b9350611ec260208601611d62565b925060408501359150606085013567ffffffffffffffff811115611ee557600080fd5b611ef187828801611d7e565b91505092959194509250565b60008060408385031215611f1057600080fd5b611f1983611d62565b91506020830135611f2981612450565b809150509250929050565b60008060408385031215611f4757600080fd5b611f5083611d62565b946020939093013593505050565b600060208284031215611f7057600080fd5b815161173181612450565b600060208284031215611f8d57600080fd5b5035919050565b600060208284031215611fa657600080fd5b5051919050565b60008060408385031215611fc057600080fd5b82359150611e5060208401611d62565b600060208284031215611fe257600080fd5b81356117318161245e565b600060208284031215611fff57600080fd5b81516117318161245e565b60006020828403121561201c57600080fd5b813567ffffffffffffffff81111561203357600080fd5b61104b84828501611d7e565b6000806040838503121561205257600080fd5b823567ffffffffffffffff8082111561206a57600080fd5b61207686838701611d7e565b9350602085013591508082111561208c57600080fd5b5061209985828601611d7e565b9150509250929050565b600081518084526120bb816020860160208601612380565b601f01601f19169290920160200192915050565b6bffffffffffffffffffffffff198360601b168152600082516120f9816014850160208701612380565b919091016014019392505050565b60008251612119818460208701612380565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161215b816017850160208801612380565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161218c816028840160208801612380565b01602801949350505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906121cb908301846120a3565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156122165783516001600160a01b0316835292840192918401916001016121f1565b50909695505050505050565b82815260406020820152600061104b60408301846120a3565b60208152600061173160208301846120a3565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60008219821115612345576123456123f8565b500190565b6000816000190483118215151615612364576123646123f8565b500290565b60008282101561237b5761237b6123f8565b500390565b60005b8381101561239b578181015183820152602001612383565b83811115610df95750506000910152565b6000816123bb576123bb6123f8565b506000190190565b600181811c908216806123d757607f821691505b60208210811415610d7c57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b8015158114610f6357600080fd5b6001600160e01b031981168114610f6357600080fdfea26469706673582212200c961fe1c5a6eed832ca649f504716fcc362332384260cea33d9c392f1c1456764736f6c63430008070033697066733a2f2f516d576e394c637634506846713146455858516a70686b51795661593465777631673163786459643466547a4272

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101585760003560e01c80636352211e116100c3578063a22cb4651161007c578063a22cb465146102f9578063b88d4fde1461030c578063c87b56dd1461031f578063d547741f14610332578063e0df5b6f14610345578063e985e9c51461035857600080fd5b80636352211e1461029057806370a08231146102a3578063821c48a4146102b657806391d14854146102d657806395d89b41146102e9578063a217fddf146102f157600080fd5b80632f2ff15d116101155780632f2ff15d1461021e57806336568abe146102315780633f4962ec1461024457806342842e0e146102575780634737576e1461026a578063484ba3921461027d57600080fd5b806301ffc9a71461015d57806306fdde0314610185578063081812fc1461019a578063095ea7b3146101c557806323b872dd146101da578063248a9ca3146101ed575b600080fd5b61017061016b366004611fd0565b610394565b60405190151581526020015b60405180910390f35b61018d6103a5565b60405161017c919061223b565b6101ad6101a8366004611f7b565b610437565b6040516001600160a01b03909116815260200161017c565b6101d86101d3366004611f34565b61045e565b005b6101d86101e8366004611e59565b610579565b6102106101fb366004611f7b565b60009081526007602052604090206001015490565b60405190815260200161017c565b6101d861022c366004611fad565b6105aa565b6101d861023f366004611fad565b6105cf565b61017061025236600461200a565b61064d565b6101d8610265366004611e59565b6107f9565b6101d861027836600461203f565b610814565b61017061028b36600461200a565b610bb9565b6101ad61029e366004611f7b565b610bfc565b6102106102b1366004611e0b565b610c5c565b6102c96102c436600461200a565b610ce2565b60405161017c91906121d5565b6101706102e4366004611fad565b610d82565b61018d610dad565b610210600081565b6101d8610307366004611efd565b610dbc565b6101d861031a366004611e95565b610dc7565b61018d61032d366004611f7b565b610dff565b6101d8610340366004611fad565b610e9c565b6101d861035336600461200a565b610ec1565b610170610366366004611e26565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600061039f82610edf565b92915050565b6060600080546103b4906123c3565b80601f01602080910402602001604051908101604052809291908181526020018280546103e0906123c3565b801561042d5780601f106104025761010080835404028352916020019161042d565b820191906000526020600020905b81548152906001019060200180831161041057829003601f168201915b5050505050905090565b600061044282610f04565b506000908152600460205260409020546001600160a01b031690565b600061046982610bfc565b9050806001600160a01b0316836001600160a01b031614156104dc5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806104f857506104f88133610366565b61056a5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016104d3565b6105748383610f66565b505050565b6105833382610fd4565b61059f5760405162461bcd60e51b81526004016104d39061224e565b610574838383611053565b6000828152600760205260409020600101546105c5816111c4565b61057483836111ce565b6001600160a01b038116331461063f5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016104d3565b6106498282611254565b5050565b600080826040516020016106619190612107565b604051602081830303815290604052805190602001209050600061068460085490565b600083815260276020526040808220905163cf1d8fd560e01b8152600481019190915233602482015291925090738828d87c8e53910485320e93e090c59715a4b2229063cf1d8fd59060440160206040518083038186803b1580156106e857600080fd5b505af41580156106fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107209190611f5e565b905061753082108015610741575060008381526028602052604090205460ff165b80156107e65750600083815260276020526040908190209051633775465d60e11b81526103e891738828d87c8e53910485320e93e090c59715a4b22291636eea8cba916107949160040190815260200190565b60206040518083038186803b1580156107ac57600080fd5b505af41580156107c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e49190611f94565b105b80156107f0575080155b95945050505050565b61057483838360405180602001604052806000815250610dc7565b61081c6112bb565b600061082760085490565b9050617530811061086a5760405162461bcd60e51b815260206004820152600d60248201526c4e6f7420636c61696d61626c6560981b60448201526064016104d3565b60008360405160200161087d9190612107565b60408051601f1981840301815291815281516020928301206000818152602890935291205490915060ff166108ef5760405162461bcd60e51b81526020600482015260186024820152772237b6b0b4b71034b9903737ba1031b630b4b6b0b136329760411b60448201526064016104d3565b600081815260276020526040908190209051633775465d60e11b81526103e891738828d87c8e53910485320e93e090c59715a4b22291636eea8cba9161093b9160040190815260200190565b60206040518083038186803b15801561095357600080fd5b505af4158015610967573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098b9190611f94565b106109d35760405162461bcd60e51b81526020600482015260186024820152772237b6b0b4b71034b9903737ba1031b630b4b6b0b136329760411b60448201526064016104d3565b6109dd8484611315565b610a1d5760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b60448201526064016104d3565b600081815260276020526040808220905163cf1d8fd560e01b81526004810191909152336024820152738828d87c8e53910485320e93e090c59715a4b2229063cf1d8fd59060440160206040518083038186803b158015610a7d57600080fd5b505af4158015610a91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab59190611f5e565b90508015610b1b5760405162461bcd60e51b815260206004820152602d60248201527f4164647265737320616c7265616479206861732074686520746f6b656e206f6e60448201526c103a3434b9903237b6b0b4b71760991b60648201526084016104d3565b6000828152602760205260409081902090516301a7282160e21b81526004810191909152336024820152738828d87c8e53910485320e93e090c59715a4b2229063069ca0849060440160006040518083038186803b158015610b7c57600080fd5b505af4158015610b90573d6000803e3d6000fd5b50505050610ba2600880546001019055565b610bac33846113a7565b5050506106496001600655565b60008082604051602001610bcd9190612107565b60408051601f1981840301815291815281516020928301206000908152602890925290205460ff169392505050565b6000818152600260205260408120546001600160a01b03168061039f5760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016104d3565b60006001600160a01b038216610cc65760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016104d3565b506001600160a01b031660009081526003602052604090205490565b60606000610cef816111c4565b600083604051602001610d029190612107565b60408051601f1981840301815282825280516020918201206000818152602783528390208054808402860184019094528385529094509190830182828015610d7357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610d55575b50505050509250505b50919050565b60009182526007602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6060600180546103b4906123c3565b6106493383836113c1565b610dd13383610fd4565b610ded5760405162461bcd60e51b81526004016104d39061224e565b610df984848484611490565b50505050565b6060610e0a82610f04565b60298054610e17906123c3565b80601f0160208091040260200160405190810160405280929190818152602001828054610e43906123c3565b8015610e905780601f10610e6557610100808354040283529160200191610e90565b820191906000526020600020905b815481529060010190602001808311610e7357829003601f168201915b50505050509050919050565b600082815260076020526040902060010154610eb7816111c4565b6105748383611254565b6000610ecc816111c4565b8151610574906029906020850190611cc9565b60006001600160e01b03198216637965db0b60e01b148061039f575061039f826114c3565b6000818152600260205260409020546001600160a01b0316610f635760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016104d3565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190610f9b82610bfc565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b600080610fe083610bfc565b9050806001600160a01b0316846001600160a01b0316148061102757506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b8061104b5750836001600160a01b031661104084610437565b6001600160a01b0316145b949350505050565b826001600160a01b031661106682610bfc565b6001600160a01b03161461108c5760405162461bcd60e51b81526004016104d3906122ed565b6001600160a01b0382166110ee5760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016104d3565b6110fb8383836001611513565b826001600160a01b031661110e82610bfc565b6001600160a01b0316146111345760405162461bcd60e51b81526004016104d3906122ed565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b610f63813361159b565b6111d88282610d82565b6106495760008281526007602090815260408083206001600160a01b03851684529091529020805460ff191660011790556112103390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b61125e8282610d82565b156106495760008281526007602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6002600654141561130e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016104d3565b6002600655565b600080338460405160200161132b9291906120cf565b60405160208183030381529060405280519060200120905060008160405160200161138291907f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b60408051601f19818403018152919052805160209091012090506107f03382866115f4565b610649828260405180602001604052806000815250611738565b816001600160a01b0316836001600160a01b031614156114235760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016104d3565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61149b848484611053565b6114a78484848461176b565b610df95760405162461bcd60e51b81526004016104d39061229b565b60006001600160e01b031982166380ac58cd60e01b14806114f457506001600160e01b03198216635b5e139f60e01b145b8061039f57506301ffc9a760e01b6001600160e01b031983161461039f565b6001811115610df9576001600160a01b03841615611559576001600160a01b03841660009081526003602052604081208054839290611553908490612369565b90915550505b6001600160a01b03831615610df9576001600160a01b03831660009081526003602052604081208054839290611590908490612332565b909155505050505050565b6115a58282610d82565b610649576115b281611878565b6115bd83602061188a565b6040516020016115ce929190612123565b60408051601f198184030181529082905262461bcd60e51b82526104d39160040161223b565b60008060006116038585611a26565b9092509050600081600481111561161c5761161c61240e565b14801561163a5750856001600160a01b0316826001600160a01b0316145b1561164a57600192505050611731565b600080876001600160a01b0316631626ba7e60e01b8888604051602401611672929190612222565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516116b09190612107565b600060405180830381855afa9150503d80600081146116eb576040519150601f19603f3d011682016040523d82523d6000602084013e6116f0565b606091505b5091509150818015611703575080516020145b801561172a57508051630b135d3f60e11b906117289083016020908101908401611f94565b145b9450505050505b9392505050565b6117428383611a6c565b61174f600084848461176b565b6105745760405162461bcd60e51b81526004016104d39061229b565b60006001600160a01b0384163b1561186d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a02906117af903390899088908890600401612198565b602060405180830381600087803b1580156117c957600080fd5b505af19250505080156117f9575060408051601f3d908101601f191682019092526117f691810190611fed565b60015b611853573d808015611827576040519150601f19603f3d011682016040523d82523d6000602084013e61182c565b606091505b50805161184b5760405162461bcd60e51b81526004016104d39061229b565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905061104b565b506001949350505050565b606061039f6001600160a01b03831660145b6060600061189983600261234a565b6118a4906002612332565b67ffffffffffffffff8111156118bc576118bc61243a565b6040519080825280601f01601f1916602001820160405280156118e6576020820181803683370190505b509050600360fc1b8160008151811061190157611901612424565b60200101906001600160f81b031916908160001a905350600f60fb1b8160018151811061193057611930612424565b60200101906001600160f81b031916908160001a905350600061195484600261234a565b61195f906001612332565b90505b60018111156119d7576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061199357611993612424565b1a60f81b8282815181106119a9576119a9612424565b60200101906001600160f81b031916908160001a90535060049490941c936119d0816123ac565b9050611962565b5083156117315760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016104d3565b600080825160411415611a5d5760208301516040840151606085015160001a611a5187828585611c05565b94509450505050611a65565b506000905060025b9250929050565b6001600160a01b038216611ac25760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f206164647265737360448201526064016104d3565b6000818152600260205260409020546001600160a01b031615611b275760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060448201526064016104d3565b611b35600083836001611513565b6000818152600260205260409020546001600160a01b031615611b9a5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e7465640000000060448201526064016104d3565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115611c3c5750600090506003611cc0565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611c90573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611cb957600060019250925050611cc0565b9150600090505b94509492505050565b828054611cd5906123c3565b90600052602060002090601f016020900481019282611cf75760008555611d3d565b82601f10611d1057805160ff1916838001178555611d3d565b82800160010185558215611d3d579182015b82811115611d3d578251825591602001919060010190611d22565b50611d49929150611d4d565b5090565b5b80821115611d495760008155600101611d4e565b80356001600160a01b0381168114611d7957600080fd5b919050565b600082601f830112611d8f57600080fd5b813567ffffffffffffffff80821115611daa57611daa61243a565b604051601f8301601f19908116603f01168101908282118183101715611dd257611dd261243a565b81604052838152866020858801011115611deb57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060208284031215611e1d57600080fd5b61173182611d62565b60008060408385031215611e3957600080fd5b611e4283611d62565b9150611e5060208401611d62565b90509250929050565b600080600060608486031215611e6e57600080fd5b611e7784611d62565b9250611e8560208501611d62565b9150604084013590509250925092565b60008060008060808587031215611eab57600080fd5b611eb485611d62565b9350611ec260208601611d62565b925060408501359150606085013567ffffffffffffffff811115611ee557600080fd5b611ef187828801611d7e565b91505092959194509250565b60008060408385031215611f1057600080fd5b611f1983611d62565b91506020830135611f2981612450565b809150509250929050565b60008060408385031215611f4757600080fd5b611f5083611d62565b946020939093013593505050565b600060208284031215611f7057600080fd5b815161173181612450565b600060208284031215611f8d57600080fd5b5035919050565b600060208284031215611fa657600080fd5b5051919050565b60008060408385031215611fc057600080fd5b82359150611e5060208401611d62565b600060208284031215611fe257600080fd5b81356117318161245e565b600060208284031215611fff57600080fd5b81516117318161245e565b60006020828403121561201c57600080fd5b813567ffffffffffffffff81111561203357600080fd5b61104b84828501611d7e565b6000806040838503121561205257600080fd5b823567ffffffffffffffff8082111561206a57600080fd5b61207686838701611d7e565b9350602085013591508082111561208c57600080fd5b5061209985828601611d7e565b9150509250929050565b600081518084526120bb816020860160208601612380565b601f01601f19169290920160200192915050565b6bffffffffffffffffffffffff198360601b168152600082516120f9816014850160208701612380565b919091016014019392505050565b60008251612119818460208701612380565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161215b816017850160208801612380565b7001034b99036b4b9b9b4b733903937b6329607d1b601791840191820152835161218c816028840160208801612380565b01602801949350505050565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906121cb908301846120a3565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b818110156122165783516001600160a01b0316835292840192918401916001016121f1565b50909695505050505050565b82815260406020820152600061104b60408301846120a3565b60208152600061173160208301846120a3565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60008219821115612345576123456123f8565b500190565b6000816000190483118215151615612364576123646123f8565b500290565b60008282101561237b5761237b6123f8565b500390565b60005b8381101561239b578181015183820152602001612383565b83811115610df95750506000910152565b6000816123bb576123bb6123f8565b506000190190565b600181811c908216806123d757607f821691505b60208210811415610d7c57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b8015158114610f6357600080fd5b6001600160e01b031981168114610f6357600080fdfea26469706673582212200c961fe1c5a6eed832ca649f504716fcc362332384260cea33d9c392f1c1456764736f6c63430008070033

Libraries Used


Deployed Bytecode Sourcemap

79783:5663:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;85258:185;;;;;;:::i;:::-;;:::i;:::-;;;9386:14:1;;9379:22;9361:41;;9349:2;9334:18;85258:185:0;;;;;;;;52372:100;;;:::i;:::-;;;;;;;:::i;53884:171::-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;8021:32:1;;;8003:51;;7991:2;7976:18;53884:171:0;7857:203:1;53402:416:0;;;;;;:::i;:::-;;:::i;:::-;;54584:335;;;;;;:::i;:::-;;:::i;74725:131::-;;;;;;:::i;:::-;74799:7;74826:12;;;:6;:12;;;;;:22;;;;74725:131;;;;9559:25:1;;;9547:2;9532:18;74725:131:0;9413:177:1;75166:147:0;;;;;;:::i;:::-;;:::i;76310:218::-;;;;;;:::i;:::-;;:::i;84813:371::-;;;;;;:::i;:::-;;:::i;54990:185::-;;;;;;:::i;:::-;;:::i;83026:746::-;;;;;;:::i;:::-;;:::i;84623:184::-;;;;;;:::i;:::-;;:::i;52082:223::-;;;;;;:::i;:::-;;:::i;51813:207::-;;;;;;:::i;:::-;;:::i;84399:218::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;73198:147::-;;;;;;:::i;:::-;;:::i;52541:104::-;;;:::i;72303:49::-;;72348:4;72303:49;;54127:155;;;;;;:::i;:::-;;:::i;55246:322::-;;;;;;:::i;:::-;;:::i;84244:149::-;;;;;;:::i;:::-;;:::i;75606:::-;;;;;;:::i;:::-;;:::i;84122:116::-;;;;;;:::i;:::-;;:::i;54353:164::-;;;;;;:::i;:::-;-1:-1:-1;;;;;54474:25:0;;;54450:4;54474:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;54353:164;85258:185;85378:4;85401:36;85425:11;85401:23;:36::i;:::-;85394:43;85258:185;-1:-1:-1;;85258:185:0:o;52372:100::-;52426:13;52459:5;52452:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;52372:100;:::o;53884:171::-;53960:7;53980:23;53995:7;53980:14;:23::i;:::-;-1:-1:-1;54023:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;54023:24:0;;53884:171::o;53402:416::-;53483:13;53499:23;53514:7;53499:14;:23::i;:::-;53483:39;;53547:5;-1:-1:-1;;;;;53541:11:0;:2;-1:-1:-1;;;;;53541:11:0;;;53533:57;;;;-1:-1:-1;;;53533:57:0;;16012:2:1;53533:57:0;;;15994:21:1;16051:2;16031:18;;;16024:30;16090:34;16070:18;;;16063:62;-1:-1:-1;;;16141:18:1;;;16134:31;16182:19;;53533:57:0;;;;;;;;;49903:10;-1:-1:-1;;;;;53625:21:0;;;;:62;;-1:-1:-1;53650:37:0;53667:5;49903:10;54353:164;:::i;53650:37::-;53603:173;;;;-1:-1:-1;;;53603:173:0;;16414:2:1;53603:173:0;;;16396:21:1;16453:2;16433:18;;;16426:30;16492:34;16472:18;;;16465:62;16563:31;16543:18;;;16536:59;16612:19;;53603:173:0;16212:425:1;53603:173:0;53789:21;53798:2;53802:7;53789:8;:21::i;:::-;53472:346;53402:416;;:::o;54584:335::-;54779:41;49903:10;54812:7;54779:18;:41::i;:::-;54771:99;;;;-1:-1:-1;;;54771:99:0;;;;;;;:::i;:::-;54883:28;54893:4;54899:2;54903:7;54883:9;:28::i;75166:147::-;74799:7;74826:12;;;:6;:12;;;;;:22;;;72794:16;72805:4;72794:10;:16::i;:::-;75280:25:::1;75291:4;75297:7;75280:10;:25::i;76310:218::-:0;-1:-1:-1;;;;;76406:23:0;;49903:10;76406:23;76398:83;;;;-1:-1:-1;;;76398:83:0;;17204:2:1;76398:83:0;;;17186:21:1;17243:2;17223:18;;;17216:30;17282:34;17262:18;;;17255:62;-1:-1:-1;;;17333:18:1;;;17326:45;17388:19;;76398:83:0;17002:411:1;76398:83:0;76494:26;76506:4;76512:7;76494:11;:26::i;:::-;76310:218;;:::o;84813:371::-;84876:4;84889:20;84939:5;84922:23;;;;;;;;:::i;:::-;;;;;;;;;;;;;84912:34;;;;;;84889:57;;84953:15;84971:25;:15;964:14;;872:114;84971:25;85003:14;85020:19;;;:5;:19;;;;;;:35;;-1:-1:-1;;;85020:35:0;;;;;17834:25:1;;;;85044:10:0;17875:18:1;;;17868:60;84953:43:0;;-1:-1:-1;85003:14:0;85020:23;;;;17807:18:1;;85020:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85003:52;;80052:5;85071:7;:19;:48;;;;-1:-1:-1;85094:25:0;;;;:11;:25;;;;;;;;85071:48;:93;;;;-1:-1:-1;85123:19:0;;;;:5;:19;;;;;;;:26;;-1:-1:-1;;;85123:26:0;;80094:4;;85123:24;;;;:26;;;;9559:25:1;;;9547:2;9532:18;;9413:177;85123:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;85071:93;:107;;;;;85169:9;85168:10;85071:107;85064:114;84813:371;-1:-1:-1;;;;;84813:371:0:o;54990:185::-;55128:39;55145:4;55151:2;55155:7;55128:39;;;;;;;;;;;;:16;:39::i;83026:746::-;4864:21;:19;:21::i;:::-;83130:15:::1;83148:25;:15;964:14:::0;;872:114;83148:25:::1;83130:43;;80052:5;83188:7;:19;83180:45;;;::::0;-1:-1:-1;;;83180:45:0;;14546:2:1;83180:45:0::1;::::0;::::1;14528:21:1::0;14585:2;14565:18;;;14558:30;-1:-1:-1;;;14604:18:1;;;14597:43;14657:18;;83180:45:0::1;14344:337:1::0;83180:45:0::1;83234:20;83284:5;83267:23;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;83267:23:0;;::::1;::::0;;;;;;83257:34;;83267:23:::1;83257:34:::0;;::::1;::::0;83306:25:::1;::::0;;;:11:::1;:25:::0;;;;;;83257:34;;-1:-1:-1;83306:25:0::1;;83298:62;;;::::0;-1:-1:-1;;;83298:62:0;;13088:2:1;83298:62:0::1;::::0;::::1;13070:21:1::0;13127:2;13107:18;;;13100:30;-1:-1:-1;;;13146:18:1;;;13139:54;13210:18;;83298:62:0::1;12886:348:1::0;83298:62:0::1;83375:19;::::0;;;:5:::1;:19;::::0;;;;;;:26;;-1:-1:-1;;;83375:26:0;;80094:4:::1;::::0;83375:24:::1;::::0;::::1;::::0;:26:::1;::::0;::::1;;9559:25:1::0;;;9547:2;9532:18;;9413:177;83375:26:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;83367:78;;;::::0;-1:-1:-1;;;83367:78:0;;13088:2:1;83367:78:0::1;::::0;::::1;13070:21:1::0;13127:2;13107:18;;;13100:30;-1:-1:-1;;;13146:18:1;;;13139:54;13210:18;;83367:78:0::1;12886:348:1::0;83367:78:0::1;83460:35;83477:5;83484:10;83460:16;:35::i;:::-;83452:65;;;::::0;-1:-1:-1;;;83452:65:0;;14200:2:1;83452:65:0::1;::::0;::::1;14182:21:1::0;14239:2;14219:18;;;14212:30;-1:-1:-1;;;14258:18:1;;;14251:47;14315:18;;83452:65:0::1;13998:341:1::0;83452:65:0::1;83526:14;83543:19:::0;;;:5:::1;:19;::::0;;;;;:35;;-1:-1:-1;;;83543:35:0;;::::1;::::0;::::1;17834:25:1::0;;;;83567:10:0::1;17875:18:1::0;;;17868:60;83543:23:0::1;::::0;::::1;::::0;17807:18:1;;83543:35:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83526:52;;83594:9;83593:10;83585:68;;;::::0;-1:-1:-1;;;83585:68:0;;11911:2:1;83585:68:0::1;::::0;::::1;11893:21:1::0;11950:2;11930:18;;;11923:30;11989:34;11969:18;;;11962:62;-1:-1:-1;;;12040:18:1;;;12033:43;12093:19;;83585:68:0::1;11709:409:1::0;83585:68:0::1;83660:19;::::0;;;:5:::1;:19;::::0;;;;;;:35;;-1:-1:-1;;;83660:35:0;;::::1;::::0;::::1;17834:25:1::0;;;;83684:10:0::1;17875:18:1::0;;;17868:60;83660:23:0::1;::::0;::::1;::::0;17807:18:1;;83660:35:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;83702:27;:15;1083:19:::0;;1101:1;1083:19;;;994:127;83702:27:::1;83736:30;83746:10;83758:7;83736:9;:30::i;:::-;83123:649;;;4908:20:::0;4302:1;5428:7;:22;5245:213;84623:184;84690:4;84703:20;84753:5;84736:23;;;;;;;;:::i;:::-;;;;-1:-1:-1;;84736:23:0;;;;;;;;;84726:34;;84736:23;84726:34;;;;84776:25;;;;:11;:25;;;;;;;;;84623:184;-1:-1:-1;;;84623:184:0:o;52082:223::-;52154:7;56969:16;;;:7;:16;;;;;;-1:-1:-1;;;;;56969:16:0;;52218:56;;;;-1:-1:-1;;;52218:56:0;;15659:2:1;52218:56:0;;;15641:21:1;15698:2;15678:18;;;15671:30;-1:-1:-1;;;15717:18:1;;;15710:54;15781:18;;52218:56:0;15457:348:1;51813:207:0;51885:7;-1:-1:-1;;;;;51913:19:0;;51905:73;;;;-1:-1:-1;;;51905:73:0;;14888:2:1;51905:73:0;;;14870:21:1;14927:2;14907:18;;;14900:30;14966:34;14946:18;;;14939:62;-1:-1:-1;;;15017:18:1;;;15010:39;15066:19;;51905:73:0;14686:405:1;51905:73:0;-1:-1:-1;;;;;;51996:16:0;;;;;:9;:16;;;;;;;51813:207::o;84399:218::-;84491:16;72348:4;72794:16;72348:4;72794:10;:16::i;:::-;84516:20:::1;84566:5;84549:23;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;84549:23:0;;::::1;::::0;;;;;;84539:34;;84549:23:::1;84539:34:::0;;::::1;::::0;84587:19:::1;::::0;;;:5:::1;:19:::0;;;;;84580:31;;;;::::1;::::0;;;;;;;;;;84539:34;;-1:-1:-1;84587:19:0;84580:31;;::::1;84587:19:::0;84580:31;;::::1;;;;;;;;;;;;;;;;::::0;;-1:-1:-1;;;;;84580:31:0::1;::::0;;;;;::::1;::::0;::::1;;::::0;;::::1;;;;;;;;;;;;72821:1;84399:218:::0;;;;:::o;73198:147::-;73284:4;73308:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;73308:29:0;;;;;;;;;;;;;;;73198:147::o;52541:104::-;52597:13;52630:7;52623:14;;;;;:::i;54127:155::-;54222:52;49903:10;54255:8;54265;54222:18;:52::i;55246:322::-;55420:41;49903:10;55453:7;55420:18;:41::i;:::-;55412:99;;;;-1:-1:-1;;;55412:99:0;;;;;;;:::i;:::-;55522:38;55536:4;55542:2;55546:7;55555:4;55522:13;:38::i;:::-;55246:322;;;;:::o;84244:149::-;84317:13;84339:23;84354:7;84339:14;:23::i;:::-;84378:9;84371:16;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;84244:149;;;:::o;75606:::-;74799:7;74826:12;;;:6;:12;;;;;:22;;;72794:16;72805:4;72794:10;:16::i;:::-;75721:26:::1;75733:4;75739:7;75721:11;:26::i;84122:116::-:0;72348:4;72794:16;72348:4;72794:10;:16::i;:::-;84216;;::::1;::::0;:9:::1;::::0;:16:::1;::::0;::::1;::::0;::::1;:::i;72902:204::-:0;72987:4;-1:-1:-1;;;;;;73011:47:0;;-1:-1:-1;;;73011:47:0;;:87;;;73062:36;73086:11;73062:23;:36::i;63703:135::-;57371:4;56969:16;;;:7;:16;;;;;;-1:-1:-1;;;;;56969:16:0;63777:53;;;;-1:-1:-1;;;63777:53:0;;15659:2:1;63777:53:0;;;15641:21:1;15698:2;15678:18;;;15671:30;-1:-1:-1;;;15717:18:1;;;15710:54;15781:18;;63777:53:0;15457:348:1;63777:53:0;63703:135;:::o;62982:174::-;63057:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;63057:29:0;-1:-1:-1;;;;;63057:29:0;;;;;;;;:24;;63111:23;63057:24;63111:14;:23::i;:::-;-1:-1:-1;;;;;63102:46:0;;;;;;;;;;;62982:174;;:::o;57601:264::-;57694:4;57711:13;57727:23;57742:7;57727:14;:23::i;:::-;57711:39;;57780:5;-1:-1:-1;;;;;57769:16:0;:7;-1:-1:-1;;;;;57769:16:0;;:52;;;-1:-1:-1;;;;;;54474:25:0;;;54450:4;54474:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;57789:32;57769:87;;;;57849:7;-1:-1:-1;;;;;57825:31:0;:20;57837:7;57825:11;:20::i;:::-;-1:-1:-1;;;;;57825:31:0;;57769:87;57761:96;57601:264;-1:-1:-1;;;;57601:264:0:o;61600:1263::-;61759:4;-1:-1:-1;;;;;61732:31:0;:23;61747:7;61732:14;:23::i;:::-;-1:-1:-1;;;;;61732:31:0;;61724:81;;;;-1:-1:-1;;;61724:81:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;61824:16:0;;61816:65;;;;-1:-1:-1;;;61816:65:0;;13441:2:1;61816:65:0;;;13423:21:1;13480:2;13460:18;;;13453:30;13519:34;13499:18;;;13492:62;-1:-1:-1;;;13570:18:1;;;13563:34;13614:19;;61816:65:0;13239:400:1;61816:65:0;61894:42;61915:4;61921:2;61925:7;61934:1;61894:20;:42::i;:::-;62066:4;-1:-1:-1;;;;;62039:31:0;:23;62054:7;62039:14;:23::i;:::-;-1:-1:-1;;;;;62039:31:0;;62031:81;;;;-1:-1:-1;;;62031:81:0;;;;;;;:::i;:::-;62184:24;;;;:15;:24;;;;;;;;62177:31;;-1:-1:-1;;;;;;62177:31:0;;;;;;-1:-1:-1;;;;;62660:15:0;;;;;;:9;:15;;;;;:20;;-1:-1:-1;;62660:20:0;;;62695:13;;;;;;;;;:18;;62177:31;62695:18;;;62735:16;;;:7;:16;;;;;;:21;;;;;;;;;;62774:27;;62200:7;;62774:27;;;53472:346;53402:416;;:::o;73649:105::-;73716:30;73727:4;49903:10;73716;:30::i;77907:238::-;77991:22;77999:4;78005:7;77991;:22::i;:::-;77986:152;;78030:12;;;;:6;:12;;;;;;;;-1:-1:-1;;;;;78030:29:0;;;;;;;;;:36;;-1:-1:-1;;78030:36:0;78062:4;78030:36;;;78113:12;49903:10;;49823:98;78113:12;-1:-1:-1;;;;;78086:40:0;78104:7;-1:-1:-1;;;;;78086:40:0;78098:4;78086:40;;;;;;;;;;77907:238;;:::o;78325:239::-;78409:22;78417:4;78423:7;78409;:22::i;:::-;78405:152;;;78480:5;78448:12;;;:6;:12;;;;;;;;-1:-1:-1;;;;;78448:29:0;;;;;;;;;;:37;;-1:-1:-1;;78448:37:0;;;78505:40;49903:10;;78448:12;;78505:40;;78480:5;78505:40;78325:239;;:::o;4944:293::-;4346:1;5078:7;;:19;;5070:63;;;;-1:-1:-1;;;5070:63:0;;16844:2:1;5070:63:0;;;16826:21:1;16883:2;16863:18;;;16856:30;16922:33;16902:18;;;16895:61;16973:18;;5070:63:0;16642:355:1;5070:63:0;4346:1;5211:7;:18;4944:293::o;83778:338::-;83873:4;83888:14;83932:10;83944:5;83915:35;;;;;;;;;:::i;:::-;;;;;;;;;;;;;83905:46;;;;;;83888:63;;83960:12;84038:6;83985:60;;;;;;;6923:66:1;6911:79;;7015:2;7006:12;;6999:28;;;;7052:2;7043:12;;6681:380;83985:60:0;;;;-1:-1:-1;;83985:60:0;;;;;;;;;83975:71;;83985:60;83975:71;;;;;-1:-1:-1;84062:48:0;:10;83975:71;84099:10;84062:30;:48::i;58207:110::-;58283:26;58293:2;58297:7;58283:26;;;;;;;;;;;;:9;:26::i;63299:315::-;63454:8;-1:-1:-1;;;;;63445:17:0;:5;-1:-1:-1;;;;;63445:17:0;;;63437:55;;;;-1:-1:-1;;;63437:55:0;;13846:2:1;63437:55:0;;;13828:21:1;13885:2;13865:18;;;13858:30;13924:27;13904:18;;;13897:55;13969:18;;63437:55:0;13644:349:1;63437:55:0;-1:-1:-1;;;;;63503:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;63503:46:0;;;;;;;;;;63565:41;;9361::1;;;63565::0;;9334:18:1;63565:41:0;;;;;;;63299:315;;;:::o;56449:313::-;56605:28;56615:4;56621:2;56625:7;56605:9;:28::i;:::-;56652:47;56675:4;56681:2;56685:7;56694:4;56652:22;:47::i;:::-;56644:110;;;;-1:-1:-1;;;56644:110:0;;;;;;;:::i;51444:305::-;51546:4;-1:-1:-1;;;;;;51583:40:0;;-1:-1:-1;;;51583:40:0;;:105;;-1:-1:-1;;;;;;;51640:48:0;;-1:-1:-1;;;51640:48:0;51583:105;:158;;;-1:-1:-1;;;;;;;;;;23417:40:0;;;51705:36;23308:157;65987:410;66177:1;66165:9;:13;66161:229;;;-1:-1:-1;;;;;66199:18:0;;;66195:87;;-1:-1:-1;;;;;66238:15:0;;;;;;:9;:15;;;;;:28;;66257:9;;66238:15;:28;;66257:9;;66238:28;:::i;:::-;;;;-1:-1:-1;;66195:87:0;-1:-1:-1;;;;;66300:16:0;;;66296:83;;-1:-1:-1;;;;;66337:13:0;;;;;;:9;:13;;;;;:26;;66354:9;;66337:13;:26;;66354:9;;66337:26;:::i;:::-;;;;-1:-1:-1;;65987:410:0;;;;:::o;74044:492::-;74133:22;74141:4;74147:7;74133;:22::i;:::-;74128:401;;74321:28;74341:7;74321:19;:28::i;:::-;74422:38;74450:4;74457:2;74422:19;:38::i;:::-;74226:257;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;74226:257:0;;;;;;;;;;-1:-1:-1;;;74172:345:0;;;;;;;:::i;48454:683::-;48594:4;48612:17;48631:24;48659:33;48676:4;48682:9;48659:16;:33::i;:::-;48611:81;;-1:-1:-1;48611:81:0;-1:-1:-1;48716:26:0;48707:5;:35;;;;;;;;:::i;:::-;;:58;;;;;48759:6;-1:-1:-1;;;;;48746:19:0;:9;-1:-1:-1;;;;;48746:19:0;;48707:58;48703:102;;;48789:4;48782:11;;;;;;48703:102;48818:12;48832:19;48855:6;-1:-1:-1;;;;;48855:17:0;48910:34;;;48946:4;48952:9;48887:75;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;48887:75:0;;;;;;;;;;;;;;-1:-1:-1;;;;;48887:75:0;-1:-1:-1;;;;;;48887:75:0;;;;;;;;;;48855:118;;;;48887:75;48855:118;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;48817:156;;;;48992:7;:43;;;;;49016:6;:13;49033:2;49016:19;48992:43;:136;;;;-1:-1:-1;49052:29:0;;-1:-1:-1;;;49093:34:0;49052:29;;;;;;;;;;;;:::i;:::-;:76;48992:136;48984:145;;;;;;48454:683;;;;;;:::o;58544:319::-;58673:18;58679:2;58683:7;58673:5;:18::i;:::-;58724:53;58755:1;58759:2;58763:7;58772:4;58724:22;:53::i;:::-;58702:153;;;;-1:-1:-1;;;58702:153:0;;;;;;;:::i;64402:853::-;64556:4;-1:-1:-1;;;;;64577:13:0;;7709:19;:23;64573:675;;64613:71;;-1:-1:-1;;;64613:71:0;;-1:-1:-1;;;;;64613:36:0;;;;;:71;;49903:10;;64664:4;;64670:7;;64679:4;;64613:71;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;64613:71:0;;;;;;;;-1:-1:-1;;64613:71:0;;;;;;;;;;;;:::i;:::-;;;64609:584;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;64854:13:0;;64850:328;;64897:60;;-1:-1:-1;;;64897:60:0;;;;;;;:::i;64850:328::-;65128:6;65122:13;65113:6;65109:2;65105:15;65098:38;64609:584;-1:-1:-1;;;;;;64735:51:0;-1:-1:-1;;;64735:51:0;;-1:-1:-1;64728:58:0;;64573:675;-1:-1:-1;65232:4:0;64402:853;;;;;;:::o;38513:151::-;38571:13;38604:52;-1:-1:-1;;;;;38616:22:0;;36668:2;37909:447;37984:13;38010:19;38042:10;38046:6;38042:1;:10;:::i;:::-;:14;;38055:1;38042:14;:::i;:::-;38032:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;38032:25:0;;38010:47;;-1:-1:-1;;;38068:6:0;38075:1;38068:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;38068:15:0;;;;;;;;;-1:-1:-1;;;38094:6:0;38101:1;38094:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;38094:15:0;;;;;;;;-1:-1:-1;38125:9:0;38137:10;38141:6;38137:1;:10;:::i;:::-;:14;;38150:1;38137:14;:::i;:::-;38125:26;;38120:131;38157:1;38153;:5;38120:131;;;-1:-1:-1;;;38201:5:0;38209:3;38201:11;38192:21;;;;;;;:::i;:::-;;;;38180:6;38187:1;38180:9;;;;;;;;:::i;:::-;;;;:33;-1:-1:-1;;;;;38180:33:0;;;;;;;;-1:-1:-1;38238:1:0;38228:11;;;;;38160:3;;;:::i;:::-;;;38120:131;;;-1:-1:-1;38269:10:0;;38261:55;;;;-1:-1:-1;;;38261:55:0;;10717:2:1;38261:55:0;;;10699:21:1;;;10736:18;;;10729:30;10795:34;10775:18;;;10768:62;10847:18;;38261:55:0;10515:356:1;40878:747:0;40959:7;40968:12;40997:9;:16;41017:2;40997:22;40993:625;;;41341:4;41326:20;;41320:27;41391:4;41376:20;;41370:27;41449:4;41434:20;;41428:27;41036:9;41420:36;41492:25;41503:4;41420:36;41320:27;41370;41492:10;:25::i;:::-;41485:32;;;;;;;;;40993:625;-1:-1:-1;41566:1:0;;-1:-1:-1;41570:35:0;40993:625;40878:747;;;;;:::o;59199:942::-;-1:-1:-1;;;;;59279:16:0;;59271:61;;;;-1:-1:-1;;;59271:61:0;;15298:2:1;59271:61:0;;;15280:21:1;;;15317:18;;;15310:30;15376:34;15356:18;;;15349:62;15428:18;;59271:61:0;15096:356:1;59271:61:0;57371:4;56969:16;;;:7;:16;;;;;;-1:-1:-1;;;;;56969:16:0;57395:31;59343:58;;;;-1:-1:-1;;;59343:58:0;;12731:2:1;59343:58:0;;;12713:21:1;12770:2;12750:18;;;12743:30;12809;12789:18;;;12782:58;12857:18;;59343:58:0;12529:352:1;59343:58:0;59414:48;59443:1;59447:2;59451:7;59460:1;59414:20;:48::i;:::-;57371:4;56969:16;;;:7;:16;;;;;;-1:-1:-1;;;;;56969:16:0;57395:31;59552:58;;;;-1:-1:-1;;;59552:58:0;;12731:2:1;59552:58:0;;;12713:21:1;12770:2;12750:18;;;12743:30;12809;12789:18;;;12782:58;12857:18;;59552:58:0;12529:352:1;59552:58:0;-1:-1:-1;;;;;59959:13:0;;;;;;:9;:13;;;;;;;;:18;;59976:1;59959:18;;;60001:16;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;60001:21:0;;;;;60040:33;60009:7;;59959:13;;60040:33;;59959:13;;60040:33;76310:218;;:::o;43879:1520::-;44010:7;;44944:66;44931:79;;44927:163;;;-1:-1:-1;45043:1:0;;-1:-1:-1;45047:30:0;45027:51;;44927:163;45204:24;;;45187:14;45204:24;;;;;;;;;10115:25:1;;;10188:4;10176:17;;10156:18;;;10149:45;;;;10210:18;;;10203:34;;;10253:18;;;10246:34;;;45204:24:0;;10087:19:1;;45204:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;45204:24:0;;-1:-1:-1;;45204:24:0;;;-1:-1:-1;;;;;;;45243:20:0;;45239:103;;45296:1;45300:29;45280:50;;;;;;;45239:103;45362:6;-1:-1:-1;45370:20:0;;-1:-1:-1;43879:1520:0;;;;;;;;:::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:173:1;82:20;;-1:-1:-1;;;;;131:31:1;;121:42;;111:70;;177:1;174;167:12;111:70;14:173;;;:::o;192:718::-;234:5;287:3;280:4;272:6;268:17;264:27;254:55;;305:1;302;295:12;254:55;341:6;328:20;367:18;404:2;400;397:10;394:36;;;410:18;;:::i;:::-;485:2;479:9;453:2;539:13;;-1:-1:-1;;535:22:1;;;559:2;531:31;527:40;515:53;;;583:18;;;603:22;;;580:46;577:72;;;629:18;;:::i;:::-;669:10;665:2;658:22;704:2;696:6;689:18;750:3;743:4;738:2;730:6;726:15;722:26;719:35;716:55;;;767:1;764;757:12;716:55;831:2;824:4;816:6;812:17;805:4;797:6;793:17;780:54;878:1;871:4;866:2;858:6;854:15;850:26;843:37;898:6;889:15;;;;;;192:718;;;;:::o;915:186::-;974:6;1027:2;1015:9;1006:7;1002:23;998:32;995:52;;;1043:1;1040;1033:12;995:52;1066:29;1085:9;1066:29;:::i;1106:260::-;1174:6;1182;1235:2;1223:9;1214:7;1210:23;1206:32;1203:52;;;1251:1;1248;1241:12;1203:52;1274:29;1293:9;1274:29;:::i;:::-;1264:39;;1322:38;1356:2;1345:9;1341:18;1322:38;:::i;:::-;1312:48;;1106:260;;;;;:::o;1371:328::-;1448:6;1456;1464;1517:2;1505:9;1496:7;1492:23;1488:32;1485:52;;;1533:1;1530;1523:12;1485:52;1556:29;1575:9;1556:29;:::i;:::-;1546:39;;1604:38;1638:2;1627:9;1623:18;1604:38;:::i;:::-;1594:48;;1689:2;1678:9;1674:18;1661:32;1651:42;;1371:328;;;;;:::o;1704:537::-;1799:6;1807;1815;1823;1876:3;1864:9;1855:7;1851:23;1847:33;1844:53;;;1893:1;1890;1883:12;1844:53;1916:29;1935:9;1916:29;:::i;:::-;1906:39;;1964:38;1998:2;1987:9;1983:18;1964:38;:::i;:::-;1954:48;;2049:2;2038:9;2034:18;2021:32;2011:42;;2104:2;2093:9;2089:18;2076:32;2131:18;2123:6;2120:30;2117:50;;;2163:1;2160;2153:12;2117:50;2186:49;2227:7;2218:6;2207:9;2203:22;2186:49;:::i;:::-;2176:59;;;1704:537;;;;;;;:::o;2246:315::-;2311:6;2319;2372:2;2360:9;2351:7;2347:23;2343:32;2340:52;;;2388:1;2385;2378:12;2340:52;2411:29;2430:9;2411:29;:::i;:::-;2401:39;;2490:2;2479:9;2475:18;2462:32;2503:28;2525:5;2503:28;:::i;:::-;2550:5;2540:15;;;2246:315;;;;;:::o;2566:254::-;2634:6;2642;2695:2;2683:9;2674:7;2670:23;2666:32;2663:52;;;2711:1;2708;2701:12;2663:52;2734:29;2753:9;2734:29;:::i;:::-;2724:39;2810:2;2795:18;;;;2782:32;;-1:-1:-1;;;2566:254:1:o;2825:245::-;2892:6;2945:2;2933:9;2924:7;2920:23;2916:32;2913:52;;;2961:1;2958;2951:12;2913:52;2993:9;2987:16;3012:28;3034:5;3012:28;:::i;3075:180::-;3134:6;3187:2;3175:9;3166:7;3162:23;3158:32;3155:52;;;3203:1;3200;3193:12;3155:52;-1:-1:-1;3226:23:1;;3075:180;-1:-1:-1;3075:180:1:o;3260:184::-;3330:6;3383:2;3371:9;3362:7;3358:23;3354:32;3351:52;;;3399:1;3396;3389:12;3351:52;-1:-1:-1;3422:16:1;;3260:184;-1:-1:-1;3260:184:1:o;3449:254::-;3517:6;3525;3578:2;3566:9;3557:7;3553:23;3549:32;3546:52;;;3594:1;3591;3584:12;3546:52;3630:9;3617:23;3607:33;;3659:38;3693:2;3682:9;3678:18;3659:38;:::i;3708:245::-;3766:6;3819:2;3807:9;3798:7;3794:23;3790:32;3787:52;;;3835:1;3832;3825:12;3787:52;3874:9;3861:23;3893:30;3917:5;3893:30;:::i;3958:249::-;4027:6;4080:2;4068:9;4059:7;4055:23;4051:32;4048:52;;;4096:1;4093;4086:12;4048:52;4128:9;4122:16;4147:30;4171:5;4147:30;:::i;4212:321::-;4281:6;4334:2;4322:9;4313:7;4309:23;4305:32;4302:52;;;4350:1;4347;4340:12;4302:52;4390:9;4377:23;4423:18;4415:6;4412:30;4409:50;;;4455:1;4452;4445:12;4409:50;4478:49;4519:7;4510:6;4499:9;4495:22;4478:49;:::i;4538:540::-;4625:6;4633;4686:2;4674:9;4665:7;4661:23;4657:32;4654:52;;;4702:1;4699;4692:12;4654:52;4742:9;4729:23;4771:18;4812:2;4804:6;4801:14;4798:34;;;4828:1;4825;4818:12;4798:34;4851:49;4892:7;4883:6;4872:9;4868:22;4851:49;:::i;:::-;4841:59;;4953:2;4942:9;4938:18;4925:32;4909:48;;4982:2;4972:8;4969:16;4966:36;;;4998:1;4995;4988:12;4966:36;;5021:51;5064:7;5053:8;5042:9;5038:24;5021:51;:::i;:::-;5011:61;;;4538:540;;;;;:::o;5457:257::-;5498:3;5536:5;5530:12;5563:6;5558:3;5551:19;5579:63;5635:6;5628:4;5623:3;5619:14;5612:4;5605:5;5601:16;5579:63;:::i;:::-;5696:2;5675:15;-1:-1:-1;;5671:29:1;5662:39;;;;5703:4;5658:50;;5457:257;-1:-1:-1;;5457:257:1:o;5719:397::-;5933:26;5929:31;5920:6;5916:2;5912:15;5908:53;5903:3;5896:66;5878:3;5991:6;5985:13;6007:62;6062:6;6057:2;6052:3;6048:12;6041:4;6033:6;6029:17;6007:62;:::i;:::-;6089:16;;;;6107:2;6085:25;;5719:397;-1:-1:-1;;;5719:397:1:o;6121:274::-;6250:3;6288:6;6282:13;6304:53;6350:6;6345:3;6338:4;6330:6;6326:17;6304:53;:::i;:::-;6373:16;;;;;6121:274;-1:-1:-1;;6121:274:1:o;7066:786::-;7477:25;7472:3;7465:38;7447:3;7532:6;7526:13;7548:62;7603:6;7598:2;7593:3;7589:12;7582:4;7574:6;7570:17;7548:62;:::i;:::-;-1:-1:-1;;;7669:2:1;7629:16;;;7661:11;;;7654:40;7719:13;;7741:63;7719:13;7790:2;7782:11;;7775:4;7763:17;;7741:63;:::i;:::-;7824:17;7843:2;7820:26;;7066:786;-1:-1:-1;;;;7066:786:1:o;8065:488::-;-1:-1:-1;;;;;8334:15:1;;;8316:34;;8386:15;;8381:2;8366:18;;8359:43;8433:2;8418:18;;8411:34;;;8481:3;8476:2;8461:18;;8454:31;;;8259:4;;8502:45;;8527:19;;8519:6;8502:45;:::i;:::-;8494:53;8065:488;-1:-1:-1;;;;;;8065:488:1:o;8558:658::-;8729:2;8781:21;;;8851:13;;8754:18;;;8873:22;;;8700:4;;8729:2;8952:15;;;;8926:2;8911:18;;;8700:4;8995:195;9009:6;9006:1;9003:13;8995:195;;;9074:13;;-1:-1:-1;;;;;9070:39:1;9058:52;;9165:15;;;;9130:12;;;;9106:1;9024:9;8995:195;;;-1:-1:-1;9207:3:1;;8558:658;-1:-1:-1;;;;;;8558:658:1:o;9595:288::-;9770:6;9759:9;9752:25;9813:2;9808;9797:9;9793:18;9786:30;9733:4;9833:44;9873:2;9862:9;9858:18;9850:6;9833:44;:::i;10291:219::-;10440:2;10429:9;10422:21;10403:4;10460:44;10500:2;10489:9;10485:18;10477:6;10460:44;:::i;10876:409::-;11078:2;11060:21;;;11117:2;11097:18;;;11090:30;11156:34;11151:2;11136:18;;11129:62;-1:-1:-1;;;11222:2:1;11207:18;;11200:43;11275:3;11260:19;;10876:409::o;11290:414::-;11492:2;11474:21;;;11531:2;11511:18;;;11504:30;11570:34;11565:2;11550:18;;11543:62;-1:-1:-1;;;11636:2:1;11621:18;;11614:48;11694:3;11679:19;;11290:414::o;12123:401::-;12325:2;12307:21;;;12364:2;12344:18;;;12337:30;12403:34;12398:2;12383:18;;12376:62;-1:-1:-1;;;12469:2:1;12454:18;;12447:35;12514:3;12499:19;;12123:401::o;18121:128::-;18161:3;18192:1;18188:6;18185:1;18182:13;18179:39;;;18198:18;;:::i;:::-;-1:-1:-1;18234:9:1;;18121:128::o;18254:168::-;18294:7;18360:1;18356;18352:6;18348:14;18345:1;18342:21;18337:1;18330:9;18323:17;18319:45;18316:71;;;18367:18;;:::i;:::-;-1:-1:-1;18407:9:1;;18254:168::o;18427:125::-;18467:4;18495:1;18492;18489:8;18486:34;;;18500:18;;:::i;:::-;-1:-1:-1;18537:9:1;;18427:125::o;18557:258::-;18629:1;18639:113;18653:6;18650:1;18647:13;18639:113;;;18729:11;;;18723:18;18710:11;;;18703:39;18675:2;18668:10;18639:113;;;18770:6;18767:1;18764:13;18761:48;;;-1:-1:-1;;18805:1:1;18787:16;;18780:27;18557:258::o;18820:136::-;18859:3;18887:5;18877:39;;18896:18;;:::i;:::-;-1:-1:-1;;;18932:18:1;;18820:136::o;18961:380::-;19040:1;19036:12;;;;19083;;;19104:61;;19158:4;19150:6;19146:17;19136:27;;19104:61;19211:2;19203:6;19200:14;19180:18;19177:38;19174:161;;;19257:10;19252:3;19248:20;19245:1;19238:31;19292:4;19289:1;19282:15;19320:4;19317:1;19310:15;19346:127;19407:10;19402:3;19398:20;19395:1;19388:31;19438:4;19435:1;19428:15;19462:4;19459:1;19452:15;19478:127;19539:10;19534:3;19530:20;19527:1;19520:31;19570:4;19567:1;19560:15;19594:4;19591:1;19584:15;19610:127;19671:10;19666:3;19662:20;19659:1;19652:31;19702:4;19699:1;19692:15;19726:4;19723:1;19716:15;19742:127;19803:10;19798:3;19794:20;19791:1;19784:31;19834:4;19831:1;19824:15;19858:4;19855:1;19848:15;19874:118;19960:5;19953:13;19946:21;19939:5;19936:32;19926:60;;19982:1;19979;19972:12;19997:131;-1:-1:-1;;;;;;20071:32:1;;20061:43;;20051:71;;20118:1;20115;20108:12

Swarm Source

ipfs://0c961fe1c5a6eed832ca649f504716fcc362332384260cea33d9c392f1c14567
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.