ETH Price: $3,612.69 (+9.44%)

Token

Angry Thread (ANGRY)
 

Overview

Max Total Supply

5,082 ANGRY

Holders

689

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
1 ANGRY
0xcf428cee13cbc41e286acbe86fc0f046713de026
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
AngryThread

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion, MIT license
File 1 of 15 : AngryThread.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "./ERC721G_Full.sol";
import "./iWTF.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "operator-filter-registry/src/DefaultOperatorFilterer.sol";
import "hardhat/console.sol";

error IncorrectPrice();
error NotUser();
error InvalidSaleState();
error ZeroAddress();
error PublicSoldOut();
error SoldOut();
error InvalidSignature();
error LimitPerWalletExceeded();
error NotEnabledYet();
error NotOwner();
error AlreadySet();
error NotSet();
error TooMuch();

abstract contract RewardContract {
    function getEmissionRate(
        uint256 index_
    ) public view virtual returns (uint256);

    function claimRewards(
        uint256 index_,
        address to_,
        uint256 total_
    ) public virtual;
}

contract AngryThread is ERC721G, Ownable, DefaultOperatorFilterer {
    constructor(
        address signer_,
        address payable deployerAddress_,
        string memory unrevealURI_,
        string memory contractURI_
    ) ERC721G("Angry Thread", "ANGRY", 1, 100) {
        setSignerAddress(signer_);
        setWithdrawAddress(deployerAddress_);
        setBaseURI(unrevealURI_);
        setContractMetadataURI(contractURI_);
    }

    /* WTF */
    address public wtfAddress;
    uint256 public thisAddressIndexInRewardContract = 0;

    /* SIGNATURE */

    using ECDSA for bytes32;
    address public signerAddress;
    string public salePublicKey = "Public";
    string public saleWhitelistKey = "WHITELIST";

    /* DETAILS */
    uint256 public publicMintPrice = 0.001 ether;
    uint256 public wtfMintPriceInWei; //Mint with $WTF

    uint256 public maxSupply = 10000;
    uint256 public collectionSize = 20000;
    uint256 public publicLimitPerWallet = 10;
    uint256 public whitelistLimitPerWallet = 1;

    uint256 public firstBatch = 10000;
    string public firstProvenance; //<= 10K (0-10K)
    uint256 public firstStartingIndex;

    uint256 public secondBatch = 10000;
    string public secondProvenance; //>10K (10K-20K)
    uint256 public secondStartingIndex;

    string private contractMetadataURI;

    /* SALE STATE */
    enum SaleState {
        CLOSED,
        WHITELIST,
        PUBLIC
    }
    SaleState public saleState;

    /* EVENT */
    event Minted(address indexed receiver, uint256 quantity);
    event WTF(address indexed receiver, uint256 quantity);
    event SaleStateChanged(SaleState saleState);

    /* MINT */
    function whitelistMint(
        uint256 quantity_,
        bytes calldata signature_
    ) external isSaleState(SaleState.WHITELIST) {
        if (!verifySignature(signature_, saleWhitelistKey))
            revert InvalidSignature();
        if (
            _balanceData[msg.sender].mintedAmount + quantity_ >
            whitelistLimitPerWallet
        ) revert LimitPerWalletExceeded();

        _mint(msg.sender, quantity_);
        emit Minted(msg.sender, quantity_);
    }

    function publicMint(
        uint256 quantity_,
        bytes calldata signature_
    ) external payable isSaleState(SaleState.PUBLIC) {
        if (!verifySignature(signature_, salePublicKey))
            revert InvalidSignature();
        if (totalSupply() + quantity_ > maxSupply) revert PublicSoldOut();
        if (
            _balanceData[msg.sender].mintedAmount + quantity_ >
            publicLimitPerWallet
        ) revert LimitPerWalletExceeded();
        if (msg.value != quantity_ * publicMintPrice) revert IncorrectPrice();
        if (quantity_ > publicLimitPerWallet) revert LimitPerWalletExceeded();

        _mint(msg.sender, quantity_);
        emit Minted(msg.sender, quantity_);
    }

    function verifySignature(
        bytes memory signature_,
        string memory saleStateName_
    ) internal view returns (bool) {
        return
            signerAddress ==
            keccak256(
                abi.encodePacked(
                    "\x19Ethereum Signed Message:\n32",
                    bytes32(abi.encodePacked(msg.sender, saleStateName_))
                )
            ).recover(signature_);
    }

    function reserve(address to_, uint256 amount_) external onlyOwner {
        _mint(to_, amount_);
    }

    /* STAKING */

    mapping(uint256 => uint256) internal latestTokenIdClaimTimestamp;

    bool public stakingIsEnabled;
    bool public unstakingIsEnabled;
    bool public claimIsEnabled;
    uint256 public endStakingTime;

    function setStakingIsEnabled(bool bool_) external onlyOwner {
        stakingIsEnabled = bool_;
    }

    function setUnstakingIsEnabled(bool bool_) external onlyOwner {
        unstakingIsEnabled = bool_;
    }

    function setClaimIsEnabled(bool bool_) external onlyOwner {
        claimIsEnabled = bool_;
    }

    function stake(uint256[] calldata tokenIds_) public override {
        if (!stakingIsEnabled) revert NotEnabledYet();
        ERC721G.stake(tokenIds_);

        for (uint256 i = 0; i < tokenIds_.length; i++) {
            latestTokenIdClaimTimestamp[tokenIds_[i]] = block.timestamp;
        }
    }

    function unstake(uint256[] calldata tokenIds_) public override {
        if (!unstakingIsEnabled) revert NotEnabledYet();
        ERC721G.unstake(tokenIds_);

        // Automatically claim
        _claimInternal(tokenIds_);
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /* WTF */

    function WTFClaim(uint256[] calldata tokenIds_) external {
        if (!claimIsEnabled) revert NotEnabledYet();

        _claimInternal(tokenIds_);
    }

    function _claimInternal(uint256[] calldata tokenIds_) internal {
        if (endStakingTime == 0) revert NotSet();
        for (uint256 i = 0; i < tokenIds_.length; i++) {
            if (_trueOwnerOf(tokenIds_[i]) != msg.sender) revert NotOwner();
        }

        RewardContract wtfContract = RewardContract(wtfAddress);
        uint256 emissionRate = wtfContract.getEmissionRate(
            thisAddressIndexInRewardContract
        );

        uint256 time = min(block.timestamp, endStakingTime);
        for (uint256 i = 0; i < tokenIds_.length; i++) {
            uint256 totalRewards = (time -
                latestTokenIdClaimTimestamp[tokenIds_[i]]) * emissionRate;
            wtfContract.claimRewards(
                thisAddressIndexInRewardContract,
                msg.sender,
                totalRewards
            );

            latestTokenIdClaimTimestamp[tokenIds_[i]] = block.timestamp;
        }
    }

    function getTotalClaimable(uint256 tokenId_) public view returns (uint256) {
        RewardContract wtfContract = RewardContract(wtfAddress);
        uint256 emissionRate = wtfContract.getEmissionRate(
            thisAddressIndexInRewardContract
        );

        uint256 time = min(block.timestamp, endStakingTime);
        uint256 totalRewards = (time - latestTokenIdClaimTimestamp[tokenId_]) *
            emissionRate;
        return totalRewards; //$WTF
    }

    function WTFMint(uint256 quantity_) external {
        if (!stakingIsEnabled) revert NotEnabledYet();
        if (wtfAddress == address(0)) revert ZeroAddress();
        if (totalSupply() + quantity_ > collectionSize) revert SoldOut();
        if (quantity_ > publicLimitPerWallet) revert TooMuch();

        iWTF(wtfAddress).burnFrom(msg.sender, wtfMintPriceInWei * quantity_);

        _mint(msg.sender, quantity_);
        emit WTF(msg.sender, quantity_);
    }

    /* PROVENANCE */

    using SafeMath for uint256;

    function setFirstStartingIndex(
        uint256 random1_,
        uint256 random2_,
        uint256 random3_
    ) public {
        if (firstStartingIndex != 0) revert AlreadySet();

        firstStartingIndex =
            uint256(
                keccak256(
                    abi.encodePacked(
                        block.timestamp,
                        random1_,
                        block.difficulty,
                        block.coinbase,
                        block.gaslimit,
                        blockhash(block.number),
                        random2_,
                        random3_
                    )
                )
            ) %
            firstBatch;

        // Prevent default sequence
        if (firstStartingIndex == 0 || firstStartingIndex == 1) {
            firstStartingIndex = 2;
        }
    }

    function setSecondStartingIndex(
        uint256 random1_,
        uint256 random2_,
        uint256 random3_
    ) public {
        if (secondStartingIndex != 0) revert AlreadySet();

        secondStartingIndex =
            uint256(
                keccak256(
                    abi.encodePacked(
                        random1_,
                        block.timestamp,
                        block.difficulty,
                        block.coinbase,
                        block.gaslimit,
                        random2_,
                        blockhash(block.number),
                        random3_
                    )
                )
            ) %
            secondBatch;

        // Prevent default sequence
        if (secondStartingIndex == 0 || secondStartingIndex == 1) {
            secondStartingIndex = 2;
        }
    }

    function setFirstProvenance0To10K(
        string memory firstProvenance_
    ) external onlyOwner {
        firstProvenance = firstProvenance_;
    }

    function setSecondProvenance10KTo20K(
        string memory secondProvenance_
    ) external onlyOwner {
        secondProvenance = secondProvenance_;
    }

    function setFirstBatch(uint256 firstBatch_) external onlyOwner {
        firstBatch = firstBatch_;
    }

    function setSecondBatch(uint256 secondBatch_) external onlyOwner {
        secondBatch = secondBatch_;
    }

    /* OWNER */

    function setWTFAddress(address wtfAddress_) external onlyOwner {
        wtfAddress = wtfAddress_;
    }

    function setSaleState(uint256 saleState_) external onlyOwner {
        saleState = SaleState(saleState_);
        emit SaleStateChanged(saleState);
    }

    modifier isSaleState(SaleState saleState_) {
        if (msg.sender != tx.origin) revert NotUser();
        if (saleState != saleState_) revert InvalidSaleState();
        _;
    }

    function setSignerAddress(address signerAddress_) public onlyOwner {
        if (signerAddress_ == address(0)) revert ZeroAddress();
        signerAddress = signerAddress_;
    }

    function setWithdrawAddress(
        address payable withdrawAddress_
    ) public onlyOwner {
        if (withdrawAddress_ == address(0)) revert ZeroAddress();
        withdrawAddress = withdrawAddress_;
    }

    function setContractMetadataURI(
        string memory contractMetadataURI_
    ) public onlyOwner {
        contractMetadataURI = contractMetadataURI_;
    }

    function setMaxSupply(uint256 maxSupply_) public onlyOwner {
        maxSupply = maxSupply_;
    }

    function setCollectionSize(uint256 collectionSize_) public onlyOwner {
        collectionSize = collectionSize_;
    }

    function setPublicMintPrice(uint256 publicMintPrice_) public onlyOwner {
        publicMintPrice = publicMintPrice_;
    }

    function setWTFMintPriceInWei(uint256 wtfMintPriceInWei_) public onlyOwner {
        wtfMintPriceInWei = wtfMintPriceInWei_;
    }

    function setWhitelistLimitPerWallet(
        uint256 whitelistLimitPerWallet_
    ) public onlyOwner {
        whitelistLimitPerWallet = whitelistLimitPerWallet_;
    }

    function setPublicLimitPerWallet(
        uint256 publicLimitPerWallet_
    ) public onlyOwner {
        publicLimitPerWallet = publicLimitPerWallet_;
    }

    function setThisAddressIndexInRewardContract(
        uint256 thisAddressIndexInRewardContract_
    ) public onlyOwner {
        thisAddressIndexInRewardContract = thisAddressIndexInRewardContract_;
    }

    function setSalePublicKey(string memory salePublicKey_) public onlyOwner {
        salePublicKey = salePublicKey_;
    }

    function setSaleWhitelistKey(
        string memory saleWhitelistKey_
    ) public onlyOwner {
        saleWhitelistKey = saleWhitelistKey_;
    }

    function setEndStakingTime(uint256 endStakingTime_) public onlyOwner {
        endStakingTime = endStakingTime_;
    }

    // Token URI Configurations
    string internal baseURI;
    string internal baseURI_EXTENSION;

    function setBaseURI(string memory uri_) public onlyOwner {
        baseURI = uri_;
    }

    function setBaseURI_EXTENSION(string memory extension_) external onlyOwner {
        baseURI_EXTENSION = extension_;
    }

    function _toString(uint256 value_) internal pure returns (string memory) {
        if (value_ == 0) {
            return "0";
        }
        uint256 _iterate = value_;
        uint256 _digits;
        while (_iterate != 0) {
            _digits++;
            _iterate /= 10;
        }
        bytes memory _buffer = new bytes(_digits);
        while (value_ != 0) {
            _digits--;
            _buffer[_digits] = bytes1(uint8(48 + uint256(value_ % 10)));
            value_ /= 10;
        }
        return string(_buffer);
    }

    function tokenURI(
        uint256 tokenId_
    ) public view override returns (string memory) {
        return
            string(
                abi.encodePacked(
                    baseURI,
                    _toString(tokenId_),
                    baseURI_EXTENSION
                )
            );
    }

    /* WITHDRAW */

    address payable public withdrawAddress;

    function withdraw() external onlyOwner {
        (bool success, ) = withdrawAddress.call{value: address(this).balance}(
            ""
        );
        require(success, "Transfer failed.");
    }

    /* OPERATOR FILTERER */

    function setApprovalForAll(
        address operator,
        bool approved
    ) public override onlyAllowedOperatorApproval(operator) {
        super.setApprovalForAll(operator, approved);
    }

    function approve(
        address operator,
        uint256 tokenId
    ) public override onlyAllowedOperatorApproval(operator) {
        super.approve(operator, tokenId);
    }

    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable override onlyAllowedOperator(from) {
        super.transferFrom(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public payable override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public payable override onlyAllowedOperator(from) {
        super.safeTransferFrom(from, to, tokenId, data);
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 3 of 15 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

File 5 of 15 : Counters.sol
// SPDX-License-Identifier: MIT
// 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 6 of 15 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

/**
 * @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 7 of 15 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @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 8 of 15 : Math.sol
// SPDX-License-Identifier: MIT
// 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 9 of 15 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

File 10 of 15 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >= 0.4.22 <0.9.0;

library console {
	address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

	function _sendLogPayload(bytes memory payload) private view {
		uint256 payloadLength = payload.length;
		address consoleAddress = CONSOLE_ADDRESS;
		assembly {
			let payloadStart := add(payload, 32)
			let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
		}
	}

	function log() internal view {
		_sendLogPayload(abi.encodeWithSignature("log()"));
	}

	function logInt(int256 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
	}

	function logUint(uint256 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
	}

	function logString(string memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
	}

	function logBool(bool p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
	}

	function logAddress(address p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
	}

	function logBytes(bytes memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
	}

	function logBytes1(bytes1 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
	}

	function logBytes2(bytes2 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
	}

	function logBytes3(bytes3 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
	}

	function logBytes4(bytes4 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
	}

	function logBytes5(bytes5 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
	}

	function logBytes6(bytes6 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
	}

	function logBytes7(bytes7 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
	}

	function logBytes8(bytes8 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
	}

	function logBytes9(bytes9 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
	}

	function logBytes10(bytes10 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
	}

	function logBytes11(bytes11 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
	}

	function logBytes12(bytes12 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
	}

	function logBytes13(bytes13 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
	}

	function logBytes14(bytes14 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
	}

	function logBytes15(bytes15 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
	}

	function logBytes16(bytes16 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
	}

	function logBytes17(bytes17 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
	}

	function logBytes18(bytes18 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
	}

	function logBytes19(bytes19 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
	}

	function logBytes20(bytes20 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
	}

	function logBytes21(bytes21 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
	}

	function logBytes22(bytes22 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
	}

	function logBytes23(bytes23 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
	}

	function logBytes24(bytes24 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
	}

	function logBytes25(bytes25 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
	}

	function logBytes26(bytes26 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
	}

	function logBytes27(bytes27 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
	}

	function logBytes28(bytes28 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
	}

	function logBytes29(bytes29 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
	}

	function logBytes30(bytes30 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
	}

	function logBytes31(bytes31 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
	}

	function logBytes32(bytes32 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
	}

	function log(uint256 p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
	}

	function log(string memory p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string)", p0));
	}

	function log(bool p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
	}

	function log(address p0) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address)", p0));
	}

	function log(uint256 p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
	}

	function log(uint256 p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
	}

	function log(uint256 p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
	}

	function log(uint256 p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
	}

	function log(string memory p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
	}

	function log(string memory p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
	}

	function log(string memory p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
	}

	function log(string memory p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
	}

	function log(bool p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
	}

	function log(bool p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
	}

	function log(bool p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
	}

	function log(bool p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
	}

	function log(address p0, uint256 p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
	}

	function log(address p0, string memory p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
	}

	function log(address p0, bool p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
	}

	function log(address p0, address p1) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
	}

	function log(uint256 p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
	}

	function log(uint256 p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
	}

	function log(uint256 p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
	}

	function log(uint256 p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
	}

	function log(string memory p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
	}

	function log(string memory p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
	}

	function log(string memory p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
	}

	function log(string memory p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
	}

	function log(string memory p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
	}

	function log(string memory p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
	}

	function log(string memory p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
	}

	function log(bool p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
	}

	function log(bool p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
	}

	function log(bool p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
	}

	function log(bool p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
	}

	function log(bool p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
	}

	function log(bool p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
	}

	function log(bool p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
	}

	function log(bool p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
	}

	function log(bool p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
	}

	function log(bool p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
	}

	function log(address p0, uint256 p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
	}

	function log(address p0, string memory p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
	}

	function log(address p0, string memory p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
	}

	function log(address p0, string memory p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
	}

	function log(address p0, string memory p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
	}

	function log(address p0, bool p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
	}

	function log(address p0, bool p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
	}

	function log(address p0, bool p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
	}

	function log(address p0, bool p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
	}

	function log(address p0, address p1, uint256 p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
	}

	function log(address p0, address p1, string memory p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
	}

	function log(address p0, address p1, bool p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
	}

	function log(address p0, address p1, address p2) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
	}

	function log(uint256 p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
	}

	function log(string memory p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
	}

	function log(bool p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, uint256 p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, string memory p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, bool p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, uint256 p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, string memory p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, bool p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, uint256 p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, string memory p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, bool p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
	}

	function log(address p0, address p1, address p2, address p3) internal view {
		_sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
	}

}

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

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

/**
 * @title  DefaultOperatorFilterer
 * @notice Inherits from OperatorFilterer and automatically subscribes to the default OpenSea subscription.
 */
abstract contract DefaultOperatorFilterer is OperatorFilterer {
    address constant DEFAULT_SUBSCRIPTION = address(0x3cc6CddA760b79bAfa08dF41ECFA224f810dCeB6);

    constructor() OperatorFilterer(DEFAULT_SUBSCRIPTION, true) {}
}

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

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

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

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

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

    IOperatorFilterRegistry public constant OPERATOR_FILTER_REGISTRY =
        IOperatorFilterRegistry(0x000000000000AAeB6D7670E522A718067333cd4E);

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

    modifier onlyAllowedOperator(address from) virtual {
        // Allow spending tokens from addresses with balance
        // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred
        // from an EOA.
        if (from != msg.sender) {
            _checkFilterOperator(msg.sender);
        }
        _;
    }

    modifier onlyAllowedOperatorApproval(address operator) virtual {
        _checkFilterOperator(operator);
        _;
    }

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

File 14 of 15 : ERC721G_Full.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

//////////////////////////////////////////////
//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★//
//★    _______  _____  _______ ___  _____  ★//
//★   / __/ _ \/ ___/ /_  /_  <  / / ___/  ★//
//★  / _// , _/ /__    / / __// / / (_ /   ★//
//★ /___/_/|_|\___/   /_/____/_/  \___/    ★//
//★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★//
//  by: 0xInuarashi                         //
//////////////////////////////////////////////
//  Audits: 0xAkihiko, 0xFoobar             //
//////////////////////////////////////////////        
//  Default: Staking Enabled                //
//  MAKE SURE YOU KNOW WHAT YOU'RE DOING!   //
//////////////////////////////////////////////

contract ERC721G {

    // Standard ERC721 Events
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved,
        uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator,
        bool approved);
 
    // Standard ERC721 Global Variables
    string public name; // Token Name
    string public symbol; // Token Symbol

    // ERC721G Global Variables
    uint256 public tokenIndex; // The running index for the next TokenId
    uint256 public immutable startTokenId; // Bytes Storage for the starting TokenId
    uint256 public immutable maxBatchSize;

    // ERC721G Staking Address Target
    function stakingAddress() public view returns (address) {
        return address(this);
    }

    /** @dev instructions:
     *  name_ sets the token name
     *  symbol_ sets the token symbol
     *  startId_ sets the starting tokenId (recommended 0-1)
     *  maxBatchSize_ sets the maximum batch size for each mint (recommended 5-20)
     */
    constructor(
    string memory name_, string memory symbol_, 
    uint256 startId_, uint256 maxBatchSize_) {
        name = name_;
        symbol = symbol_;
        tokenIndex = startId_;
        startTokenId = startId_;
        maxBatchSize = maxBatchSize_;
    }

    // ERC721G Structs
    struct OwnerStruct {
        address owner; // stores owner address for OwnerOf
        uint32 lastTransfer; // stores the last transfer of the token
        uint32 stakeTimestamp; // stores the stake timestamp in _setStakeTimestamp()
        uint32 totalTimeStaked; // stores the total time staked accumulated
    }

    struct BalanceStruct {
        uint32 balance; // stores the token balance of the address
        uint32 mintedAmount; // stores the minted amount of the address on mint
        // 24 Free Bytes
    }

    // ERC721G Mappings
    mapping(uint256 => OwnerStruct) public _tokenData; // ownerOf replacement
    mapping(address => BalanceStruct) public _balanceData; // balanceOf replacement
    mapping(uint256 => OwnerStruct) public mintIndex; // uninitialized ownerOf pointer

    // ERC721 Mappings
    mapping(uint256 => address) public getApproved; // for single token approvals
    mapping(address => mapping(address => bool)) public isApprovedForAll; // approveall

    // Time Expansion and Compression by 0xInuarashi 
    /** @dev Time Expansion and Compression extends the usage of ERC721G from
     *  Year 2106 (end of uint32) to Year 3331 (end of uint32 with time expansion)
     *  the trade-off is that staking accuracy is scoped within 10-second chunks
     */
    function _getBlockTimestampCompressed() public virtual view returns (uint32) {
        return uint32(block.timestamp / 10);
    }
    function _compressTimestamp(uint256 timestamp_) public virtual view
    returns (uint32) {
        return uint32(timestamp_ / 10);
    }
    function _expandTimestamp(uint32 timestamp_) public virtual view
    returns (uint256) {
        return uint256(timestamp_) * 10;
    }
    
    function getLastTransfer(uint256 tokenId_) public virtual view
    returns (uint256) {
        return _expandTimestamp(_getTokenDataOf(tokenId_).lastTransfer);
    }
    function getStakeTimestamp(uint256 tokenId_) public virtual view
    returns (uint256) {
        return _expandTimestamp(_getTokenDataOf(tokenId_).stakeTimestamp);
    }
    function getTotalTimeStaked(uint256 tokenId_) public virtual view
    returns (uint256) {
        return _expandTimestamp(_getTokenDataOf(tokenId_).totalTimeStaked);
    }

    ///// ERC721G: ERC721-Like Simple Read Outputs /////
    function totalSupply() public virtual view returns (uint256) {
        return tokenIndex - startTokenId;
    }
    function balanceOf(address address_) public virtual view returns (uint256) {
        return _balanceData[address_].balance;
    }

    ///// ERC721G: Range-Based Logic /////
    
    /** @dev explanation:
     *  _getTokenDataOf() finds and returns either the (and in priority)
     *      - the initialized storage pointer from _tokenData
     *      - the uninitialized storage pointer from mintIndex
     * 
     *  if the _tokenData storage slot is populated, return it
     *  otherwise, do a reverse-lookup to find the uninitialized pointer from mintIndex
     */
    function _getTokenDataOf(uint256 tokenId_) public virtual view
    returns (OwnerStruct memory) {
        // The tokenId must be above startTokenId only
        require(tokenId_ >= startTokenId, "TokenId below starting Id!");
        
        // If the _tokenData is initialized (not 0x0), return the _tokenData
        if (_tokenData[tokenId_].owner != address(0)
            || tokenId_ >= tokenIndex) {
            return _tokenData[tokenId_];
        }

        // Else, do a reverse-lookup to find  the corresponding uninitialized pointer
        else { unchecked {
            uint256 _lowerRange = tokenId_;
            while (mintIndex[_lowerRange].owner == address(0)) { _lowerRange--; }
            return mintIndex[_lowerRange];
        }}
    }

    /** @dev explanation: 
     *  ownerOf calls _getTokenDataOf() which returns either the initialized or 
     *  uninitialized pointer. 
     *  Then, it checks if the token is staked or not through stakeTimestamp.
     *  If the token is staked, return the stakingAddress, otherwise, return the owner.
     */
    function ownerOf(uint256 tokenId_) public virtual view returns (address) {
        OwnerStruct memory _OwnerStruct = _getTokenDataOf(tokenId_);
        return _OwnerStruct.stakeTimestamp == 0 ? _OwnerStruct.owner : stakingAddress();
    }

    /** @dev explanation:
     *  _trueOwnerOf() calls _getTokenDataOf() which returns either the initialized or
     *  uninitialized pointer.
     *  It returns the owner directly without any checks. 
     *  Used internally for proving the staker address on unstake.
     */
    function _trueOwnerOf(uint256 tokenId_) public virtual view returns (address) {
        return _getTokenDataOf(tokenId_).owner;
    }

    ///// ERC721G: Internal Single-Contract Staking Logic /////
    
    /** @dev explanation:
     *  _initializeTokenIf() is used as a beginning-hook to functions that require
     *  that the token is explicitly INITIALIZED before the function is able to be used.
     *  It will check if the _tokenData slot is initialized or not. 
     *  If it is not, it will initialize it.
     *  Used internally for staking logic.
     */
    function _initializeTokenIf(uint256 tokenId_, OwnerStruct memory _OwnerStruct) 
    internal virtual {
        // If the target _tokenData is not initialized, initialize it.
        if (_tokenData[tokenId_].owner == address(0)) {
            _tokenData[tokenId_] = _OwnerStruct;
        }
    }

    /** @dev explanation:
     *  _setStakeTimestamp() is our staking / unstaking logic.
     *  If timestamp_ is > 0, the action is "stake"
     *  If timestamp_ is == 0, the action is "unstake"
     * 
     *  We grab the tokenData using _getTokenDataOf and then read its values.
     *  As this function requires INITIALIZED tokens only, we call _initializeTokenIf()
     *  to initialize any token using this function first.
     * 
     *  Processing of the function is explained in in-line comments.
     */
    function _setStakeTimestamp(uint256 tokenId_, uint256 timestamp_)
    internal virtual returns (address) {
        // First, call _getTokenDataOf and grab the relevant tokenData
        OwnerStruct memory _OwnerStruct = _getTokenDataOf(tokenId_);
        address _owner = _OwnerStruct.owner;
        uint32 _stakeTimestamp = _OwnerStruct.stakeTimestamp;

        // _setStakeTimestamp requires initialization
        _initializeTokenIf(tokenId_, _OwnerStruct);

        // Clear any token approvals
        delete getApproved[tokenId_];

        // if timestamp_ > 0, the action is "stake"
        if (timestamp_ > 0) {
            // Make sure that the token is not staked already
            require(_stakeTimestamp == 0,
                "ERC721G: _setStakeTimestamp() already staked");
            
            // Callbrate balances between staker and stakingAddress
            unchecked { 
                _balanceData[_owner].balance--;
                _balanceData[stakingAddress()].balance++;
            }

            // Emit Transfer event from trueOwner
            emit Transfer(_owner, stakingAddress(), tokenId_);
        }

        // if timestamp_ == 0, the action is "unstake"
        else {
            // Make sure the token is not staked
            require(_stakeTimestamp != 0,
                "ERC721G: _setStakeTimestamp() already unstaked");
            
            // Callibrate balances between stakingAddress and staker
            unchecked {
                _balanceData[_owner].balance++;
                _balanceData[stakingAddress()].balance--;
            }
            
            // we add total time staked to the token on unstake
            uint32 _timeStaked = _getBlockTimestampCompressed() - _stakeTimestamp;
            _tokenData[tokenId_].totalTimeStaked += _timeStaked;

            // Emit Transfer event to trueOwner
            emit Transfer(stakingAddress(), _owner, tokenId_);
        }

        // Set the stakeTimestamp to timestamp_
        _tokenData[tokenId_].stakeTimestamp = _compressTimestamp(timestamp_);

        // We save internal gas by returning the owner for a follow-up function
        return _owner;
    }

    /** @dev explanation:
     *  _stake() works like an extended function of _setStakeTimestamp()
     *  where the logic of _setStakeTimestamp() runs and returns the _owner address
     *  afterwards, we do the post-hook required processing to finish the staking logic 
     *  in this function.
     * 
     *  Processing logic explained in in-line comments.
     */
    function _stake(uint256 tokenId_) internal virtual returns (address) {
        // set the stakeTimestamp to block.timestamp and return the owner
        return _setStakeTimestamp(tokenId_, block.timestamp);
    }

    /** @dev explanation:
     *  _unstake() works like an extended unction of _setStakeTimestamp()
     *  where the logic of _setStakeTimestamp() runs and returns the _owner address
     *  afterwards, we do the post-hook required processing to finish the unstaking logic
     *  in this function.
     * 
     *  Processing logic explained in in-line comments.
     */
    function _unstake(uint256 tokenId_) internal virtual returns(address) {
        // set the stakeTimestamp to 0 and return the owner
        return _setStakeTimestamp(tokenId_, 0);
    }

    /** @dev explanation:
     *  _mintAndStakeInternal() is the internal mintAndStake function that is called
     *  to mintAndStake tokens to users. 
     * 
     *  It populates mintIndex with the phantom-mint data (owner, lastTransferTime)
     *  as well as the phantom-stake data (stakeTimestamp)
     * 
     *  Then, it emits the necessary phantom events to replicate the behavior as canon.
     * 
     *  Further logic explained in in-line comments.
     */
    function _mintAndStakeInternal(address to_, uint256 amount_) internal virtual {
        // we cannot mint to 0x0
        require(to_ != address(0), "ERC721G: _mintAndStakeInternal to 0x0");

        // we limit max mints per SSTORE to prevent expensive gas lookup
        require(amount_ <= maxBatchSize, 
            "ERC721G: _mintAndStakeInternal over maxBatchSize");

        // process the required variables to write to mintIndex 
        uint256 _startId = tokenIndex;
        uint256 _endId = _startId + amount_;
        uint32 _currentTime = _getBlockTimestampCompressed();

        // write to the mintIndex to store the OwnerStruct for uninitialized tokenData
        mintIndex[_startId] = OwnerStruct(
            to_, // the address the token is minted to
            _currentTime, // the last transfer time
            _currentTime, // the curent time of staking
            0 // the accumulated time staked
        );

        unchecked { 
            // we add the balance to the stakingAddress through our staking logic
            _balanceData[stakingAddress()].balance += uint32(amount_);

            // we add the mintedAmount to the to_ through our minting logic
            _balanceData[to_].mintedAmount += uint32(amount_);

            // emit phantom mint to to_, then emit a staking transfer
            do { 
                emit Transfer(address(0), to_, _startId);
                emit Transfer(to_, stakingAddress(), _startId);
            } while (++_startId < _endId);
        }

        // set the new tokenIndex to the _endId
        tokenIndex = _endId;
    }

    /** @dev explanation: 
     *  _mintAndStake() calls _mintAndStakeInternal() but calls it using a while-loop
     *  based on the required minting amount to stay within the bounds of 
     *  max mints per batch (maxBatchSize)
     */
    function _mintAndStake(address to_, uint256 amount_) internal virtual {
        uint256 _amountToMint = amount_;
        while (_amountToMint > maxBatchSize) {
            _amountToMint -= maxBatchSize;
            _mintAndStakeInternal(to_, maxBatchSize);
        }
        _mintAndStakeInternal(to_, _amountToMint);
    }

    ///// ERC721G Range-Based Internal Minting Logic /////
    
    /** @dev explanation:
     *  _mintInternal() is our internal batch minting logic. 
     *  First, we store the uninitialized pointer at mintIndex of _startId
     *  Then, we process the balances changes
     *  Finally, we phantom-mint the tokens using Transfer events loop.
     */
    function _mintInternal(address to_, uint256 amount_) internal virtual {
        // cannot mint to 0x0
        require(to_ != address(0), "ERC721G: _mintInternal to 0x0");

        // we limit max mints to prevent expensive gas lookup
        require(amount_ <= maxBatchSize, 
            "ERC721G: _mintInternal over maxBatchSize");

        // process the token id data
        uint256 _startId = tokenIndex;
        uint256 _endId = _startId + amount_;

        // push the required phantom mint data to mintIndex
        mintIndex[_startId].owner = to_;
        mintIndex[_startId].lastTransfer = _getBlockTimestampCompressed();

        // process the balance changes and do a loop to phantom-mint the tokens to to_
        unchecked { 
            _balanceData[to_].balance += uint32(amount_);
            _balanceData[to_].mintedAmount += uint32(amount_);

            do { emit Transfer(address(0), to_, _startId); } while (++_startId < _endId);
        }

        // set the new token index
        tokenIndex = _endId;
    }

    /** @dev explanation:
     *  _mint() is the function that calls _mintInternal() using a while-loop
     *  based on the maximum batch size (maxBatchSize)
     */
    function _mint(address to_, uint256 amount_) internal virtual {
        uint256 _amountToMint = amount_;
        while (_amountToMint > maxBatchSize) {
            _amountToMint -= maxBatchSize;
            _mintInternal(to_, maxBatchSize);
        }
        _mintInternal(to_, _amountToMint);
    }

    /** @dev explanation:
     *  _transfer() is the internal function that transfers the token from_ to to_
     *  it has ERC721-standard require checks
     *  and then uses solmate-style approval clearing
     * 
     *  afterwards, it sets the _tokenData to the data of the to_ (transferee) as well as
     *  set the balanceData.
     *  
     *  this results in INITIALIZATION of the token, if it has not been initialized yet. 
     */
    function _transfer(address from_, address to_, uint256 tokenId_) internal virtual {
        // the from_ address must be the ownerOf
        require(from_ == ownerOf(tokenId_), "ERC721G: _transfer != ownerOf");
        // cannot transfer to 0x0
        require(to_ != address(0), "ERC721G: _transfer to 0x0");

        // delete any approvals
        delete getApproved[tokenId_];

        // set _tokenData to to_
        _tokenData[tokenId_].owner = to_;
        _tokenData[tokenId_].lastTransfer = _getBlockTimestampCompressed();

        // update the balance data
        unchecked { 
            _balanceData[from_].balance--;
            _balanceData[to_].balance++;
        }

        // emit a standard Transfer
        emit Transfer(from_, to_, tokenId_);
    }

    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: User-Enabled Out-of-the-box Staking Functionality /////
    ///// Note: You may implement your own staking functionality     /////
    /////       by using _stake() and _unstake() functions instead   /////
    /////       These are merely out-of-the-box standard functions   /////
    //////////////////////////////////////////////////////////////////////
    /** @dev clarification:
     *  As a developer, you DO NOT have to enable these functions, or use them
     *  in the way defined in this section. 
     * 
     *  The functions in this section are just out-of-the-box plug-and-play staking
     *  which is enabled IMMEDIATELY.
     *  (As well as some useful view-functions)
     * 
     *  You can choose to call the internal staking functions yourself, to create 
     *  custom staking logic based on the section (n-2) above.
     */
    /** @dev explanation:
    *  this is a staking function that receives calldata tokenIds_ array
    *  and loops to call internal _stake in a gas-efficient way 
    *  written in a shorthand-style syntax
    */
    function stake(uint256[] calldata tokenIds_) public virtual {
        uint256 i;
        uint256 l = tokenIds_.length;
        while (i < l) { 
            // stake and return the owner's address
            address _owner = _stake(tokenIds_[i]); 
            // make sure the msg.sender is the owner
            require(msg.sender == _owner, "You are not the owner!");
            unchecked {++i;}
        }
    }
    /** @dev explanation:
    *  this is an unstaking function that receives calldata tokenIds_ array
    *  and loops to call internal _unstake in a gas-efficient way 
    *  written in a shorthand-style syntax
    */
    function unstake(uint256[] calldata tokenIds_) public virtual {
        uint256 i;
        uint256 l = tokenIds_.length;
        while (i < l) { 
            // unstake and return the owner's address
            address _owner = _unstake(tokenIds_[i]); 
            // make sure the msg.sender is the owner
            require(msg.sender == _owner, "You are not the owner!");
            unchecked {++i;}
        }
    }
    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: User-Enabled Out-of-the-box Staking Functionality /////
    //////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////
    /////      ERC721G: User-Enabled Staking Helper Functions        /////
    /////      Note: You MUST enable staking functionality           ///// 
    /////            To make use of these functions below            /////
    //////////////////////////////////////////////////////////////////////
    /** @dev explanation:
     *  balanceOfStaked loops through the entire tokens using 
     *  startTokenId as the start pointer, and 
     *  tokenIndex (current-next tokenId) as the end pointer
     * 
     *  it checks if the _trueOwnerOf() is the address_ or not
     *  and if the owner() is not the address, indicating the 
     *  state that the token is staked.
     * 
     *  if so, it increases the balance. after the loop, it returns the balance.
     * 
     *  this is mainly for external view only. 
     *  !! NOT TO BE INTERFACED WITH CONTRACT WRITE FUNCTIONS EVER.
     */
    function balanceOfStaked(address address_) public virtual view 
    returns (uint256) {
        uint256 _balance;
        uint256 i = startTokenId;
        uint256 max = tokenIndex;
        while (i < max) {
            if (ownerOf(i) != address_ && _trueOwnerOf(i) == address_) {
                _balance++;
            }
            unchecked { ++i; }
        }
        return _balance;
    }
    /** @dev explanation:
     *  walletOfOwnerStaked calls balanceOfStaked to get the staked 
     *  balance of a user. Afterwards, it runs staked-checking logic
     *  to figure out the tokenIds that the user has staked
     *  and then returns it in walletOfOwner fashion.
     * 
     *  this is mainly for external view only.
     *  !! NOT TO BE INTERFACED WITH CONTRACT WRITE FUNCTIONS EVER.
     */
    function walletOfOwnerStaked(address address_) public virtual view
    returns (uint256[] memory) {
        uint256 _balance = balanceOfStaked(address_);
        uint256[] memory _tokens = new uint256[] (_balance);
        uint256 _currentIndex;
        uint256 i = startTokenId;
        while (_currentIndex < _balance) {
            if (ownerOf(i) != address_ && _trueOwnerOf(i) == address_) {
                _tokens[_currentIndex++] = i;
            }
            unchecked { ++i; }
        }
        return _tokens;
    }
    /** @dev explanation:
     *  balanceOf of the address returns UNSTAKED tokens only.
     *  to get the total balance of the user containing both STAKED and UNSTAKED tokens,
     *  we use this function. 
     * 
     *  this is mainly for external view only.
     *  !! NOT TO BE INTERFACED WITH CONTRACT WRITE FUNCTIONS EVER.
     */
    function totalBalanceOf(address address_) public virtual view returns (uint256) {
        return balanceOf(address_) + balanceOfStaked(address_);
    }
    /** @dev explanation:
     *  totalTimeStakedOfToken returns the accumulative total time staked of a tokenId
     *  it reads from the totalTimeStaked of the tokenId_ and adds it with 
     *  a calculation of pending time staked and returns the sum of both values.
     * 
     *  this is mainly for external view / use only.
     *  this function can be interfaced with contract writes.
     */
    function totalTimeStakedOfToken(uint256 tokenId_) public virtual view 
    returns (uint256) {
        OwnerStruct memory _OwnerStruct = _getTokenDataOf(tokenId_);
        uint256 _totalTimeStakedOnToken = _expandTimestamp(_OwnerStruct.totalTimeStaked);
        uint256 _totalTimeStakedPending = 
            _OwnerStruct.stakeTimestamp > 0 ?
            _expandTimestamp(
                _getBlockTimestampCompressed() - _OwnerStruct.stakeTimestamp) : 
                0;
        return _totalTimeStakedOnToken + _totalTimeStakedPending;
    }
    /** @dev explanation:
     *  totalTimeStakedOfTokens just returns an array of totalTimeStakedOfToken
     *  based on tokenIds_ calldata.
     *  
     *  this is mainly for external view / use only.
     *  this function can be interfaced with contract writes... however
     *  BE CAREFUL and USE IT CORRECTLY. 
     *  (dont pass in 5000 tokenIds_ in a write function)
     */
    function totalTimeStakedOfTokens(uint256[] calldata tokenIds_) public
    virtual view returns (uint256[] memory) {
        uint256 i;
        uint256 l = tokenIds_.length;
        uint256[] memory _totalTimeStakeds = new uint256[] (l);
        while (i < l) {
            _totalTimeStakeds[i] = totalTimeStakedOfToken(tokenIds_[i]);
            unchecked { ++i; }
        }
        return _totalTimeStakeds;
    }
    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: User-Enabled Staking Helper Functions             /////
    //////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: Optional Additional Helper Functions              /////
    ///// Note: You do not need to enable these. It makes querying   /////
    /////       things cheaper in GAS at around 1.5k per token       /////
    ////        if you choose to query things as such                /////
    //////////////////////////////////////////////////////////////////////
    /** @dev description: You can pass an array of <tokenIds_> here
     *  in order to query if all the <tokenIds_> passed is owned by
     *  the address <owner> (using ownerOf())
     *  doing so saves around 1.5k gas of external contract call gas
     *  per token which scales linearly in batch queries
     */
    function isOwnerOfAll(address owner, uint256[] calldata tokenIds_) 
    external view returns (bool) {
        uint256 i;
        uint256 l = tokenIds_.length;
        unchecked { do {
            if (ownerOf(tokenIds_[i]) != owner) return false;
        } while (++i < l); }
        return true;
    }
    /** @dev description: You can pass an array of <tokenIds_> here
     *  in order to query if all the <tokenIds_> passed is owned by
     *  the address <owner> (using _trueOwnerOf())
     *  doing so saves around 1.5k gas of external contract call gas
     *  per token which scales linearly in batch queries
     */
    function isTrueOwnerOfAll(address owner, uint256[] calldata tokenIds_) 
    external view returns (bool) {
        uint256 i;
        uint256 l = tokenIds_.length;
        unchecked { do {
            if (_trueOwnerOf(tokenIds_[i]) != owner) return false;
        } while (++i < l); }
        return true;
    }
    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: Optional Additional Helper Functions              /////
    //////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: ERC721 Standard Logic                             /////
    //////////////////////////////////////////////////////////////////////
    /** @dev clarification:
     *  no explanations here as these are standard ERC721 logics.
     *  the reason that we can use standard ERC721 logics is because
     *  the ERC721G logic is compartmentalized and supports internally 
     *  these ERC721 logics without any need of modification.
     */
    function _isApprovedOrOwner(address spender_, uint256 tokenId_) internal 
    view virtual returns (bool) {
        address _owner = ownerOf(tokenId_);
        return (
            // "i am the owner of the token, and i am transferring it"
            _owner == spender_
            // "the token's approved spender is me"
            || getApproved[tokenId_] == spender_
            // "the owner has approved me to spend all his tokens"
            || isApprovedForAll[_owner][spender_]);
    }
    
    /** @dev clarification:
     *  sets a specific address to be able to spend a specific token.
     */
    function _approve(address to_, uint256 tokenId_) internal virtual {
        getApproved[tokenId_] = to_;
        emit Approval(ownerOf(tokenId_), to_, tokenId_);
    }

    function approve(address to_, uint256 tokenId_) public virtual {
        address _owner = ownerOf(tokenId_);
        require(
            // "i am the owner, and i am approving this token."
            _owner == msg.sender 
            // "i am isApprovedForAll, so i can approve this token too."
            || isApprovedForAll[_owner][msg.sender],
            "ERC721G: approve not authorized");

        _approve(to_, tokenId_);
    }

    function _setApprovalForAll(address owner_, address operator_, bool approved_) 
    internal virtual {
        isApprovedForAll[owner_][operator_] = approved_;
        emit ApprovalForAll(owner_, operator_, approved_);
    }
    function setApprovalForAll(address operator_, bool approved_) public virtual {
        // this function can only be used as self-approvalforall for others. 
        _setApprovalForAll(msg.sender, operator_, approved_);
    }

    function _exists(uint256 tokenId_) internal virtual view returns (bool) {
        return ownerOf(tokenId_) != address(0);
    }

    function transferFrom(address from_, address to_, uint256 tokenId_) public payable virtual {
        require(_isApprovedOrOwner(msg.sender, tokenId_),
            "ERC721G: transferFrom unauthorized");
        _transfer(from_, to_, tokenId_);
    }
    function safeTransferFrom(address from_, address to_, uint256 tokenId_,
    bytes memory data_) public payable virtual {
        transferFrom(from_, to_, tokenId_);
        if (to_.code.length != 0) {
            (, bytes memory _returned) = to_.call(abi.encodeWithSelector(
                0x150b7a02, msg.sender, from_, tokenId_, data_));
            bytes4 _selector = abi.decode(_returned, (bytes4));
            require(_selector == 0x150b7a02, 
                "ERC721G: safeTransferFrom to_ non-ERC721Receivable!");
        }
    }
    function safeTransferFrom(address from_, address to_, uint256 tokenId_) 
    public payable virtual {
        safeTransferFrom(from_, to_, tokenId_, "");
    }

    function supportsInterface(bytes4 iid_) public virtual view returns (bool) {
        return  iid_ == 0x01ffc9a7 || 
                iid_ == 0x80ac58cd || 
                iid_ == 0x5b5e139f || 
                iid_ == 0x7f5828d0; 
    }

    /** @dev description: walletOfOwner to query an array of wallet's
     *  owned tokens. A view-intensive alternative ERC721Enumerable function.
     */
    function walletOfOwner(address address_) public virtual view 
    returns (uint256[] memory) {
        uint256 _balance = balanceOf(address_);
        uint256[] memory _tokens = new uint256[] (_balance);
        uint256 _currentIndex;
        uint256 i = startTokenId;
        while (_currentIndex < _balance) {
            if (ownerOf(i) == address_) { _tokens[_currentIndex++] = i; }
            unchecked { ++i; }
        }
        return _tokens;
    }
    //////////////////////////////////////////////////////////////////////
    ///// ERC721G: ERC721 Standard Logic                             /////
    //////////////////////////////////////////////////////////////////////

    /** @dev requirement: You MUST implement your own tokenURI logic here 
     *  recommended to use through an override function in your main contract.
     */
    function tokenURI(uint256 tokenId_) public virtual view returns (string memory) {}
}

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

pragma solidity ^0.8.13;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface iWTF is IERC20 {
    function burnFrom(address account, uint256 amount) external;
}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"signer_","type":"address"},{"internalType":"address payable","name":"deployerAddress_","type":"address"},{"internalType":"string","name":"unrevealURI_","type":"string"},{"internalType":"string","name":"contractURI_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadySet","type":"error"},{"inputs":[],"name":"IncorrectPrice","type":"error"},{"inputs":[],"name":"InvalidSaleState","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"LimitPerWalletExceeded","type":"error"},{"inputs":[],"name":"NotEnabledYet","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotSet","type":"error"},{"inputs":[],"name":"NotUser","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"inputs":[],"name":"PublicSoldOut","type":"error"},{"inputs":[],"name":"SoldOut","type":"error"},{"inputs":[],"name":"TooMuch","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"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":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum AngryThread.SaleState","name":"saleState","type":"uint8"}],"name":"SaleStateChanged","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"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"WTF","type":"event"},{"inputs":[],"name":"OPERATOR_FILTER_REGISTRY","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"WTFClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity_","type":"uint256"}],"name":"WTFMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_balanceData","outputs":[{"internalType":"uint32","name":"balance","type":"uint32"},{"internalType":"uint32","name":"mintedAmount","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"_compressTimestamp","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"timestamp_","type":"uint32"}],"name":"_expandTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_getBlockTimestampCompressed","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"_getTokenDataOf","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"lastTransfer","type":"uint32"},{"internalType":"uint32","name":"stakeTimestamp","type":"uint32"},{"internalType":"uint32","name":"totalTimeStaked","type":"uint32"}],"internalType":"struct ERC721G.OwnerStruct","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"_tokenData","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"lastTransfer","type":"uint32"},{"internalType":"uint32","name":"stakeTimestamp","type":"uint32"},{"internalType":"uint32","name":"totalTimeStaked","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"_trueOwnerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"balanceOfStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimIsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collectionSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endStakingTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstBatch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstProvenance","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstStartingIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getLastTransfer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getStakeTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTotalClaimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getTotalTimeStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"isOwnerOfAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"isTrueOwnerOfAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBatchSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintIndex","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"lastTransfer","type":"uint32"},{"internalType":"uint32","name":"stakeTimestamp","type":"uint32"},{"internalType":"uint32","name":"totalTimeStaked","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicLimitPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity_","type":"uint256"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"reserve","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":"payable","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":"payable","type":"function"},{"inputs":[],"name":"salePublicKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"saleState","outputs":[{"internalType":"enum AngryThread.SaleState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"saleWhitelistKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"secondBatch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"secondProvenance","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"secondStartingIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"extension_","type":"string"}],"name":"setBaseURI_EXTENSION","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"bool_","type":"bool"}],"name":"setClaimIsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"collectionSize_","type":"uint256"}],"name":"setCollectionSize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"contractMetadataURI_","type":"string"}],"name":"setContractMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"endStakingTime_","type":"uint256"}],"name":"setEndStakingTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"firstBatch_","type":"uint256"}],"name":"setFirstBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"firstProvenance_","type":"string"}],"name":"setFirstProvenance0To10K","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"random1_","type":"uint256"},{"internalType":"uint256","name":"random2_","type":"uint256"},{"internalType":"uint256","name":"random3_","type":"uint256"}],"name":"setFirstStartingIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSupply_","type":"uint256"}],"name":"setMaxSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"publicLimitPerWallet_","type":"uint256"}],"name":"setPublicLimitPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"publicMintPrice_","type":"uint256"}],"name":"setPublicMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"salePublicKey_","type":"string"}],"name":"setSalePublicKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"saleState_","type":"uint256"}],"name":"setSaleState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"saleWhitelistKey_","type":"string"}],"name":"setSaleWhitelistKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"secondBatch_","type":"uint256"}],"name":"setSecondBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"secondProvenance_","type":"string"}],"name":"setSecondProvenance10KTo20K","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"random1_","type":"uint256"},{"internalType":"uint256","name":"random2_","type":"uint256"},{"internalType":"uint256","name":"random3_","type":"uint256"}],"name":"setSecondStartingIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signerAddress_","type":"address"}],"name":"setSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"bool_","type":"bool"}],"name":"setStakingIsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"thisAddressIndexInRewardContract_","type":"uint256"}],"name":"setThisAddressIndexInRewardContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"bool_","type":"bool"}],"name":"setUnstakingIsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wtfAddress_","type":"address"}],"name":"setWTFAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"wtfMintPriceInWei_","type":"uint256"}],"name":"setWTFMintPriceInWei","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"whitelistLimitPerWallet_","type":"uint256"}],"name":"setWhitelistLimitPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawAddress_","type":"address"}],"name":"setWithdrawAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingIsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"iid_","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":[],"name":"thisAddressIndexInRewardContract","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"address_","type":"address"}],"name":"totalBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"totalTimeStakedOfToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"totalTimeStakedOfTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakingIsEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"walletOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"walletOfOwnerStaked","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whitelistLimitPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity_","type":"uint256"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"whitelistMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wtfAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wtfMintPriceInWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6000600a55610100604052600660c0819052655075626c696360d01b60e09081526200002f91600c919062000484565b506040805180820190915260098082526815d2125511531254d560ba1b60209092019182526200006291600d9162000484565b5066038d7ea4c68000600e55612710601055614e20601155600a60125560016013556127106014556127106017553480156200009d57600080fd5b50604051620050bc380380620050bc833981016040819052620000c09162000610565b733cc6cdda760b79bafa08df41ecfa224f810dceb660016040518060400160405280600c81526020016b105b99dc9e48151a1c99585960a21b81525060405180604001604052806005815260200164414e47525960d81b8152506001606483600090805190602001906200013692919062000484565b5082516200014c90600190602086019062000484565b50600282905560809190915260a0525062000169905033620002e7565b6daaeb6d7670e522a718067333cd4e3b15620002ae578015620001fc57604051633e9f1edf60e11b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e90637d3e3dbe906044015b600060405180830381600087803b158015620001dd57600080fd5b505af1158015620001f2573d6000803e3d6000fd5b50505050620002ae565b6001600160a01b038216156200024d5760405163a0af290360e01b81523060048201526001600160a01b03831660248201526daaeb6d7670e522a718067333cd4e9063a0af290390604401620001c2565b604051632210724360e11b81523060048201526daaeb6d7670e522a718067333cd4e90634420e48690602401600060405180830381600087803b1580156200029457600080fd5b505af1158015620002a9573d6000803e3d6000fd5b505050505b50620002bc90508462000339565b620002c7836200038d565b620002d282620003e1565b620002dd8162000404565b50505050620006e1565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6200034362000423565b6001600160a01b0381166200036b5760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6200039762000423565b6001600160a01b038116620003bf5760405163d92e233d60e01b815260040160405180910390fd5b602180546001600160a01b0319166001600160a01b0392909216919091179055565b620003eb62000423565b80516200040090601f90602084019062000484565b5050565b6200040e62000423565b80516200040090601a90602084019062000484565b6008546001600160a01b03163314620004825760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640160405180910390fd5b565b8280546200049290620006a5565b90600052602060002090601f016020900481019282620004b6576000855562000501565b82601f10620004d157805160ff191683800117855562000501565b8280016001018555821562000501579182015b8281111562000501578251825591602001919060010190620004e4565b506200050f92915062000513565b5090565b5b808211156200050f576000815560010162000514565b6001600160a01b03811681146200054057600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200056b57600080fd5b81516001600160401b038082111562000588576200058862000543565b604051601f8301601f19908116603f01168101908282118183101715620005b357620005b362000543565b81604052838152602092508683858801011115620005d057600080fd5b600091505b83821015620005f45785820183015181830184015290820190620005d5565b83821115620006065760008385830101525b9695505050505050565b600080600080608085870312156200062757600080fd5b845162000634816200052a565b602086015190945062000647816200052a565b60408601519093506001600160401b03808211156200066557600080fd5b620006738883890162000559565b935060608701519150808211156200068a57600080fd5b50620006998782880162000559565b91505092959194509250565b600181811c90821680620006ba57607f821691505b602082108103620006db57634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a051614976620007466000396000818161088501528181612c5c01528181612c8701528181612cb4015261353b0152600081816112a50152818161192201528181611bae01528181611df301528181611f46015261266f01526149766000f3fe6080604052600436106106445760003560e01c80636ea3d6a211610338578063a713e45b116101b0578063d5abeb01116100f7578063e6798baa116100a0578063f16dc57d1161007a578063f16dc57d14611322578063f2fde38b14611337578063f719e36114611357578063fe2454141461137757600080fd5b8063e6798baa14611293578063e985e9c5146112c7578063f0e56f0d1461130257600080fd5b8063df833bdc116100d1578063df833bdc14611233578063e449f34114611253578063e54f42981461127357600080fd5b8063d5abeb01146111f4578063d7b4be241461120a578063dc53fd921461121d57600080fd5b8063ba745f2e11610159578063ced74b5011610133578063ced74b50146111a9578063cff206ba146111c9578063d55f9273146111de57600080fd5b8063ba745f2e146110ff578063c87b56dd14611169578063cc47a40b1461118957600080fd5b8063b0b50ed51161018a578063b0b50ed514611073578063b4bd7c32146110cd578063b88d4fde146110ec57600080fd5b8063a713e45b14611013578063aca8ffe714611033578063af2959071461105357600080fd5b80639280dc501161027f5780639ee0bcbc11610228578063a22cb46511610202578063a22cb46514610f9d578063a2de749b14610fbd578063a37bfa3f14610fdd578063a405ea2514610ffd57600080fd5b80639ee0bcbc14610f3d5780639fb1252b14610f5d578063a201fc5014610f7d57600080fd5b8063993568c111610259578063993568c114610ee35780639b10b77114610f035780639e852f7514610f1d57600080fd5b80639280dc5014610e98578063930ced3214610eb857806395d89b4114610ece57600080fd5b80637fa0cd1d116102e157806388895767116102bb5780638889576714610e255780638c0298b814610e5a5780638da5cb5b14610e7a57600080fd5b80637fa0cd1d14610dd05780638402345414610df05780638484f44e14610e1057600080fd5b806370a082311161031257806370a0823114610d5f578063715018a614610d9b578063796ac34a14610db057600080fd5b80636ea3d6a214610cff5780636f8b44b014610d1f5780636ff92f5014610d3f57600080fd5b80633ccfd60b116104cb57806358acb6f811610412578063603f4d52116103bb57806363ba7d461161039557806363ba7d4614610c9357806367ef226314610cb35780636b1ad36714610cc95780636b8c6af114610cdf57600080fd5b8063603f4d5214610c2c5780636137298e14610c535780636352211e14610c7357600080fd5b80635ce34ef0116103ec5780635ce34ef014610bcc5780635d82cf6e14610bec5780635e7676e114610c0c57600080fd5b806358acb6f814610b765780635aea7ec114610b8c5780635b7633d014610bac57600080fd5b8063494ba7431161047457806350b9e63d1161044e57806350b9e63d14610ada5780635266069d14610afa57806355f804b314610b5657600080fd5b8063494ba74314610a845780634a7efb6b14610a9a5780634b0ee02a14610aba57600080fd5b806342842e0e116104a557806342842e0e14610a2e578063438b630014610a4157806345c0f53314610a6e57600080fd5b80633ccfd60b146109d7578063403082f2146109ec57806341f4343414610a0c57600080fd5b80631581b6001161058f578063298b3e7c1161053857806332e30f511161051257806332e30f51146109775780633455f41e146109975780633ab1a494146109b757600080fd5b8063298b3e7c146108a75780632c2cdd60146108c75780632d7211191461095757600080fd5b8063227545a511610569578063227545a51461084057806323b872dd146108605780632913daa01461087357600080fd5b80631581b600146107f557806318160ddd146108155780631cae71a21461082a57600080fd5b806309457bd3116105f15780630ed89c01116105cb5780630ed89c01146107ad5780630fbf0a93146107c057806311dac106146107e057600080fd5b806309457bd314610749578063095ea7b3146107695780630ad347911461078957600080fd5b806306fdde031161062257806306fdde03146106c6578063081812fc146106db578063084c40881461072957600080fd5b806301a6adb11461064957806301ffc9a714610674578063046dc166146106a4575b600080fd5b34801561065557600080fd5b5061065e61138d565b60405161066b91906140f7565b60405180910390f35b34801561068057600080fd5b5061069461068f366004614120565b61141b565b604051901515815260200161066b565b3480156106b057600080fd5b506106c46106bf366004614152565b6114ec565b005b3480156106d257600080fd5b5061065e61153d565b3480156106e757600080fd5b506107116106f636600461416f565b6006602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161066b565b34801561073557600080fd5b506106c461074436600461416f565b61154a565b34801561075557600080fd5b506106c4610764366004614214565b6115c7565b34801561077557600080fd5b506106c461078436600461425d565b6115e6565b34801561079557600080fd5b5061079f600f5481565b60405190815260200161066b565b6106c46107bb366004614289565b6115ff565b3480156107cc57600080fd5b506106c46107db36600461434a565b611896565b3480156107ec57600080fd5b5061065e611911565b34801561080157600080fd5b50602154610711906001600160a01b031681565b34801561082157600080fd5b5061079f61191e565b34801561083657600080fd5b5061079f60195481565b34801561084c57600080fd5b506106c461085b36600461416f565b611953565b6106c461086e36600461438c565b611960565b34801561087f57600080fd5b5061079f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108b357600080fd5b506106c46108c2366004614214565b61198b565b3480156108d357600080fd5b506109216108e236600461416f565b6003602052600090815260409020546001600160a01b0381169063ffffffff600160a01b8204811691600160c01b8104821691600160e01b9091041684565b604080516001600160a01b03909516855263ffffffff93841660208601529183169184019190915216606082015260800161066b565b34801561096357600080fd5b506106c461097236600461416f565b6119a5565b34801561098357600080fd5b506106946109923660046143cd565b611b40565b3480156109a357600080fd5b5061079f6109b2366004614152565b611ba4565b3480156109c357600080fd5b506106c46109d2366004614152565b611c41565b3480156109e357600080fd5b506106c4611c92565b3480156109f857600080fd5b5061079f610a07366004614422565b611d45565b348015610a1857600080fd5b506107116daaeb6d7670e522a718067333cd4e81565b6106c4610a3c36600461438c565b611d58565b348015610a4d57600080fd5b50610a61610a5c366004614152565b611d7d565b60405161066b9190614448565b348015610a7a57600080fd5b5061079f60115481565b348015610a9057600080fd5b5061079f60145481565b348015610aa657600080fd5b50601d546106949062010000900460ff1681565b348015610ac657600080fd5b5061079f610ad5366004614152565b611e79565b348015610ae657600080fd5b506106c4610af536600461449a565b611ead565b348015610b0657600080fd5b50610b39610b15366004614152565b60046020526000908152604090205463ffffffff8082169164010000000090041682565b6040805163ffffffff93841681529290911660208301520161066b565b348015610b6257600080fd5b506106c4610b71366004614214565b611ed1565b348015610b8257600080fd5b5061079f60175481565b348015610b9857600080fd5b50610a61610ba7366004614152565b611eec565b348015610bb857600080fd5b50600b54610711906001600160a01b031681565b348015610bd857600080fd5b506106c4610be7366004614214565b611fe9565b348015610bf857600080fd5b506106c4610c0736600461416f565b612004565b348015610c1857600080fd5b50610711610c2736600461416f565b612011565b348015610c3857600080fd5b50601b54610c469060ff1681565b60405161066b91906144cd565b348015610c5f57600080fd5b506106c4610c6e3660046144f5565b612023565b348015610c7f57600080fd5b50610711610c8e36600461416f565b6120dc565b348015610c9f57600080fd5b506106c4610cae36600461416f565b612102565b348015610cbf57600080fd5b5061079f60165481565b348015610cd557600080fd5b5061079f60125481565b348015610ceb57600080fd5b506106c4610cfa36600461449a565b61210f565b348015610d0b57600080fd5b506106c4610d1a36600461416f565b612131565b348015610d2b57600080fd5b506106c4610d3a36600461416f565b61213e565b348015610d4b57600080fd5b50600954610711906001600160a01b031681565b348015610d6b57600080fd5b5061079f610d7a366004614152565b6001600160a01b031660009081526004602052604090205463ffffffff1690565b348015610da757600080fd5b506106c461214b565b348015610dbc57600080fd5b5061079f610dcb36600461416f565b61215f565b348015610ddc57600080fd5b506106c4610deb366004614214565b612218565b348015610dfc57600080fd5b50610a61610e0b36600461434a565b612233565b348015610e1c57600080fd5b5061065e6122da565b348015610e3157600080fd5b50610e45610e4036600461416f565b6122e7565b60405163ffffffff909116815260200161066b565b348015610e6657600080fd5b506106c4610e75366004614152565b6122f4565b348015610e8657600080fd5b506008546001600160a01b0316610711565b348015610ea457600080fd5b506106c4610eb336600461416f565b61231e565b348015610ec457600080fd5b5061079f600a5481565b348015610eda57600080fd5b5061065e61232b565b348015610eef57600080fd5b5061079f610efe36600461416f565b612338565b348015610f0f57600080fd5b50601d546106949060ff1681565b348015610f2957600080fd5b506106c4610f38366004614289565b61234f565b348015610f4957600080fd5b5061079f610f5836600461416f565b612468565b348015610f6957600080fd5b506106c4610f783660046144f5565b61247f565b348015610f8957600080fd5b506106c4610f98366004614214565b61253b565b348015610fa957600080fd5b506106c4610fb8366004614521565b612556565b348015610fc957600080fd5b506106c4610fd8366004614214565b61256a565b348015610fe957600080fd5b506106c4610ff836600461416f565b612585565b34801561100957600080fd5b5061079f60135481565b34801561101f57600080fd5b5061069461102e3660046143cd565b612592565b34801561103f57600080fd5b506106c461104e36600461416f565b6125f4565b34801561105f57600080fd5b506106c461106e36600461449a565b612601565b34801561107f57600080fd5b5061092161108e36600461416f565b6005602052600090815260409020546001600160a01b0381169063ffffffff600160a01b8204811691600160c01b8104821691600160e01b9091041684565b3480156110d957600080fd5b50601d5461069490610100900460ff1681565b6106c46110fa36600461455a565b61261c565b34801561110b57600080fd5b5061111f61111a36600461416f565b612649565b60405161066b919081516001600160a01b0316815260208083015163ffffffff90811691830191909152604080840151821690830152606092830151169181019190915260800190565b34801561117557600080fd5b5061065e61118436600461416f565b6127f0565b34801561119557600080fd5b506106c46111a436600461425d565b612827565b3480156111b557600080fd5b5061079f6111c436600461416f565b612839565b3480156111d557600080fd5b5061065e612898565b3480156111ea57600080fd5b5061079f60025481565b34801561120057600080fd5b5061079f60105481565b34801561121657600080fd5b5030610711565b34801561122957600080fd5b5061079f600e5481565b34801561123f57600080fd5b506106c461124e36600461416f565b6128a5565b34801561125f57600080fd5b506106c461126e36600461434a565b6128b2565b34801561127f57600080fd5b506106c461128e36600461434a565b6128ee565b34801561129f57600080fd5b5061079f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156112d357600080fd5b506106946112e23660046145da565b600760209081526000928352604080842090915290825290205460ff1681565b34801561130e57600080fd5b5061079f61131d36600461416f565b612917565b34801561132e57600080fd5b50610e4561292e565b34801561134357600080fd5b506106c4611352366004614152565b61293b565b34801561136357600080fd5b506106c461137236600461416f565b6129c8565b34801561138357600080fd5b5061079f601e5481565b6018805461139a90614608565b80601f01602080910402602001604051908101604052809291908181526020018280546113c690614608565b80156114135780601f106113e857610100808354040283529160200191611413565b820191906000526020600020905b8154815290600101906020018083116113f657829003601f168201915b505050505081565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316148061147e57507f80ac58cd000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b806114b257507f5b5e139f000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b806114e657507f7f5828d0000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b6114f46129d5565b6001600160a01b03811661151b5760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000805461139a90614608565b6115526129d5565b806002811115611564576115646144b7565b601b805460ff19166001836002811115611580576115806144b7565b0217905550601b546040517f92a17b827ee9d42ea9454bb4ca941a1800870e6d01c0842d09ba23ccc0190ee1916115bc9160ff909116906144cd565b60405180910390a150565b6115cf6129d5565b80516115e2906018906020840190614006565b5050565b816115f081612a2f565b6115fa8383612b1a565b505050565b600233321461162157604051637aafae9760e01b815260040160405180910390fd5b806002811115611633576116336144b7565b601b5460ff16600281111561164a5761164a6144b7565b1461166857604051633482502f60e01b815260040160405180910390fd5b61173383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050600c80549092506116b09150614608565b80601f01602080910402602001604051908101604052809291908181526020018280546116dc90614608565b80156117295780601f106116fe57610100808354040283529160200191611729565b820191906000526020600020905b81548152906001019060200180831161170c57829003601f168201915b5050505050612bb7565b61175057604051638baa579f60e01b815260040160405180910390fd5b6010548461175c61191e565b6117669190614658565b111561179e576040517f31b52d7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254336000908152600460205260409020546117ca908690640100000000900463ffffffff16614658565b11156117e9576040516313f9b25d60e21b815260040160405180910390fd5b600e546117f69085614670565b341461182e576040517f99b5cb1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254841115611851576040516313f9b25d60e21b815260040160405180910390fd5b61185b3385612c58565b60405184815233907f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe9060200160405180910390a250505050565b601d5460ff166118b95760405163e0bc454160e01b815260040160405180910390fd5b6118c38282612ce7565b60005b818110156115fa5742601c60008585858181106118e5576118e561468f565b905060200201358152602001908152602001600020819055508080611909906146a5565b9150506118c6565b600c805461139a90614608565b60007f000000000000000000000000000000000000000000000000000000000000000060025461194e91906146be565b905090565b61195b6129d5565b601e55565b826001600160a01b038116331461197a5761197a33612a2f565b611985848484612d7c565b50505050565b6119936129d5565b80516115e29060209081840190614006565b601d5460ff166119c85760405163e0bc454160e01b815260040160405180910390fd5b6009546001600160a01b03166119f15760405163d92e233d60e01b815260040160405180910390fd5b601154816119fd61191e565b611a079190614658565b1115611a3f576040517f52df9fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254811115611a7b576040517fd887771b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600f546001600160a01b03909116906379cc6790903390611aa0908590614670565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015611ae657600080fd5b505af1158015611afa573d6000803e3d6000fd5b50505050611b083382612c58565b60405181815233907fb4cebbef2afa97d0409f298c34cebfd89b8d996d75659932858959611ae7d0619060200160405180910390a250565b600080825b856001600160a01b0316611b70868685818110611b6457611b6461468f565b90506020020135612011565b6001600160a01b031614611b8957600092505050611b9d565b808260010192508210611b45576001925050505b9392505050565b60025460009081907f0000000000000000000000000000000000000000000000000000000000000000905b80821015611c3857846001600160a01b0316611bea836120dc565b6001600160a01b031614158015611c1a5750846001600160a01b0316611c0f83612011565b6001600160a01b0316145b15611c2d5782611c29816146a5565b9350505b816001019150611bcf565b50909392505050565b611c496129d5565b6001600160a01b038116611c705760405163d92e233d60e01b815260040160405180910390fd5b602180546001600160a01b0319166001600160a01b0392909216919091179055565b611c9a6129d5565b6021546040516000916001600160a01b03169047908381818185875af1925050503d8060008114611ce7576040519150601f19603f3d011682016040523d82523d6000602084013e611cec565b606091505b5050905080611d425760405162461bcd60e51b815260206004820152601060248201527f5472616e73666572206661696c65642e0000000000000000000000000000000060448201526064015b60405180910390fd5b50565b60006114e663ffffffff8316600a614670565b826001600160a01b0381163314611d7257611d7233612a2f565b611985848484612e03565b60606000611da6836001600160a01b031660009081526004602052604090205463ffffffff1690565b905060008167ffffffffffffffff811115611dc357611dc3614188565b604051908082528060200260200182016040528015611dec578160200160208202803683370190505b50905060007f00000000000000000000000000000000000000000000000000000000000000005b83821015611e6f57856001600160a01b0316611e2e826120dc565b6001600160a01b031603611e6757808383611e48816146a5565b945081518110611e5a57611e5a61468f565b6020026020010181815250505b600101611e13565b5090949350505050565b6000611e8482611ba4565b6001600160a01b03831660009081526004602052604090205463ffffffff166114e69190614658565b611eb56129d5565b601d8054911515620100000262ff000019909216919091179055565b611ed96129d5565b80516115e290601f906020840190614006565b60606000611ef983611ba4565b905060008167ffffffffffffffff811115611f1657611f16614188565b604051908082528060200260200182016040528015611f3f578160200160208202803683370190505b50905060007f00000000000000000000000000000000000000000000000000000000000000005b83821015611e6f57856001600160a01b0316611f81826120dc565b6001600160a01b031614158015611fb15750856001600160a01b0316611fa682612011565b6001600160a01b0316145b15611fe157808383611fc2816146a5565b945081518110611fd457611fd461468f565b6020026020010181815250505b600101611f66565b611ff16129d5565b80516115e290600c906020840190614006565b61200c6129d5565b600e55565b600061201c82612649565b5192915050565b601654156120445760405163a741a04560e01b815260040160405180910390fd5b601454604080514260208201529081018590524460608083019190915241901b6bffffffffffffffffffffffff19166080820152456094820152434060b482015260d4810184905260f48101839052610114016040516020818303038152906040528051906020012060001c6120ba91906146eb565b601681905515806120cd57506016546001145b156115fa576002601655505050565b6000806120e883612649565b9050806040015163ffffffff1660001461201c5730611b9d565b61210a6129d5565b600f55565b6121176129d5565b601d80549115156101000261ff0019909216919091179055565b6121396129d5565b601255565b6121466129d5565b601055565b6121536129d5565b61215d6000612e1e565b565b600954600a54604051631b8e0c3560e21b815260048101919091526000916001600160a01b03169082908290636e3830d490602401602060405180830381865afa1580156121b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d591906146ff565b905060006121e542601e54612e70565b6000868152601c602052604081205491925090839061220490846146be565b61220e9190614670565b9695505050505050565b6122206129d5565b80516115e290600d906020840190614006565b6060600082818167ffffffffffffffff81111561225257612252614188565b60405190808252806020026020018201604052801561227b578160200160208202803683370190505b5090505b818310156122d1576122a886868581811061229c5761229c61468f565b90506020020135612839565b8184815181106122ba576122ba61468f565b60200260200101818152505082600101925061227f565b95945050505050565b600d805461139a90614608565b60006114e6600a83614718565b6122fc6129d5565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6123266129d5565b601355565b6001805461139a90614608565b60006114e661234683612649565b60600151611d45565b600133321461237157604051637aafae9760e01b815260040160405180910390fd5b806002811115612383576123836144b7565b601b5460ff16600281111561239a5761239a6144b7565b146123b857604051633482502f60e01b815260040160405180910390fd5b61240083838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050600d80549092506116b09150614608565b61241d57604051638baa579f60e01b815260040160405180910390fd5b60135433600090815260046020526040902054612449908690640100000000900463ffffffff16614658565b1115611851576040516313f9b25d60e21b815260040160405180910390fd5b60006114e661247683612649565b60400151611d45565b601954156124a05760405163a741a04560e01b815260040160405180910390fd5b601754604080516020810186905242918101919091524460608083019190915241901b6bffffffffffffffffffffffff1916608082015245609482015260b48101849052434060d482015260f48101839052610114016040516020818303038152906040528051906020012060001c61251991906146eb565b6019819055158061252c57506019546001145b156115fa576002601955505050565b6125436129d5565b80516115e290601a906020840190614006565b8161256081612a2f565b6115fa8383612e86565b6125726129d5565b80516115e2906015906020840190614006565b61258d6129d5565b600a55565b600080825b856001600160a01b03166125c28686858181106125b6576125b661468f565b905060200201356120dc565b6001600160a01b0316146125db57600092505050611b9d565b8082600101925082106125975750600195945050505050565b6125fc6129d5565b601155565b6126096129d5565b601d805460ff1916911515919091179055565b836001600160a01b03811633146126365761263633612a2f565b61264285858585612e91565b5050505050565b6040805160808101825260008082526020820181905291810182905260608101919091527f00000000000000000000000000000000000000000000000000000000000000008210156126dd5760405162461bcd60e51b815260206004820152601a60248201527f546f6b656e49642062656c6f77207374617274696e67204964210000000000006044820152606401611d39565b6000828152600360205260409020546001600160a01b031615158061270457506002548210155b156127685750600090815260036020908152604091829020825160808101845290546001600160a01b038116825263ffffffff600160a01b8204811693830193909352600160c01b8104831693820193909352600160e01b90920416606082015290565b815b6000818152600560205260409020546001600160a01b031661278f576000190161276a565b600090815260056020908152604091829020825160808101845290546001600160a01b038116825263ffffffff600160a01b8204811693830193909352600160c01b8104831693820193909352600160e01b90920416606082015292915050565b6060601f6127fd83613027565b6020604051602001612811939291906147c5565b6040516020818303038152906040529050919050565b61282f6129d5565b6115e28282612c58565b60008061284583612649565b905060006128568260600151611d45565b9050600080836040015163ffffffff161161287257600061288c565b61288c836040015161288261292e565b610a0791906147f8565b90506122d18183614658565b6015805461139a90614608565b6128ad6129d5565b601755565b601d54610100900460ff166128da5760405163e0bc454160e01b815260040160405180910390fd5b6128e48282613165565b6115e282826131fa565b601d5462010000900460ff166128e45760405163e0bc454160e01b815260040160405180910390fd5b60006114e661292583612649565b60200151611d45565b600061194e600a42614718565b6129436129d5565b6001600160a01b0381166129bf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401611d39565b611d4281612e1e565b6129d06129d5565b601455565b6008546001600160a01b0316331461215d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611d39565b6daaeb6d7670e522a718067333cd4e3b15611d42576040517fc61711340000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015612ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad9919061481d565b611d42576040517fede71dcc0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611d39565b6000612b25826120dc565b90506001600160a01b038116331480612b6157506001600160a01b038116600090815260076020908152604080832033845290915290205460ff165b612bad5760405162461bcd60e51b815260206004820152601f60248201527f455243373231473a20617070726f7665206e6f7420617574686f72697a6564006044820152606401611d39565b6115fa8383613451565b6000612c40833384604051602001612bd092919061483a565b604051602081830303815290604052612be890614872565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604051602081830303815290604052805190602001206134bf90919063ffffffff16565b600b546001600160a01b039182169116149392505050565b805b7f0000000000000000000000000000000000000000000000000000000000000000811115612cdd57612cac7f0000000000000000000000000000000000000000000000000000000000000000826146be565b9050612cd8837f00000000000000000000000000000000000000000000000000000000000000006134e3565b612c5a565b6115fa83826134e3565b6000815b80821015611985576000612d16858585818110612d0a57612d0a61468f565b905060200201356136d9565b9050336001600160a01b03821614612d705760405162461bcd60e51b815260206004820152601660248201527f596f7520617265206e6f7420746865206f776e657221000000000000000000006044820152606401611d39565b82600101925050612ceb565b612d8633826136e5565b612df85760405162461bcd60e51b815260206004820152602260248201527f455243373231473a207472616e7366657246726f6d20756e617574686f72697a60448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401611d39565b6115fa838383613763565b6115fa8383836040518060200160405280600081525061261c565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000818310612e7f5781611b9d565b5090919050565b6115e233838361390e565b612e9c848484611960565b6001600160a01b0383163b15611985576000836001600160a01b031663150b7a0233878686604051602401612ed49493929190614896565b6040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051612f2291906148c8565b6000604051808303816000865af19150503d8060008114612f5f576040519150601f19603f3d011682016040523d82523d6000602084013e612f64565b606091505b50915050600081806020019051810190612f7e91906148e4565b90507f150b7a02000000000000000000000000000000000000000000000000000000006001600160e01b031982161461301f5760405162461bcd60e51b815260206004820152603360248201527f455243373231473a20736166655472616e7366657246726f6d20746f5f206e6f60448201527f6e2d45524337323152656365697661626c6521000000000000000000000000006064820152608401611d39565b505050505050565b60608160000361306a57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115613094578061307e816146a5565b915061308d9050600a83614718565b915061306e565b60008167ffffffffffffffff8111156130af576130af614188565b6040519080825280601f01601f1916602001820160405280156130d9576020820181803683370190505b5090505b841561315d57816130ed81614901565b92506130fc9050600a866146eb565b613107906030614658565b60f81b81838151811061311c5761311c61468f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613156600a86614718565b94506130dd565b949350505050565b6000815b808210156119855760006131948585858181106131885761318861468f565b9050602002013561397b565b9050336001600160a01b038216146131ee5760405162461bcd60e51b815260206004820152601660248201527f596f7520617265206e6f7420746865206f776e657221000000000000000000006044820152606401611d39565b82600101925050613169565b601e54600003613236576040517f441dfbd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156132a95733613257848484818110611b6457611b6461468f565b6001600160a01b031614613297576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806132a1816146a5565b915050613239565b50600954600a54604051631b8e0c3560e21b81526001600160a01b03909216916000918391636e3830d4916132e49160040190815260200190565b602060405180830381865afa158015613301573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332591906146ff565b9050600061333542601e54612e70565b905060005b8481101561301f57600083601c600089898681811061335b5761335b61468f565b905060200201358152602001908152602001600020548461337c91906146be565b6133869190614670565b600a546040517f9d9df5690000000000000000000000000000000000000000000000000000000081526004810191909152336024820152604481018290529091506001600160a01b03861690639d9df56990606401600060405180830381600087803b1580156133f557600080fd5b505af1158015613409573d6000803e3d6000fd5b5050505042601c60008989868181106134245761342461468f565b90506020020135815260200190815260200160002081905550508080613449906146a5565b91505061333a565b600081815260066020526040902080546001600160a01b0319166001600160a01b0384169081179091558190613486826120dc565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008060006134ce8585613988565b915091506134db816139cd565b509392505050565b6001600160a01b0382166135395760405162461bcd60e51b815260206004820152601d60248201527f455243373231473a205f6d696e74496e7465726e616c20746f203078300000006044820152606401611d39565b7f00000000000000000000000000000000000000000000000000000000000000008111156135cf5760405162461bcd60e51b815260206004820152602860248201527f455243373231473a205f6d696e74496e7465726e616c206f766572206d61784260448201527f6174636853697a650000000000000000000000000000000000000000000000006064820152608401611d39565b60025460006135de8383614658565b600083815260056020526040902080546001600160a01b0319166001600160a01b038716179055905061360f61292e565b6000838152600560209081526040808320805463ffffffff60a01b1916600160a01b63ffffffff968716021790556001600160a01b038816835260049091529020805467ffffffffffffffff1981168184168701841690811764010000000063ffffffff1990931690911782900484168701909316029190911790555b60405182906001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a480826001019250821061368c57600255505050565b60006114e68242613b32565b6000806136f1836120dc565b9050836001600160a01b0316816001600160a01b0316148061372c57506000838152600660205260409020546001600160a01b038581169116145b8061315d57506001600160a01b0380821660009081526007602090815260408083209388168352929052205460ff16949350505050565b61376c816120dc565b6001600160a01b0316836001600160a01b0316146137cc5760405162461bcd60e51b815260206004820152601d60248201527f455243373231473a205f7472616e7366657220213d206f776e65724f660000006044820152606401611d39565b6001600160a01b0382166138225760405162461bcd60e51b815260206004820152601960248201527f455243373231473a205f7472616e7366657220746f20307830000000000000006044820152606401611d39565b600081815260066020908152604080832080546001600160a01b0319908116909155600390925290912080549091166001600160a01b03841617905561386661292e565b6000828152600360209081526040808320805463ffffffff958616600160a01b0263ffffffff60a01b199091161790556001600160a01b038088168085526004909352818420805460001981881601871663ffffffff1991821617909155908716808552828520805480881660010190971696909216959095179055518493927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6001600160a01b03838116600081815260076020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60006114e6826000613b32565b60008082516041036139be5760208301516040840151606085015160001a6139b287828585613e65565b945094505050506139c6565b506000905060025b9250929050565b60008160048111156139e1576139e16144b7565b036139e95750565b60018160048111156139fd576139fd6144b7565b03613a4a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401611d39565b6002816004811115613a5e57613a5e6144b7565b03613aab5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611d39565b6003816004811115613abf57613abf6144b7565b03611d425760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401611d39565b600080613b3e84612649565b8051604082015191925090613b538684613f29565b600086815260066020526040902080546001600160a01b03191690558415613c705763ffffffff811615613bef5760405162461bcd60e51b815260206004820152602c60248201527f455243373231473a205f7365745374616b6554696d657374616d70282920616c60448201527f7265616479207374616b656400000000000000000000000000000000000000006064820152608401611d39565b6001600160a01b038216600081815260046020526040808220805463ffffffff1980821663ffffffff9283166000190183161790925530808552838520805480841660010190931692909316919091179091559051899391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4613e09565b8063ffffffff16600003613cec5760405162461bcd60e51b815260206004820152602e60248201527f455243373231473a205f7365745374616b6554696d657374616d70282920616c60448201527f726561647920756e7374616b65640000000000000000000000000000000000006064820152608401611d39565b6001600160a01b03821660009081526004602081905260408220805463ffffffff8082166001011663ffffffff1990911617905590613d283090565b6001600160a01b0316815260208101919091526040016000908120805463ffffffff19811663ffffffff9182166000190190911617905581613d6861292e565b613d7291906147f8565b600088815260036020526040902080549192508291601c90613da2908490600160e01b900463ffffffff16614918565b92506101000a81548163ffffffff021916908363ffffffff16021790555086836001600160a01b0316613dd23090565b6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505b613e12856122e7565b6000878152600360205260409020805463ffffffff92909216600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555091505092915050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613e9c5750600090506003613f20565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613ef0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613f1957600060019250925050613f20565b9150600090505b94509492505050565b6000828152600360205260409020546001600160a01b03166115e257600082815260036020908152604091829020835181549285015193850151606086015163ffffffff908116600160e01b027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff928216600160c01b029290921677ffffffffffffffffffffffffffffffffffffffffffffffff91909616600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009095166001600160a01b03909316929092179390931716929092171790555050565b82805461401290614608565b90600052602060002090601f016020900481019282614034576000855561407a565b82601f1061404d57805160ff191683800117855561407a565b8280016001018555821561407a579182015b8281111561407a57825182559160200191906001019061405f565b5061408692915061408a565b5090565b5b80821115614086576000815560010161408b565b60005b838110156140ba5781810151838201526020016140a2565b838111156119855750506000910152565b600081518084526140e381602086016020860161409f565b601f01601f19169290920160200192915050565b602081526000611b9d60208301846140cb565b6001600160e01b031981168114611d4257600080fd5b60006020828403121561413257600080fd5b8135611b9d8161410a565b6001600160a01b0381168114611d4257600080fd5b60006020828403121561416457600080fd5b8135611b9d8161413d565b60006020828403121561418157600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156141b9576141b9614188565b604051601f8501601f19908116603f011681019082821181831017156141e1576141e1614188565b816040528093508581528686860111156141fa57600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121561422657600080fd5b813567ffffffffffffffff81111561423d57600080fd5b8201601f8101841361424e57600080fd5b61315d8482356020840161419e565b6000806040838503121561427057600080fd5b823561427b8161413d565b946020939093013593505050565b60008060006040848603121561429e57600080fd5b83359250602084013567ffffffffffffffff808211156142bd57600080fd5b818601915086601f8301126142d157600080fd5b8135818111156142e057600080fd5b8760208285010111156142f257600080fd5b6020830194508093505050509250925092565b60008083601f84011261431757600080fd5b50813567ffffffffffffffff81111561432f57600080fd5b6020830191508360208260051b85010111156139c657600080fd5b6000806020838503121561435d57600080fd5b823567ffffffffffffffff81111561437457600080fd5b61438085828601614305565b90969095509350505050565b6000806000606084860312156143a157600080fd5b83356143ac8161413d565b925060208401356143bc8161413d565b929592945050506040919091013590565b6000806000604084860312156143e257600080fd5b83356143ed8161413d565b9250602084013567ffffffffffffffff81111561440957600080fd5b61441586828701614305565b9497909650939450505050565b60006020828403121561443457600080fd5b813563ffffffff81168114611b9d57600080fd5b6020808252825182820181905260009190848201906040850190845b8181101561448057835183529284019291840191600101614464565b50909695505050505050565b8015158114611d4257600080fd5b6000602082840312156144ac57600080fd5b8135611b9d8161448c565b634e487b7160e01b600052602160045260246000fd5b60208101600383106144ef57634e487b7160e01b600052602160045260246000fd5b91905290565b60008060006060848603121561450a57600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561453457600080fd5b823561453f8161413d565b9150602083013561454f8161448c565b809150509250929050565b6000806000806080858703121561457057600080fd5b843561457b8161413d565b9350602085013561458b8161413d565b925060408501359150606085013567ffffffffffffffff8111156145ae57600080fd5b8501601f810187136145bf57600080fd5b6145ce8782356020840161419e565b91505092959194509250565b600080604083850312156145ed57600080fd5b82356145f88161413d565b9150602083013561454f8161413d565b600181811c9082168061461c57607f821691505b60208210810361463c57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561466b5761466b614642565b500190565b600081600019048311821515161561468a5761468a614642565b500290565b634e487b7160e01b600052603260045260246000fd5b6000600182016146b7576146b7614642565b5060010190565b6000828210156146d0576146d0614642565b500390565b634e487b7160e01b600052601260045260246000fd5b6000826146fa576146fa6146d5565b500690565b60006020828403121561471157600080fd5b5051919050565b600082614727576147276146d5565b500490565b8054600090600181811c908083168061474657607f831692505b6020808410820361476757634e487b7160e01b600052602260045260246000fd5b81801561477b576001811461478c576147b9565b60ff198616895284890196506147b9565b60008881526020902060005b868110156147b15781548b820152908501908301614798565b505084890196505b50505050505092915050565b60006147d1828661472c565b84516147e181836020890161409f565b6147ed8183018661472c565b979650505050505050565b600063ffffffff8381169083168181101561481557614815614642565b039392505050565b60006020828403121561482f57600080fd5b8151611b9d8161448c565b6bffffffffffffffffffffffff198360601b1681526000825161486481601485016020870161409f565b919091016014019392505050565b8051602080830151919081101561463c5760001960209190910360031b1b16919050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261220e60808301846140cb565b600082516148da81846020870161409f565b9190910192915050565b6000602082840312156148f657600080fd5b8151611b9d8161410a565b60008161491057614910614642565b506000190190565b600063ffffffff80831681851680830382111561493757614937614642565b0194935050505056fea26469706673582212203cef86a5027532037ec9e80198eb68352ab1dc113263f6fcfb1df42f66b36b2f64736f6c634300080d003300000000000000000000000060ee5aaa2ef54bef9e85d4a28a26e51af7bb7194000000000000000000000000aa1db62de542929f30a47d42231ef8a8500bf6dd000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000003068747470733a2f2f616e6772797468726561646e66742e73332e616d617a6f6e6177732e636f6d2f73746167655f312f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042697066733a2f2f6261666b726569667963787579636b6a6d6a787268737877626f736c69776d7062666c69746e746e3273716d6179746466783271796f3435693661000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106106445760003560e01c80636ea3d6a211610338578063a713e45b116101b0578063d5abeb01116100f7578063e6798baa116100a0578063f16dc57d1161007a578063f16dc57d14611322578063f2fde38b14611337578063f719e36114611357578063fe2454141461137757600080fd5b8063e6798baa14611293578063e985e9c5146112c7578063f0e56f0d1461130257600080fd5b8063df833bdc116100d1578063df833bdc14611233578063e449f34114611253578063e54f42981461127357600080fd5b8063d5abeb01146111f4578063d7b4be241461120a578063dc53fd921461121d57600080fd5b8063ba745f2e11610159578063ced74b5011610133578063ced74b50146111a9578063cff206ba146111c9578063d55f9273146111de57600080fd5b8063ba745f2e146110ff578063c87b56dd14611169578063cc47a40b1461118957600080fd5b8063b0b50ed51161018a578063b0b50ed514611073578063b4bd7c32146110cd578063b88d4fde146110ec57600080fd5b8063a713e45b14611013578063aca8ffe714611033578063af2959071461105357600080fd5b80639280dc501161027f5780639ee0bcbc11610228578063a22cb46511610202578063a22cb46514610f9d578063a2de749b14610fbd578063a37bfa3f14610fdd578063a405ea2514610ffd57600080fd5b80639ee0bcbc14610f3d5780639fb1252b14610f5d578063a201fc5014610f7d57600080fd5b8063993568c111610259578063993568c114610ee35780639b10b77114610f035780639e852f7514610f1d57600080fd5b80639280dc5014610e98578063930ced3214610eb857806395d89b4114610ece57600080fd5b80637fa0cd1d116102e157806388895767116102bb5780638889576714610e255780638c0298b814610e5a5780638da5cb5b14610e7a57600080fd5b80637fa0cd1d14610dd05780638402345414610df05780638484f44e14610e1057600080fd5b806370a082311161031257806370a0823114610d5f578063715018a614610d9b578063796ac34a14610db057600080fd5b80636ea3d6a214610cff5780636f8b44b014610d1f5780636ff92f5014610d3f57600080fd5b80633ccfd60b116104cb57806358acb6f811610412578063603f4d52116103bb57806363ba7d461161039557806363ba7d4614610c9357806367ef226314610cb35780636b1ad36714610cc95780636b8c6af114610cdf57600080fd5b8063603f4d5214610c2c5780636137298e14610c535780636352211e14610c7357600080fd5b80635ce34ef0116103ec5780635ce34ef014610bcc5780635d82cf6e14610bec5780635e7676e114610c0c57600080fd5b806358acb6f814610b765780635aea7ec114610b8c5780635b7633d014610bac57600080fd5b8063494ba7431161047457806350b9e63d1161044e57806350b9e63d14610ada5780635266069d14610afa57806355f804b314610b5657600080fd5b8063494ba74314610a845780634a7efb6b14610a9a5780634b0ee02a14610aba57600080fd5b806342842e0e116104a557806342842e0e14610a2e578063438b630014610a4157806345c0f53314610a6e57600080fd5b80633ccfd60b146109d7578063403082f2146109ec57806341f4343414610a0c57600080fd5b80631581b6001161058f578063298b3e7c1161053857806332e30f511161051257806332e30f51146109775780633455f41e146109975780633ab1a494146109b757600080fd5b8063298b3e7c146108a75780632c2cdd60146108c75780632d7211191461095757600080fd5b8063227545a511610569578063227545a51461084057806323b872dd146108605780632913daa01461087357600080fd5b80631581b600146107f557806318160ddd146108155780631cae71a21461082a57600080fd5b806309457bd3116105f15780630ed89c01116105cb5780630ed89c01146107ad5780630fbf0a93146107c057806311dac106146107e057600080fd5b806309457bd314610749578063095ea7b3146107695780630ad347911461078957600080fd5b806306fdde031161062257806306fdde03146106c6578063081812fc146106db578063084c40881461072957600080fd5b806301a6adb11461064957806301ffc9a714610674578063046dc166146106a4575b600080fd5b34801561065557600080fd5b5061065e61138d565b60405161066b91906140f7565b60405180910390f35b34801561068057600080fd5b5061069461068f366004614120565b61141b565b604051901515815260200161066b565b3480156106b057600080fd5b506106c46106bf366004614152565b6114ec565b005b3480156106d257600080fd5b5061065e61153d565b3480156106e757600080fd5b506107116106f636600461416f565b6006602052600090815260409020546001600160a01b031681565b6040516001600160a01b03909116815260200161066b565b34801561073557600080fd5b506106c461074436600461416f565b61154a565b34801561075557600080fd5b506106c4610764366004614214565b6115c7565b34801561077557600080fd5b506106c461078436600461425d565b6115e6565b34801561079557600080fd5b5061079f600f5481565b60405190815260200161066b565b6106c46107bb366004614289565b6115ff565b3480156107cc57600080fd5b506106c46107db36600461434a565b611896565b3480156107ec57600080fd5b5061065e611911565b34801561080157600080fd5b50602154610711906001600160a01b031681565b34801561082157600080fd5b5061079f61191e565b34801561083657600080fd5b5061079f60195481565b34801561084c57600080fd5b506106c461085b36600461416f565b611953565b6106c461086e36600461438c565b611960565b34801561087f57600080fd5b5061079f7f000000000000000000000000000000000000000000000000000000000000006481565b3480156108b357600080fd5b506106c46108c2366004614214565b61198b565b3480156108d357600080fd5b506109216108e236600461416f565b6003602052600090815260409020546001600160a01b0381169063ffffffff600160a01b8204811691600160c01b8104821691600160e01b9091041684565b604080516001600160a01b03909516855263ffffffff93841660208601529183169184019190915216606082015260800161066b565b34801561096357600080fd5b506106c461097236600461416f565b6119a5565b34801561098357600080fd5b506106946109923660046143cd565b611b40565b3480156109a357600080fd5b5061079f6109b2366004614152565b611ba4565b3480156109c357600080fd5b506106c46109d2366004614152565b611c41565b3480156109e357600080fd5b506106c4611c92565b3480156109f857600080fd5b5061079f610a07366004614422565b611d45565b348015610a1857600080fd5b506107116daaeb6d7670e522a718067333cd4e81565b6106c4610a3c36600461438c565b611d58565b348015610a4d57600080fd5b50610a61610a5c366004614152565b611d7d565b60405161066b9190614448565b348015610a7a57600080fd5b5061079f60115481565b348015610a9057600080fd5b5061079f60145481565b348015610aa657600080fd5b50601d546106949062010000900460ff1681565b348015610ac657600080fd5b5061079f610ad5366004614152565b611e79565b348015610ae657600080fd5b506106c4610af536600461449a565b611ead565b348015610b0657600080fd5b50610b39610b15366004614152565b60046020526000908152604090205463ffffffff8082169164010000000090041682565b6040805163ffffffff93841681529290911660208301520161066b565b348015610b6257600080fd5b506106c4610b71366004614214565b611ed1565b348015610b8257600080fd5b5061079f60175481565b348015610b9857600080fd5b50610a61610ba7366004614152565b611eec565b348015610bb857600080fd5b50600b54610711906001600160a01b031681565b348015610bd857600080fd5b506106c4610be7366004614214565b611fe9565b348015610bf857600080fd5b506106c4610c0736600461416f565b612004565b348015610c1857600080fd5b50610711610c2736600461416f565b612011565b348015610c3857600080fd5b50601b54610c469060ff1681565b60405161066b91906144cd565b348015610c5f57600080fd5b506106c4610c6e3660046144f5565b612023565b348015610c7f57600080fd5b50610711610c8e36600461416f565b6120dc565b348015610c9f57600080fd5b506106c4610cae36600461416f565b612102565b348015610cbf57600080fd5b5061079f60165481565b348015610cd557600080fd5b5061079f60125481565b348015610ceb57600080fd5b506106c4610cfa36600461449a565b61210f565b348015610d0b57600080fd5b506106c4610d1a36600461416f565b612131565b348015610d2b57600080fd5b506106c4610d3a36600461416f565b61213e565b348015610d4b57600080fd5b50600954610711906001600160a01b031681565b348015610d6b57600080fd5b5061079f610d7a366004614152565b6001600160a01b031660009081526004602052604090205463ffffffff1690565b348015610da757600080fd5b506106c461214b565b348015610dbc57600080fd5b5061079f610dcb36600461416f565b61215f565b348015610ddc57600080fd5b506106c4610deb366004614214565b612218565b348015610dfc57600080fd5b50610a61610e0b36600461434a565b612233565b348015610e1c57600080fd5b5061065e6122da565b348015610e3157600080fd5b50610e45610e4036600461416f565b6122e7565b60405163ffffffff909116815260200161066b565b348015610e6657600080fd5b506106c4610e75366004614152565b6122f4565b348015610e8657600080fd5b506008546001600160a01b0316610711565b348015610ea457600080fd5b506106c4610eb336600461416f565b61231e565b348015610ec457600080fd5b5061079f600a5481565b348015610eda57600080fd5b5061065e61232b565b348015610eef57600080fd5b5061079f610efe36600461416f565b612338565b348015610f0f57600080fd5b50601d546106949060ff1681565b348015610f2957600080fd5b506106c4610f38366004614289565b61234f565b348015610f4957600080fd5b5061079f610f5836600461416f565b612468565b348015610f6957600080fd5b506106c4610f783660046144f5565b61247f565b348015610f8957600080fd5b506106c4610f98366004614214565b61253b565b348015610fa957600080fd5b506106c4610fb8366004614521565b612556565b348015610fc957600080fd5b506106c4610fd8366004614214565b61256a565b348015610fe957600080fd5b506106c4610ff836600461416f565b612585565b34801561100957600080fd5b5061079f60135481565b34801561101f57600080fd5b5061069461102e3660046143cd565b612592565b34801561103f57600080fd5b506106c461104e36600461416f565b6125f4565b34801561105f57600080fd5b506106c461106e36600461449a565b612601565b34801561107f57600080fd5b5061092161108e36600461416f565b6005602052600090815260409020546001600160a01b0381169063ffffffff600160a01b8204811691600160c01b8104821691600160e01b9091041684565b3480156110d957600080fd5b50601d5461069490610100900460ff1681565b6106c46110fa36600461455a565b61261c565b34801561110b57600080fd5b5061111f61111a36600461416f565b612649565b60405161066b919081516001600160a01b0316815260208083015163ffffffff90811691830191909152604080840151821690830152606092830151169181019190915260800190565b34801561117557600080fd5b5061065e61118436600461416f565b6127f0565b34801561119557600080fd5b506106c46111a436600461425d565b612827565b3480156111b557600080fd5b5061079f6111c436600461416f565b612839565b3480156111d557600080fd5b5061065e612898565b3480156111ea57600080fd5b5061079f60025481565b34801561120057600080fd5b5061079f60105481565b34801561121657600080fd5b5030610711565b34801561122957600080fd5b5061079f600e5481565b34801561123f57600080fd5b506106c461124e36600461416f565b6128a5565b34801561125f57600080fd5b506106c461126e36600461434a565b6128b2565b34801561127f57600080fd5b506106c461128e36600461434a565b6128ee565b34801561129f57600080fd5b5061079f7f000000000000000000000000000000000000000000000000000000000000000181565b3480156112d357600080fd5b506106946112e23660046145da565b600760209081526000928352604080842090915290825290205460ff1681565b34801561130e57600080fd5b5061079f61131d36600461416f565b612917565b34801561132e57600080fd5b50610e4561292e565b34801561134357600080fd5b506106c4611352366004614152565b61293b565b34801561136357600080fd5b506106c461137236600461416f565b6129c8565b34801561138357600080fd5b5061079f601e5481565b6018805461139a90614608565b80601f01602080910402602001604051908101604052809291908181526020018280546113c690614608565b80156114135780601f106113e857610100808354040283529160200191611413565b820191906000526020600020905b8154815290600101906020018083116113f657829003601f168201915b505050505081565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b03198316148061147e57507f80ac58cd000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b806114b257507f5b5e139f000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b806114e657507f7f5828d0000000000000000000000000000000000000000000000000000000006001600160e01b03198316145b92915050565b6114f46129d5565b6001600160a01b03811661151b5760405163d92e233d60e01b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6000805461139a90614608565b6115526129d5565b806002811115611564576115646144b7565b601b805460ff19166001836002811115611580576115806144b7565b0217905550601b546040517f92a17b827ee9d42ea9454bb4ca941a1800870e6d01c0842d09ba23ccc0190ee1916115bc9160ff909116906144cd565b60405180910390a150565b6115cf6129d5565b80516115e2906018906020840190614006565b5050565b816115f081612a2f565b6115fa8383612b1a565b505050565b600233321461162157604051637aafae9760e01b815260040160405180910390fd5b806002811115611633576116336144b7565b601b5460ff16600281111561164a5761164a6144b7565b1461166857604051633482502f60e01b815260040160405180910390fd5b61173383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050600c80549092506116b09150614608565b80601f01602080910402602001604051908101604052809291908181526020018280546116dc90614608565b80156117295780601f106116fe57610100808354040283529160200191611729565b820191906000526020600020905b81548152906001019060200180831161170c57829003601f168201915b5050505050612bb7565b61175057604051638baa579f60e01b815260040160405180910390fd5b6010548461175c61191e565b6117669190614658565b111561179e576040517f31b52d7300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254336000908152600460205260409020546117ca908690640100000000900463ffffffff16614658565b11156117e9576040516313f9b25d60e21b815260040160405180910390fd5b600e546117f69085614670565b341461182e576040517f99b5cb1d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254841115611851576040516313f9b25d60e21b815260040160405180910390fd5b61185b3385612c58565b60405184815233907f30385c845b448a36257a6a1716e6ad2e1bc2cbe333cde1e69fe849ad6511adfe9060200160405180910390a250505050565b601d5460ff166118b95760405163e0bc454160e01b815260040160405180910390fd5b6118c38282612ce7565b60005b818110156115fa5742601c60008585858181106118e5576118e561468f565b905060200201358152602001908152602001600020819055508080611909906146a5565b9150506118c6565b600c805461139a90614608565b60007f000000000000000000000000000000000000000000000000000000000000000160025461194e91906146be565b905090565b61195b6129d5565b601e55565b826001600160a01b038116331461197a5761197a33612a2f565b611985848484612d7c565b50505050565b6119936129d5565b80516115e29060209081840190614006565b601d5460ff166119c85760405163e0bc454160e01b815260040160405180910390fd5b6009546001600160a01b03166119f15760405163d92e233d60e01b815260040160405180910390fd5b601154816119fd61191e565b611a079190614658565b1115611a3f576040517f52df9fe500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254811115611a7b576040517fd887771b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600954600f546001600160a01b03909116906379cc6790903390611aa0908590614670565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b158015611ae657600080fd5b505af1158015611afa573d6000803e3d6000fd5b50505050611b083382612c58565b60405181815233907fb4cebbef2afa97d0409f298c34cebfd89b8d996d75659932858959611ae7d0619060200160405180910390a250565b600080825b856001600160a01b0316611b70868685818110611b6457611b6461468f565b90506020020135612011565b6001600160a01b031614611b8957600092505050611b9d565b808260010192508210611b45576001925050505b9392505050565b60025460009081907f0000000000000000000000000000000000000000000000000000000000000001905b80821015611c3857846001600160a01b0316611bea836120dc565b6001600160a01b031614158015611c1a5750846001600160a01b0316611c0f83612011565b6001600160a01b0316145b15611c2d5782611c29816146a5565b9350505b816001019150611bcf565b50909392505050565b611c496129d5565b6001600160a01b038116611c705760405163d92e233d60e01b815260040160405180910390fd5b602180546001600160a01b0319166001600160a01b0392909216919091179055565b611c9a6129d5565b6021546040516000916001600160a01b03169047908381818185875af1925050503d8060008114611ce7576040519150601f19603f3d011682016040523d82523d6000602084013e611cec565b606091505b5050905080611d425760405162461bcd60e51b815260206004820152601060248201527f5472616e73666572206661696c65642e0000000000000000000000000000000060448201526064015b60405180910390fd5b50565b60006114e663ffffffff8316600a614670565b826001600160a01b0381163314611d7257611d7233612a2f565b611985848484612e03565b60606000611da6836001600160a01b031660009081526004602052604090205463ffffffff1690565b905060008167ffffffffffffffff811115611dc357611dc3614188565b604051908082528060200260200182016040528015611dec578160200160208202803683370190505b50905060007f00000000000000000000000000000000000000000000000000000000000000015b83821015611e6f57856001600160a01b0316611e2e826120dc565b6001600160a01b031603611e6757808383611e48816146a5565b945081518110611e5a57611e5a61468f565b6020026020010181815250505b600101611e13565b5090949350505050565b6000611e8482611ba4565b6001600160a01b03831660009081526004602052604090205463ffffffff166114e69190614658565b611eb56129d5565b601d8054911515620100000262ff000019909216919091179055565b611ed96129d5565b80516115e290601f906020840190614006565b60606000611ef983611ba4565b905060008167ffffffffffffffff811115611f1657611f16614188565b604051908082528060200260200182016040528015611f3f578160200160208202803683370190505b50905060007f00000000000000000000000000000000000000000000000000000000000000015b83821015611e6f57856001600160a01b0316611f81826120dc565b6001600160a01b031614158015611fb15750856001600160a01b0316611fa682612011565b6001600160a01b0316145b15611fe157808383611fc2816146a5565b945081518110611fd457611fd461468f565b6020026020010181815250505b600101611f66565b611ff16129d5565b80516115e290600c906020840190614006565b61200c6129d5565b600e55565b600061201c82612649565b5192915050565b601654156120445760405163a741a04560e01b815260040160405180910390fd5b601454604080514260208201529081018590524460608083019190915241901b6bffffffffffffffffffffffff19166080820152456094820152434060b482015260d4810184905260f48101839052610114016040516020818303038152906040528051906020012060001c6120ba91906146eb565b601681905515806120cd57506016546001145b156115fa576002601655505050565b6000806120e883612649565b9050806040015163ffffffff1660001461201c5730611b9d565b61210a6129d5565b600f55565b6121176129d5565b601d80549115156101000261ff0019909216919091179055565b6121396129d5565b601255565b6121466129d5565b601055565b6121536129d5565b61215d6000612e1e565b565b600954600a54604051631b8e0c3560e21b815260048101919091526000916001600160a01b03169082908290636e3830d490602401602060405180830381865afa1580156121b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d591906146ff565b905060006121e542601e54612e70565b6000868152601c602052604081205491925090839061220490846146be565b61220e9190614670565b9695505050505050565b6122206129d5565b80516115e290600d906020840190614006565b6060600082818167ffffffffffffffff81111561225257612252614188565b60405190808252806020026020018201604052801561227b578160200160208202803683370190505b5090505b818310156122d1576122a886868581811061229c5761229c61468f565b90506020020135612839565b8184815181106122ba576122ba61468f565b60200260200101818152505082600101925061227f565b95945050505050565b600d805461139a90614608565b60006114e6600a83614718565b6122fc6129d5565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6123266129d5565b601355565b6001805461139a90614608565b60006114e661234683612649565b60600151611d45565b600133321461237157604051637aafae9760e01b815260040160405180910390fd5b806002811115612383576123836144b7565b601b5460ff16600281111561239a5761239a6144b7565b146123b857604051633482502f60e01b815260040160405180910390fd5b61240083838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050600d80549092506116b09150614608565b61241d57604051638baa579f60e01b815260040160405180910390fd5b60135433600090815260046020526040902054612449908690640100000000900463ffffffff16614658565b1115611851576040516313f9b25d60e21b815260040160405180910390fd5b60006114e661247683612649565b60400151611d45565b601954156124a05760405163a741a04560e01b815260040160405180910390fd5b601754604080516020810186905242918101919091524460608083019190915241901b6bffffffffffffffffffffffff1916608082015245609482015260b48101849052434060d482015260f48101839052610114016040516020818303038152906040528051906020012060001c61251991906146eb565b6019819055158061252c57506019546001145b156115fa576002601955505050565b6125436129d5565b80516115e290601a906020840190614006565b8161256081612a2f565b6115fa8383612e86565b6125726129d5565b80516115e2906015906020840190614006565b61258d6129d5565b600a55565b600080825b856001600160a01b03166125c28686858181106125b6576125b661468f565b905060200201356120dc565b6001600160a01b0316146125db57600092505050611b9d565b8082600101925082106125975750600195945050505050565b6125fc6129d5565b601155565b6126096129d5565b601d805460ff1916911515919091179055565b836001600160a01b03811633146126365761263633612a2f565b61264285858585612e91565b5050505050565b6040805160808101825260008082526020820181905291810182905260608101919091527f00000000000000000000000000000000000000000000000000000000000000018210156126dd5760405162461bcd60e51b815260206004820152601a60248201527f546f6b656e49642062656c6f77207374617274696e67204964210000000000006044820152606401611d39565b6000828152600360205260409020546001600160a01b031615158061270457506002548210155b156127685750600090815260036020908152604091829020825160808101845290546001600160a01b038116825263ffffffff600160a01b8204811693830193909352600160c01b8104831693820193909352600160e01b90920416606082015290565b815b6000818152600560205260409020546001600160a01b031661278f576000190161276a565b600090815260056020908152604091829020825160808101845290546001600160a01b038116825263ffffffff600160a01b8204811693830193909352600160c01b8104831693820193909352600160e01b90920416606082015292915050565b6060601f6127fd83613027565b6020604051602001612811939291906147c5565b6040516020818303038152906040529050919050565b61282f6129d5565b6115e28282612c58565b60008061284583612649565b905060006128568260600151611d45565b9050600080836040015163ffffffff161161287257600061288c565b61288c836040015161288261292e565b610a0791906147f8565b90506122d18183614658565b6015805461139a90614608565b6128ad6129d5565b601755565b601d54610100900460ff166128da5760405163e0bc454160e01b815260040160405180910390fd5b6128e48282613165565b6115e282826131fa565b601d5462010000900460ff166128e45760405163e0bc454160e01b815260040160405180910390fd5b60006114e661292583612649565b60200151611d45565b600061194e600a42614718565b6129436129d5565b6001600160a01b0381166129bf5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401611d39565b611d4281612e1e565b6129d06129d5565b601455565b6008546001600160a01b0316331461215d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611d39565b6daaeb6d7670e522a718067333cd4e3b15611d42576040517fc61711340000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03821660248201526daaeb6d7670e522a718067333cd4e9063c617113490604401602060405180830381865afa158015612ab5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad9919061481d565b611d42576040517fede71dcc0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611d39565b6000612b25826120dc565b90506001600160a01b038116331480612b6157506001600160a01b038116600090815260076020908152604080832033845290915290205460ff165b612bad5760405162461bcd60e51b815260206004820152601f60248201527f455243373231473a20617070726f7665206e6f7420617574686f72697a6564006044820152606401611d39565b6115fa8383613451565b6000612c40833384604051602001612bd092919061483a565b604051602081830303815290604052612be890614872565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604051602081830303815290604052805190602001206134bf90919063ffffffff16565b600b546001600160a01b039182169116149392505050565b805b7f0000000000000000000000000000000000000000000000000000000000000064811115612cdd57612cac7f0000000000000000000000000000000000000000000000000000000000000064826146be565b9050612cd8837f00000000000000000000000000000000000000000000000000000000000000646134e3565b612c5a565b6115fa83826134e3565b6000815b80821015611985576000612d16858585818110612d0a57612d0a61468f565b905060200201356136d9565b9050336001600160a01b03821614612d705760405162461bcd60e51b815260206004820152601660248201527f596f7520617265206e6f7420746865206f776e657221000000000000000000006044820152606401611d39565b82600101925050612ceb565b612d8633826136e5565b612df85760405162461bcd60e51b815260206004820152602260248201527f455243373231473a207472616e7366657246726f6d20756e617574686f72697a60448201527f65640000000000000000000000000000000000000000000000000000000000006064820152608401611d39565b6115fa838383613763565b6115fa8383836040518060200160405280600081525061261c565b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000818310612e7f5781611b9d565b5090919050565b6115e233838361390e565b612e9c848484611960565b6001600160a01b0383163b15611985576000836001600160a01b031663150b7a0233878686604051602401612ed49493929190614896565b6040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051612f2291906148c8565b6000604051808303816000865af19150503d8060008114612f5f576040519150601f19603f3d011682016040523d82523d6000602084013e612f64565b606091505b50915050600081806020019051810190612f7e91906148e4565b90507f150b7a02000000000000000000000000000000000000000000000000000000006001600160e01b031982161461301f5760405162461bcd60e51b815260206004820152603360248201527f455243373231473a20736166655472616e7366657246726f6d20746f5f206e6f60448201527f6e2d45524337323152656365697661626c6521000000000000000000000000006064820152608401611d39565b505050505050565b60608160000361306a57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115613094578061307e816146a5565b915061308d9050600a83614718565b915061306e565b60008167ffffffffffffffff8111156130af576130af614188565b6040519080825280601f01601f1916602001820160405280156130d9576020820181803683370190505b5090505b841561315d57816130ed81614901565b92506130fc9050600a866146eb565b613107906030614658565b60f81b81838151811061311c5761311c61468f565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613156600a86614718565b94506130dd565b949350505050565b6000815b808210156119855760006131948585858181106131885761318861468f565b9050602002013561397b565b9050336001600160a01b038216146131ee5760405162461bcd60e51b815260206004820152601660248201527f596f7520617265206e6f7420746865206f776e657221000000000000000000006044820152606401611d39565b82600101925050613169565b601e54600003613236576040517f441dfbd600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156132a95733613257848484818110611b6457611b6461468f565b6001600160a01b031614613297576040517f30cd747100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806132a1816146a5565b915050613239565b50600954600a54604051631b8e0c3560e21b81526001600160a01b03909216916000918391636e3830d4916132e49160040190815260200190565b602060405180830381865afa158015613301573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332591906146ff565b9050600061333542601e54612e70565b905060005b8481101561301f57600083601c600089898681811061335b5761335b61468f565b905060200201358152602001908152602001600020548461337c91906146be565b6133869190614670565b600a546040517f9d9df5690000000000000000000000000000000000000000000000000000000081526004810191909152336024820152604481018290529091506001600160a01b03861690639d9df56990606401600060405180830381600087803b1580156133f557600080fd5b505af1158015613409573d6000803e3d6000fd5b5050505042601c60008989868181106134245761342461468f565b90506020020135815260200190815260200160002081905550508080613449906146a5565b91505061333a565b600081815260066020526040902080546001600160a01b0319166001600160a01b0384169081179091558190613486826120dc565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008060006134ce8585613988565b915091506134db816139cd565b509392505050565b6001600160a01b0382166135395760405162461bcd60e51b815260206004820152601d60248201527f455243373231473a205f6d696e74496e7465726e616c20746f203078300000006044820152606401611d39565b7f00000000000000000000000000000000000000000000000000000000000000648111156135cf5760405162461bcd60e51b815260206004820152602860248201527f455243373231473a205f6d696e74496e7465726e616c206f766572206d61784260448201527f6174636853697a650000000000000000000000000000000000000000000000006064820152608401611d39565b60025460006135de8383614658565b600083815260056020526040902080546001600160a01b0319166001600160a01b038716179055905061360f61292e565b6000838152600560209081526040808320805463ffffffff60a01b1916600160a01b63ffffffff968716021790556001600160a01b038816835260049091529020805467ffffffffffffffff1981168184168701841690811764010000000063ffffffff1990931690911782900484168701909316029190911790555b60405182906001600160a01b038616906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a480826001019250821061368c57600255505050565b60006114e68242613b32565b6000806136f1836120dc565b9050836001600160a01b0316816001600160a01b0316148061372c57506000838152600660205260409020546001600160a01b038581169116145b8061315d57506001600160a01b0380821660009081526007602090815260408083209388168352929052205460ff16949350505050565b61376c816120dc565b6001600160a01b0316836001600160a01b0316146137cc5760405162461bcd60e51b815260206004820152601d60248201527f455243373231473a205f7472616e7366657220213d206f776e65724f660000006044820152606401611d39565b6001600160a01b0382166138225760405162461bcd60e51b815260206004820152601960248201527f455243373231473a205f7472616e7366657220746f20307830000000000000006044820152606401611d39565b600081815260066020908152604080832080546001600160a01b0319908116909155600390925290912080549091166001600160a01b03841617905561386661292e565b6000828152600360209081526040808320805463ffffffff958616600160a01b0263ffffffff60a01b199091161790556001600160a01b038088168085526004909352818420805460001981881601871663ffffffff1991821617909155908716808552828520805480881660010190971696909216959095179055518493927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6001600160a01b03838116600081815260076020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60006114e6826000613b32565b60008082516041036139be5760208301516040840151606085015160001a6139b287828585613e65565b945094505050506139c6565b506000905060025b9250929050565b60008160048111156139e1576139e16144b7565b036139e95750565b60018160048111156139fd576139fd6144b7565b03613a4a5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401611d39565b6002816004811115613a5e57613a5e6144b7565b03613aab5760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401611d39565b6003816004811115613abf57613abf6144b7565b03611d425760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401611d39565b600080613b3e84612649565b8051604082015191925090613b538684613f29565b600086815260066020526040902080546001600160a01b03191690558415613c705763ffffffff811615613bef5760405162461bcd60e51b815260206004820152602c60248201527f455243373231473a205f7365745374616b6554696d657374616d70282920616c60448201527f7265616479207374616b656400000000000000000000000000000000000000006064820152608401611d39565b6001600160a01b038216600081815260046020526040808220805463ffffffff1980821663ffffffff9283166000190183161790925530808552838520805480841660010190931692909316919091179091559051899391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4613e09565b8063ffffffff16600003613cec5760405162461bcd60e51b815260206004820152602e60248201527f455243373231473a205f7365745374616b6554696d657374616d70282920616c60448201527f726561647920756e7374616b65640000000000000000000000000000000000006064820152608401611d39565b6001600160a01b03821660009081526004602081905260408220805463ffffffff8082166001011663ffffffff1990911617905590613d283090565b6001600160a01b0316815260208101919091526040016000908120805463ffffffff19811663ffffffff9182166000190190911617905581613d6861292e565b613d7291906147f8565b600088815260036020526040902080549192508291601c90613da2908490600160e01b900463ffffffff16614918565b92506101000a81548163ffffffff021916908363ffffffff16021790555086836001600160a01b0316613dd23090565b6001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505b613e12856122e7565b6000878152600360205260409020805463ffffffff92909216600160c01b027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555091505092915050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613e9c5750600090506003613f20565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613ef0573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613f1957600060019250925050613f20565b9150600090505b94509492505050565b6000828152600360205260409020546001600160a01b03166115e257600082815260036020908152604091829020835181549285015193850151606086015163ffffffff908116600160e01b027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff928216600160c01b029290921677ffffffffffffffffffffffffffffffffffffffffffffffff91909616600160a01b027fffffffffffffffff0000000000000000000000000000000000000000000000009095166001600160a01b03909316929092179390931716929092171790555050565b82805461401290614608565b90600052602060002090601f016020900481019282614034576000855561407a565b82601f1061404d57805160ff191683800117855561407a565b8280016001018555821561407a579182015b8281111561407a57825182559160200191906001019061405f565b5061408692915061408a565b5090565b5b80821115614086576000815560010161408b565b60005b838110156140ba5781810151838201526020016140a2565b838111156119855750506000910152565b600081518084526140e381602086016020860161409f565b601f01601f19169290920160200192915050565b602081526000611b9d60208301846140cb565b6001600160e01b031981168114611d4257600080fd5b60006020828403121561413257600080fd5b8135611b9d8161410a565b6001600160a01b0381168114611d4257600080fd5b60006020828403121561416457600080fd5b8135611b9d8161413d565b60006020828403121561418157600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff808411156141b9576141b9614188565b604051601f8501601f19908116603f011681019082821181831017156141e1576141e1614188565b816040528093508581528686860111156141fa57600080fd5b858560208301376000602087830101525050509392505050565b60006020828403121561422657600080fd5b813567ffffffffffffffff81111561423d57600080fd5b8201601f8101841361424e57600080fd5b61315d8482356020840161419e565b6000806040838503121561427057600080fd5b823561427b8161413d565b946020939093013593505050565b60008060006040848603121561429e57600080fd5b83359250602084013567ffffffffffffffff808211156142bd57600080fd5b818601915086601f8301126142d157600080fd5b8135818111156142e057600080fd5b8760208285010111156142f257600080fd5b6020830194508093505050509250925092565b60008083601f84011261431757600080fd5b50813567ffffffffffffffff81111561432f57600080fd5b6020830191508360208260051b85010111156139c657600080fd5b6000806020838503121561435d57600080fd5b823567ffffffffffffffff81111561437457600080fd5b61438085828601614305565b90969095509350505050565b6000806000606084860312156143a157600080fd5b83356143ac8161413d565b925060208401356143bc8161413d565b929592945050506040919091013590565b6000806000604084860312156143e257600080fd5b83356143ed8161413d565b9250602084013567ffffffffffffffff81111561440957600080fd5b61441586828701614305565b9497909650939450505050565b60006020828403121561443457600080fd5b813563ffffffff81168114611b9d57600080fd5b6020808252825182820181905260009190848201906040850190845b8181101561448057835183529284019291840191600101614464565b50909695505050505050565b8015158114611d4257600080fd5b6000602082840312156144ac57600080fd5b8135611b9d8161448c565b634e487b7160e01b600052602160045260246000fd5b60208101600383106144ef57634e487b7160e01b600052602160045260246000fd5b91905290565b60008060006060848603121561450a57600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561453457600080fd5b823561453f8161413d565b9150602083013561454f8161448c565b809150509250929050565b6000806000806080858703121561457057600080fd5b843561457b8161413d565b9350602085013561458b8161413d565b925060408501359150606085013567ffffffffffffffff8111156145ae57600080fd5b8501601f810187136145bf57600080fd5b6145ce8782356020840161419e565b91505092959194509250565b600080604083850312156145ed57600080fd5b82356145f88161413d565b9150602083013561454f8161413d565b600181811c9082168061461c57607f821691505b60208210810361463c57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561466b5761466b614642565b500190565b600081600019048311821515161561468a5761468a614642565b500290565b634e487b7160e01b600052603260045260246000fd5b6000600182016146b7576146b7614642565b5060010190565b6000828210156146d0576146d0614642565b500390565b634e487b7160e01b600052601260045260246000fd5b6000826146fa576146fa6146d5565b500690565b60006020828403121561471157600080fd5b5051919050565b600082614727576147276146d5565b500490565b8054600090600181811c908083168061474657607f831692505b6020808410820361476757634e487b7160e01b600052602260045260246000fd5b81801561477b576001811461478c576147b9565b60ff198616895284890196506147b9565b60008881526020902060005b868110156147b15781548b820152908501908301614798565b505084890196505b50505050505092915050565b60006147d1828661472c565b84516147e181836020890161409f565b6147ed8183018661472c565b979650505050505050565b600063ffffffff8381169083168181101561481557614815614642565b039392505050565b60006020828403121561482f57600080fd5b8151611b9d8161448c565b6bffffffffffffffffffffffff198360601b1681526000825161486481601485016020870161409f565b919091016014019392505050565b8051602080830151919081101561463c5760001960209190910360031b1b16919050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261220e60808301846140cb565b600082516148da81846020870161409f565b9190910192915050565b6000602082840312156148f657600080fd5b8151611b9d8161410a565b60008161491057614910614642565b506000190190565b600063ffffffff80831681851680830382111561493757614937614642565b0194935050505056fea26469706673582212203cef86a5027532037ec9e80198eb68352ab1dc113263f6fcfb1df42f66b36b2f64736f6c634300080d0033

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

00000000000000000000000060ee5aaa2ef54bef9e85d4a28a26e51af7bb7194000000000000000000000000aa1db62de542929f30a47d42231ef8a8500bf6dd000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000003068747470733a2f2f616e6772797468726561646e66742e73332e616d617a6f6e6177732e636f6d2f73746167655f312f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042697066733a2f2f6261666b726569667963787579636b6a6d6a787268737877626f736c69776d7062666c69746e746e3273716d6179746466783271796f3435693661000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : signer_ (address): 0x60ee5aaA2EF54BeF9E85d4a28a26e51af7BB7194
Arg [1] : deployerAddress_ (address): 0xAA1db62De542929F30A47D42231ef8A8500Bf6Dd
Arg [2] : unrevealURI_ (string): https://angrythreadnft.s3.amazonaws.com/stage_1/
Arg [3] : contractURI_ (string): ipfs://bafkreifycxuyckjmjxrhsxwbosliwmpbflitntn2sqmaytdfx2qyo45i6a

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 00000000000000000000000060ee5aaa2ef54bef9e85d4a28a26e51af7bb7194
Arg [1] : 000000000000000000000000aa1db62de542929f30a47d42231ef8a8500bf6dd
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [3] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000030
Arg [5] : 68747470733a2f2f616e6772797468726561646e66742e73332e616d617a6f6e
Arg [6] : 6177732e636f6d2f73746167655f312f00000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000042
Arg [8] : 697066733a2f2f6261666b726569667963787579636b6a6d6a78726873787762
Arg [9] : 6f736c69776d7062666c69746e746e3273716d6179746466783271796f343569
Arg [10] : 3661000000000000000000000000000000000000000000000000000000000000


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.