ETH Price: $3,591.62 (+3.60%)
 

Overview

Max Total Supply

1,626 OMFC

Holders

298

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
notarget.eth
Balance
1 OMFC
0x4228c5752654e4a4f8d281521521d3dde2b6d6e6
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:
AccessPassNFT

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 23 : AccessPassNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.8.6;

/**
* @title NFTs for the AccessPass to Metaframes Maradona Club
* @author MetaFrames
* @notice This NFT Contract follows the ERC721 Standards and sets one of its properties (tier), on chain.
* The three tiers are as follows: GOLD, SILVER, BRONZE. This contract is also connected to Metaframes' TicketNFT
* which are used to join Metaframes' Ticket Competition for the World Cup Ticket.
* @dev The flow of this contract is as follows:
*    Deployment: Contract is deployed and configured
*    -----------------------------------------------
*    Additional Configuration
*     -setWhitelistSigner()
*     -setPrivateMintingTimestamp() if privateMintingTimestamp is 0
*    -----------------------------------------------
*    Private Minting: Allows accounts in the mint whitelist to mint
*    -----------------------------------------------
*    Public Minting: Allows all accounts to mint
*     -setPublicMintingTimestamp() if publicMintingTimestamp is 0
*    -----------------------------------------------
*    Reveal: Revealing the tiers
*     -randomizeTiers()
*     -nftTiers() then builds the final token metadata
*    -----------------------------------------------
*    Airdrop: Minting TicketNFTs to 500 Random Users
*     -randomizeTickets()
*     -winners() then builds the 500 random users
*     NOTE: the actual minting will happen in the TicketNFT contract
*/

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./WhitelistVerifier.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "./TicketNFT.sol";
import "./interfaces/IAccessPassNFT.sol";
import "./interfaces/ITicketNFT.sol";

contract AccessPassNFT is Ownable, WhitelistVerifier, ERC721Royalty, VRFConsumerBaseV2, IAccessPassNFT {
    using Counters for Counters.Counter;
    using Strings for uint256;

    /**
    * @dev maxTotalSupply is the amount of NFTs that can be minted
    */
    uint16 public immutable maxTotalSupply;

    /**
    * @dev goldenTierSupply is the amount of GOLD NFTs
    */
    uint16 public immutable goldenTierSupply;

    /**
    * @dev silverTierSupply is the amount of SILVER NFTs
    */
    uint16 public immutable silverTierSupply;

    /**
    * @dev ticketSupply is the amount of TicketNFTs to be airdropped
    */
    uint16 public immutable ticketSupply;

    /**
    * @dev Mapping minter address to amount minted
    */
    struct Minted {
        uint256 publicMinted;
        uint256 privateMinted;
    }
    mapping(address => Minted) private minted;

    /**
    * @dev Keeps track of how many NFTs have been minted
    */
    Counters.Counter public tokenIdCounter;

    /**
    * @dev privateMintingTimestamp sets when privateMinting is enabled. When this is 0,
    * it means all minting is disabled
    */
    uint256 public privateMintingTimestamp;

    /**
    * @dev publicMintingTimestamp sets when publicMinting is enabled. When this is 0, it means
    * public minting is disabled. This value must be greater than the privateMintingTimestamp if this is not 0
    */
    uint256 public publicMintingTimestamp;

    /**
    * @dev price specifies how much eth an account pays for a mint. This is in wei
    */
    uint256 public price;

    /**
    * @dev maxPublicMintable is the maximum an account can publicMint
    */
    uint16 public maxPublicMintable;

    /**
    * @dev flag that tells if the final uri has been set
    */
    bool public tiersRevealed;

    /**
    * @dev unrevealedURI is the placeholder token metadata when the reveal has not happened yet
    */
    string unrevealedURI;

    /**
    * @dev baseURI is the base of the real token metadata after the reveal
    */
    string baseURI;

    /**
    * @dev contractURI is an OpenSea standard. This should point to a metadata that tells who will
    * receive revenues from OpensSea. See https://docs.opensea.io/docs/contract-level-metadata
    */
    string public contractURI;

    /**
    * @dev receives the eth from accounts private and public minting and the royalties from selling the token.
    * All revenues should be sent to this address
    */
    address payable public treasury;

    /**
    * @dev ticketNFT decides the trade freeze when the winners have been selected
    */
    TicketNFT public ticketNFT;

    /**
    * @dev The following variables are needed to request a random value from Chainlink
    * see https://docs.chain.link/docs/vrf-contracts/
    */
    address public chainlinkCoordinator;  // Chainlink coordinator address
    uint256 public tiersRequestId;        // Chainlink request id for tier randomization
    uint256 public tiersRandomWord;       // Random value received from Chainlink VRF
    uint256 public ticketsRequestId;      // Chainlink request id for ticket randomization
    uint256 public ticketsRandomWord;     // Random value received from Chainlink VRF

    /**
    * @notice initializes the contract
    * @param treasury_ is the recipient of eth from private and public minting as well as the recipient for token selling fees
    * @param vrfCoordinator_ is the address of the VRF Contract for generating random number
    * @param maxTotalSupply_ is the max number of tokens that can be minted
    * @param goldenTierSupply_ is the max number of golden tiered tokens
    * @param silverTierSupply_ is the max number of silver tiered tokens
    * @param ticketSupply_ is the max number of tickets that will be airdropped
    * @param privateMintingTimestamp_ is when the private minting will be enabled. NOTE: this could also be set later. 0 is an acceptable value
    * @param royaltyFee is the fees taken from second-hand selling. This is expressed in _royaltyFee/10_000.
    * So to do 5% means supplying 500 since 500/10_000 is 5% (see ERC2981 function _setDefaultRoyalty(address receiver, uint96 feeNumerator))
    * @param price_ is the price of a public or private mint in wei
    * @param contractURI_ is an OpenSeas standard and is necessary for getting revenues from OpenSeas
    * @param unrevealedURI_ is the token metadata placeholder while the reveal has not happened yet.
    */
    constructor(
        address payable treasury_,
        address vrfCoordinator_,

        uint16 maxTotalSupply_,
        uint16 goldenTierSupply_,
        uint16 silverTierSupply_,
        uint16 ticketSupply_,

        uint256 privateMintingTimestamp_,

        uint96 royaltyFee,
        uint256 price_,

        string memory contractURI_,
        string memory unrevealedURI_
    )   ERC721("Maradona Official Access Pass", "OMFC")
        WhitelistVerifier()
        VRFConsumerBaseV2(vrfCoordinator_) {

        if (treasury_ == address(0)) revert ZeroAddress("treasury");
        treasury = treasury_;

        if (vrfCoordinator_ == address(0)) revert ZeroAddress("vrfCoordinator");
        chainlinkCoordinator = vrfCoordinator_;

        if (maxTotalSupply_ == 0) revert IsZero("maxTotalSupply");
        maxTotalSupply = maxTotalSupply_;

        // The following is to ensure that there will be bronzeTierSupply
        require(
            goldenTierSupply_ + silverTierSupply_ < maxTotalSupply_,
                "Tier Supplies must be less than maxTotalSupply"
        );
        if (goldenTierSupply_ == 0) revert IsZero("goldenTierSupply");
        goldenTierSupply = goldenTierSupply_;

        if (silverTierSupply_ == 0) revert IsZero("silverTierSupply");
        silverTierSupply = silverTierSupply_;

        if (ticketSupply_ > maxTotalSupply_) revert IncorrectValue("ticketSupply");
        ticketSupply = ticketSupply_;

        // not checking for zero on purpose here
        privateMintingTimestamp = privateMintingTimestamp_;

        if (royaltyFee == 0) revert IsZero("royaltyFee");
        _setDefaultRoyalty(treasury_, royaltyFee);

        if (price_ == 0) revert IsZero("price");
        price = price_;

        bytes memory bytesUnrevealedURI = bytes(unrevealedURI_);
        if (bytesUnrevealedURI[bytesUnrevealedURI.length - 1] != bytes("/")[0]) revert IncorrectValue("unrevealedURI");
        unrevealedURI = unrevealedURI_;

        if (bytes(contractURI_).length == 0) revert EmptyString("contractURI");
        contractURI = contractURI_;

        maxPublicMintable = 10;

        // mint one to deployer so the OpenSeas store front can be edited before private minting starts
        uint256 tokenId = tokenIdCounter.current();
        _safeMint(msg.sender, tokenId);
        tokenIdCounter.increment();

        // classifying this mint as a private mint
        minted[msg.sender].privateMinted += 1;
    }

    /********************** EXTERNAL ********************************/

    /**
    * @inheritdoc IAccessPassNFT
    */
    function privateMint(
        VerifiedSlot calldata verifiedSlot
    ) external
        override
        payable
        onlyDuring(ContractStatus.PRIVATE_MINTING)
    {
        validateVerifiedSlot(msg.sender, minted[msg.sender].privateMinted, verifiedSlot);
        internalMint(msg.sender, msg.value, MintingType.PRIVATE_MINT);
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function publicMint() external override payable onlyDuring(ContractStatus.PUBLIC_MINTING) {
        if (minted[msg.sender].publicMinted >= maxPublicMintable) revert ExceedMintingCapacity(minted[msg.sender].publicMinted);
        internalMint(msg.sender, msg.value, MintingType.PUBLIC_MINT);
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function randomizeTiers(
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit
    ) external
        override
        onlyOwner
        onlyOnOrAfter(ContractStatus.END_MINTING)
    {
        /// Only allow randomize if random word has not been set
        if (tiersRandomWord != 0) revert CanNoLongerCall();

        // making sure that the request has enough callbackGasLimit to execute
        if (callbackGasLimit < 40_000) revert IncorrectValue("callbackGasLimit");

        /// Call Chainlink to receive a random word
        /// Will revert if subscription is not funded.
        VRFCoordinatorV2Interface coordinator = VRFCoordinatorV2Interface(chainlinkCoordinator);
        /// Now Chainlink will call us back in a future transaction, see function fulfillRandomWords

        tiersRequestId = coordinator.requestRandomWords(
            gasLane,
            subscriptionId,
            3, /// Request confirmations
            callbackGasLimit,
            1 /// request 1 random number
        );

        emit TiersRandomWordRequested(tiersRequestId);
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function revealTiers(
        string memory revealedURI
    ) external
        override
        onlyOwner
        onlyOnOrAfter(ContractStatus.TIERS_RANDOMIZED)
    {
        if (tiersRevealed) revert CallingMoreThanOnce();
        bytes memory bytesRevealedURI = bytes(revealedURI);
        if (bytesRevealedURI[bytesRevealedURI.length - 1] != bytes("/")[0]) revert IncorrectValue("revealedURI");
        baseURI = revealedURI;
        tiersRevealed = true;

        emit TiersRevealed();
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function randomizeTickets(
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit
    ) external
        override
        onlyOwner
        onlyOnOrAfter(ContractStatus.END_MINTING)
    {
        // Only allow randomize if random word has not been set
        if (ticketsRandomWord != 0) revert CanNoLongerCall();

        // making sure that the request has enough callbackGasLimit to execute
        if (callbackGasLimit < 40_000) revert IncorrectValue("callbackGasLimit");

        /// Call Chainlink to receive a random word
        /// Will revert if subscription is not funded.
        VRFCoordinatorV2Interface coordinator = VRFCoordinatorV2Interface(chainlinkCoordinator);
        ticketsRequestId = coordinator.requestRandomWords(
            gasLane,
            subscriptionId,
            3, /// Request confirmations
            callbackGasLimit,
            1 /// request 1 random number
        );

        emit TicketsRandomWordRequested(ticketsRequestId);
        /// Now Chainlink will call us back in a future transaction, see function fulfillRandomWords
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setWhitelistSigner(address whiteListSigner_) external override onlyOwner {
        _setWhiteListSigner(whiteListSigner_);
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setTicketNFT(TicketNFT ticketNFT_) external override onlyOwner() {
        bytes4 ticketNFTInterfaceId = type(ITicketNFT).interfaceId;
        if (!ticketNFT_.supportsInterface(ticketNFTInterfaceId)) revert IncorrectValue("ticketNFT_");

        // should not be able to setTicketNFT if ticketNFTs have been airdropped
        if (address(ticketNFT) != address(0)) {

            // contractStatus 2 means that the tickets have been airdropped so any status before that should be good
            if (uint(ticketNFT.contractStatus()) > 1) revert  CanNoLongerCall();
        }
        emit TicketNFTSet(ticketNFT, ticketNFT_);
        ticketNFT = ticketNFT_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setTreasury(address payable treasury_) external override onlyOwner() {
        if (treasury_ == address(0)) revert ZeroAddress("treasury");
        emit TreasurySet(treasury, treasury_);
        treasury = treasury_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setRoyaltyFee(uint96 royaltyFee) external override onlyOwner() {
        _setDefaultRoyalty(treasury, royaltyFee);

        emit RoyaltyFeesSet(royaltyFee);
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setPrice(uint256 price_) external override onlyOwner {
        if (price_ == 0) revert IsZero("price");
        emit PriceSet(price, price_);
        price = price_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setContractURI(string memory contractURI_) external override onlyOwner() {
        if (bytes(contractURI_).length == 0) revert EmptyString("contractURI");
        emit ContractURISet(contractURI, contractURI_);
        contractURI = contractURI_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setUnrevealedURI(string memory unrevealedURI_) external override onlyOwner {
        bytes memory bytesUnrevealedURI = bytes(unrevealedURI_);
        if (bytesUnrevealedURI[bytesUnrevealedURI.length - 1] != bytes("/")[0]) revert IncorrectValue("unrevealedURI");
        emit UnrevealedURISet(unrevealedURI, unrevealedURI_);
        unrevealedURI = unrevealedURI_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setPrivateMintingTimestamp(
        uint256 privateMintingTimestamp_
    ) external
        override
        onlyOwner
        onlyBefore(ContractStatus.PRIVATE_MINTING)
    {
        if (
            privateMintingTimestamp_ >= publicMintingTimestamp &&
            privateMintingTimestamp_ != 0 &&
            publicMintingTimestamp != 0
        ) revert IncorrectValue("privateMintingTimestamp");
        emit PrivateMintingTimestampSet(privateMintingTimestamp, privateMintingTimestamp_);
        privateMintingTimestamp = privateMintingTimestamp_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setPublicMintingTimestamp(
        uint256 publicMintingTimestamp_
    ) external
        override
        onlyOwner
        onlyBefore(ContractStatus.PUBLIC_MINTING)
    {
        if (
            publicMintingTimestamp_ < privateMintingTimestamp &&
            publicMintingTimestamp_ != 0
        ) revert IncorrectValue("publicMintingTimestamp");

        emit PublicMintingTimestampSet(publicMintingTimestamp, publicMintingTimestamp_);
        publicMintingTimestamp = publicMintingTimestamp_;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function setMaxPublicMintable(uint16 maxPublicMintable_) external override onlyOwner {
        if (maxPublicMintable_ == 0) revert IsZero("maxPublicMintable");
        emit MaxPublicMintableSet(maxPublicMintable, maxPublicMintable_);
        maxPublicMintable = maxPublicMintable_;
    }

    /********************** EXTERNAL VIEW ********************************/

    /**
    * @inheritdoc IAccessPassNFT
    */
    function mintedBy(address minter) external view override returns (uint256) {
        if(minter == address(0)) revert ZeroAddressQuery();
        return minted[minter].privateMinted + minted[minter].publicMinted;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function mintedBy(address minter, MintingType mintingType) external view override returns (uint256) {
        if(minter == address(0)) revert ZeroAddressQuery();
        if (mintingType == MintingType.PRIVATE_MINT) return minted[minter].privateMinted;
        else return minted[minter].publicMinted;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function nftTier(
        uint256 tokenId
    ) external
        view
        override
        onlyOnOrAfter(ContractStatus.TIERS_RANDOMIZED)
        returns (uint16 tier)
    {
        if (!_exists(tokenId)) revert NonExistentToken();
        return nftTiers()[tokenId];
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function ticketsRevealed() external view override returns(bool) {
        return ticketsRandomWord != 0;
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function winners() external view override onlyOnOrAfter(ContractStatus.TICKETS_RANDOMIZED) returns (uint16[] memory) {

        // Setup a pool with random values
        uint256 randomPoolSize = 100;
        uint256 batch = 0;
        uint16[] memory randomPool = randArray(ticketsRandomWord, randomPoolSize, batch++);

        /// Setup an array with nfts that will be returned
        uint16[] memory nfts = new uint16[](maxTotalSupply);
        uint256 counter;
        uint256 randomId;

        // Assign 500 winners
        for(uint256 i = 0; i < ticketSupply; i++) {
            randomId = randomPool[counter++];
            if (counter == randomPoolSize) {
                randomPool = randArray(ticketsRandomWord, randomPoolSize, batch++);
                counter = 0;
            }
            while(nfts[randomId] != 0) {
                randomId = randomPool[counter++];
                if (counter == randomPoolSize) {
                    randomPool = randArray(ticketsRandomWord, randomPoolSize, batch++);
                    counter = 0;
                }
            }
            nfts[randomId] = 1;     // Winner
        }

        return nfts;
    }

    /********************** PUBLIC ********************************/

    /**
    * @inheritdoc IAccessPassNFT
    */
    function totalSupply() public view override returns (uint256) {
        return tokenIdCounter.current();
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function contractStatus() public view override returns (ContractStatus) {
        if (ticketsRandomWord != 0) return ContractStatus.TICKETS_RANDOMIZED;
        if (tiersRevealed) return ContractStatus.TIERS_REVEALED;
        if (tiersRandomWord != 0) return ContractStatus.TIERS_RANDOMIZED;
        if (maxTotalSupply == tokenIdCounter.current()) return ContractStatus.END_MINTING;
        if (
            block.timestamp >= privateMintingTimestamp &&
            privateMintingTimestamp != 0 &&
            (
            block.timestamp < publicMintingTimestamp ||
            publicMintingTimestamp == 0
            )
        ) return ContractStatus.PRIVATE_MINTING;
        if (
            block.timestamp >= publicMintingTimestamp &&
            publicMintingTimestamp != 0 &&
            privateMintingTimestamp != 0
        ) return ContractStatus.PUBLIC_MINTING;
        return ContractStatus.NO_MINTING;
    }

    /**
    * @notice returns the unrevealed uri when the reveal hasn't happened yet and when it has, returns the real uri
    * @param tokenId should be a minted tokenId owned by an account
    */
    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        if (!_exists(tokenId)) revert NonExistentToken();

        if (!tiersRevealed) return string(abi.encodePacked(unrevealedURI, tokenId.toString(), ".json"));
        return string(abi.encodePacked(baseURI, tokenId.toString(), ".json"));
    }

    /**
    * @inheritdoc IAccessPassNFT
    */
    function nftTiers() public view override onlyOnOrAfter(ContractStatus.TIERS_RANDOMIZED) returns (uint16[] memory) {
        /// Setup a pool with random values
        uint256 randomPoolSize = 500;
        uint256 batch = 0;
        uint16[] memory randomPool = randArray(tiersRandomWord, randomPoolSize, batch++);

        /// Setup an array with nfts that will be returned
        uint16[] memory nfts = new uint16[](maxTotalSupply);
        uint256 counter;    /// Loop counter to check when we exhaust our random pool and need to fill it again
        uint256 randomId;   /// Random NFT id

        /// Assign goldenTierSupply golden tier nfts
        for(uint256 i = 0; i < goldenTierSupply; i++) {
            randomId = randomPool[counter++];
            if (counter == randomPoolSize) { /// If we exhaust the random pool, fill it again
                randomPool = randArray(tiersRandomWord, randomPoolSize, batch++);
                counter = 0;
            }
            while(nfts[randomId] != 0) { /// Loop while the NFT id already has a tier assigned
                randomId = randomPool[counter++]; /// If we exhaust the random pool, fill it again
                if (counter == randomPoolSize) {
                    randomPool = randArray(tiersRandomWord, randomPoolSize, batch++);
                    counter = 0;
                }
            }
            nfts[randomId] = uint16(Tier.GOLD);
        }

        // Assign silverTierSupply silver tier nfts
        for(uint256 i = 0; i < silverTierSupply; i++) {
            randomId = randomPool[counter++];
            if (counter == randomPoolSize) { /// If we exhaust the random pool, fill it again
                randomPool = randArray(tiersRandomWord, randomPoolSize, batch++);
                counter = 0;
            }
            while(nfts[randomId] != 0) { /// Loop while the NFT id already has a tier assigned
                randomId = randomPool[counter++];
                if (counter == randomPoolSize) { /// If we exhaust the random pool, fill it again
                    randomPool = randArray(tiersRandomWord, randomPoolSize, batch++);
                    counter = 0;
                }
            }
            nfts[randomId] = uint16(Tier.SILVER);
        }

        // All remaining nfts are automatically bronze because they are already set to 0
        return nfts;
    }

    /**
    * @inheritdoc IERC165
    */
    function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721Royalty, IERC165)
    returns (bool)
    {
        return
            interfaceId == type(IAccessPassNFT).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /********************** INTERNAL ********************************/

    /**
    * @notice check if the owner has a winning ticket
    * @inheritdoc ERC721
    */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override {

        if (address(ticketNFT) != address(0)) {
            uint256 frozenPeriod = ticketNFT.frozenPeriod();
            // not allowing winners to transfer if they only have one AccessPassNFT
            if (
                block.timestamp < frozenPeriod &&
                ticketNFT.isAccountWinner(from) &&
                balanceOf(from) == 1
            ) revert TransferringFrozenAccount(from, block.timestamp, frozenPeriod);
        }
    }

    /**
    * @notice pays treasury the amount
    * @param account is the account that paid
    * @param amount is how much the account has paid
    */
    function payTreasury(address account, uint256 amount) internal {
        (bool success, ) = treasury.call{value: amount}("");
        require (success, "Could not pay treasury");
        emit TreasuryPaid(account, amount);
    }

    /**
    * @notice internal mint function
    * @param to is the account receiving the NFT
    * @param amountPaid is the amount that the account has paid for the mint
    * @param mintingType could be PRIVATE_MINT or PUBLIC_MINT
    */
    function internalMint(
        address to,
        uint256 amountPaid,
        MintingType mintingType
    ) internal
        onlyBefore(ContractStatus.END_MINTING)
    {
        if (amountPaid != price) revert IncorrectValue("amountPaid");
        uint256 tokenId = tokenIdCounter.current();

        payTreasury(to, amountPaid);

        tokenIdCounter.increment();
        if (MintingType.PRIVATE_MINT == mintingType) {
            minted[to].privateMinted += 1;
        } else {
            minted[to].publicMinted += 1;
        }

        _safeMint(to, tokenId);
    }

    /**
    * @notice Chainlink calls us with a random value. (See VRFConsumerBaseV2's fulfillRandomWords function)
    * @dev Note that this happens in a later transaction than the request.
    * @param requestId is the id of the request from VRF's side
    * @param randomWords is an array of random numbers generated by VRF
    */
    function fulfillRandomWords(
        uint256 requestId,
        uint256[] memory randomWords
    ) internal override {
        if (requestId == 0) revert IsZero("requestId");
        if (requestId == tiersRequestId) {
            if (tiersRandomWord != 0) revert CallingMoreThanOnce();
            tiersRandomWord = randomWords[0]; /// Set the random value received from Chainlink
            emit TiersRandomized(tiersRandomWord);
        } else if (requestId == ticketsRequestId) {
            if (ticketsRandomWord != 0) revert CallingMoreThanOnce();
            ticketsRandomWord = randomWords[0]; /// Set the random value received from Chainlink
            emit TicketsRandomized(ticketsRandomWord);
        }
    }

    /**
    * @notice Returns a list of x random numbers, in increments of 16 numbers.
    * So you may receive x random numbers or up to 15 more. The random numbers are between 0 and 499
    * Each batch will be different, you can call multiple times with different batch numbers
    * This routine is deterministic and will always return the same result if randomWord is the same
    * @param randomWord can only be tiersRandomWord and ticketsRandomWord
    * @param max is the max numbers needed in a batch
    * @param batch represents the batch number
    */
    function randArray(uint256 randomWord, uint256 max, uint256 batch) internal view returns (uint16[] memory) {
        // First make sure the random chainlinkVRF value is initialized
        if (randomWord == 0) revert IsZero("randomWord");
        uint256 mask = 0xFFFF;   // 0xFFFF == [1111111111111111], masking the last 16 bits

        uint256 mainCounterMax = max / 16;
        if (max % 16 > 0) {
            mainCounterMax +=1;
        }
        uint256 batchOffset = (batch * mainCounterMax * 16);
        uint16[] memory randomValues = new uint16[](mainCounterMax * 16);
        for (uint256 mainCounter = 0; mainCounter < mainCounterMax; mainCounter++) {
            uint256 randomValue = uint256(keccak256(abi.encode(randomWord, mainCounter + batchOffset)));
            for (uint256 subCounter = 0; subCounter < 16; subCounter++) {
                randomValues[mainCounter * 16 + subCounter] = uint16(randomValue & mask) % maxTotalSupply;   // Mask 16 bits, value between 0 .. MAX_TOTAL_SUPPLY-1
                randomValue = randomValue / 2 ** 16;     // Right shift 16 bits into oblivion
            }
        }
        return randomValues;
    }

    /********************** MODIFIERS ********************************/

    /**
    * @notice functions like a less than to the supplied status
    * @param status is a ContractStatus in which the function must happen before in. For example:
    * setting the privateMintTimestamp should only happen before private minting starts to ensure that no one
    * messes with the privateMint settings during ContractStatus.PrivateMinting. To do that add this modifier
    * with the parameter: ContractStatus.PrivateMinting
    */
    modifier onlyBefore(ContractStatus status) {
        // asserting here because there should be no state before NO_MINTING
        assert(status != ContractStatus.NO_MINTING);
        ContractStatus lastStatus = ContractStatus(uint(status) - 1);
        if (contractStatus() >= status) revert IncorrectContractStatus(contractStatus(), lastStatus);
        _;
    }

    /**
    * @notice functions like a an equal to the supplied status
    * @param status is the ContractStatus it must be in
    */
    modifier onlyDuring(ContractStatus status) {
        if (contractStatus() != status) revert IncorrectContractStatus(contractStatus(), status);
        _;
    }

    /**
    * @notice functions like a greater than or equal to. The current status must be the same as or happened after the parameter.
    * @param status that the contract must at least be in. For example:
    * getting the nftTiers should only happen when TIERS_RANDOMIZED has already happened. so the parameter will be
    * TIERS_RANDOMIZED, because the function can only work once the status is TIERS_RANDOMIZED or has passed that
    */
    modifier onlyOnOrAfter(ContractStatus status) {
        if (contractStatus() < status) revert IncorrectContractStatus(contractStatus(), status);
        _;
    }
}

File 2 of 23 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        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 23 : 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 4 of 23 : WhitelistVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
* @title An abstract contract that checks if the verified slot is valid
* @author Oost & Voort, Inc
* @notice This contract is to be used in conjunction with the AccessPassNFT contract
*/

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./interfaces/IVerifiedSlot.sol";

abstract contract WhitelistVerifier is IVerifiedSlot {
    using ECDSA for bytes32;

    /**
    * @dev The following struct follows the EIP712 Standard
    */
    struct EIP712Domain {
        string name;
        string version;
        uint256 chainId;
        address verifyingContract;
    }

    /**
    * @dev The typehash for EIP712Domain
    */
    bytes32 constant EIP712DOMAIN_TYPEHASH = keccak256(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    );

    /**
    * @dev The typehash for the message being sent to the contract
    */
    bytes32 constant VERIFIED_SLOT_TYPEHASH =
        keccak256("VerifiedSlot(address minter,uint256 mintingCapacity)");

    /**
    * @dev The hashed Domain Message
    */
    bytes32 DOMAIN_SEPARATOR;

    /**
    * @dev the address of the whiteListSigner which is an EOA that signs a message that confirms who can mint how much
    */
    address public whiteListSigner;

    /**
    * @dev emitted when the whitelistSigner has been set
    * @param oldSigner represents the old signer for the Contract
    * @param newSigner represents the newly set signer for the Contract
    */
    event WhitelistSignerSet(address oldSigner, address newSigner);

    /**
    * @dev reverts with this message when the Zero Address is being used to set the Whitelist Signer
    */
    error WhitelistSignerIsZeroAddress();

    /**
    * @dev reverts with this message when the Caller of the mint is not the same as the one in the VerifiedSLot
    * @param caller is the account that called for the mint
    * @param minter is the address specified in the VerifiedSlot
    */
    error CallerIsNotMinter(address caller, address minter);

    /**
    * @dev reverts with this message when the message is not correct or if it is not signed by the WhitelistSigner
    * @param unknownSigner is the signer that signed the message
    * @param whitelistSigner is the signer who should have signed the message
    */
    error UnknownSigner(address unknownSigner, address whitelistSigner);

    /**
    * @dev reverts with this message when the caller is trying to mint more than allowed
    * @param minted is the amount of tokens the caller has minted already
    */
    error ExceedMintingCapacity(uint256 minted);

    /**
    * @notice initializes the contract
    */
    constructor () {
        DOMAIN_SEPARATOR = hash(EIP712Domain({
            name: "AccessPassNFT",
            version: '1',
            chainId: block.chainid,
            verifyingContract: address(this)
        }));
    }

    /**
    * @notice sets the whitelistSigner
    * @param whitelistSigner_ is an EOA that signs verified slots
    */
    function _setWhiteListSigner(address whitelistSigner_) internal virtual {
        if (whitelistSigner_ == address(0)) revert WhitelistSignerIsZeroAddress();

        emit WhitelistSignerSet(whiteListSigner, whitelistSigner_);
        whiteListSigner = whitelistSigner_;

    }

    /**
    * @notice validates verified slot
    * @param minter is msg.sender
    * @param minted is the amount the minter has minted
    * @param verifiedSlot is an object with the following:
    * minter: address of the minter,
    * mintingCapacity: amount Metaframes has decided to grant to the minter,
    * r and s --- The x co-ordinate of r and the s value of the signature
    * v: The parity of the y co-ordinate of r
    */
    function validateVerifiedSlot(
        address minter,
        uint256 minted,
        VerifiedSlot memory verifiedSlot
    ) internal view
    {
        if (whiteListSigner == address(0)) revert WhitelistSignerIsZeroAddress();
        if (verifiedSlot.minter != minter) revert CallerIsNotMinter(minter, verifiedSlot.minter);
        if(verifiedSlot.mintingCapacity <= minted) revert ExceedMintingCapacity(minted);

        address wouldBeSigner = getSigner(verifiedSlot);
        if (wouldBeSigner != whiteListSigner) revert UnknownSigner(wouldBeSigner, whiteListSigner);
    }

    /**
    * @notice hashes the DOMAIN object using keccak256
    * @param eip712Domain represents the EIP712 object to be hashed
    */
    function hash(EIP712Domain memory eip712Domain) internal pure returns (bytes32) {
        return keccak256(abi.encode(
                EIP712DOMAIN_TYPEHASH,
                keccak256(bytes(eip712Domain.name)),
                keccak256(bytes(eip712Domain.version)),
                eip712Domain.chainId,
                eip712Domain.verifyingContract
            ));
    }

    /**
    * @notice hashes the verifiedslot object using keccak256
    * @param verifiedSlot is an object with the following:
    * minter: address of the minter,
    * mintingCapacity: amount Metaframes has decided to grant to the minter,
    * r and s --- The x co-ordinate of r and the s value of the signature
    * v: The parity of the y co-ordinate of r
    */
    function hash(VerifiedSlot memory verifiedSlot) internal pure returns (bytes32) {
        return
        keccak256(abi.encode(
            VERIFIED_SLOT_TYPEHASH,
            verifiedSlot.minter,
            verifiedSlot.mintingCapacity
        ));
    }

    /**
    * @notice returns the signer of a given verifiedSlot to be used to check who signed the message
    * @param verifiedSlot is an object with the following:
    * minter: address of the minter,
    * mintingCapacity: amount Metaframes has decided to grant to the minter,
    * r and s --- The x co-ordinate of r and the s value of the signature
    * v: The parity of the y co-ordinate of r
    */
    function getSigner(VerifiedSlot memory verifiedSlot) internal view returns (address) {

        // Note: we need to use `encodePacked` here instead of `encode`.
        bytes32 digest = keccak256(abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                hash(verifiedSlot)
            ));

        return ecrecover(digest, verifiedSlot.v, verifiedSlot.r, verifiedSlot.s);
    }
}

File 5 of 23 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

File 6 of 23 : ERC721Royalty.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/ERC721Royalty.sol)

pragma solidity ^0.8.0;

import "../ERC721.sol";
import "../../common/ERC2981.sol";
import "../../../utils/introspection/ERC165.sol";

/**
 * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment
 * information.
 *
 * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
 * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
 *
 * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
 * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
 * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
 *
 * _Available since v4.5._
 */
abstract contract ERC721Royalty is ERC2981, ERC721 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {ERC721-_burn}. This override additionally clears the royalty information for the token.
     */
    function _burn(uint256 tokenId) internal virtual override {
        super._burn(tokenId);
        _resetTokenRoyalty(tokenId);
    }
}

File 7 of 23 : VRFCoordinatorV2Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface VRFCoordinatorV2Interface {
  /**
   * @notice Get configuration relevant for making requests
   * @return minimumRequestConfirmations global min for request confirmations
   * @return maxGasLimit global max for request gas limit
   * @return s_provingKeyHashes list of registered key hashes
   */
  function getRequestConfig()
    external
    view
    returns (
      uint16,
      uint32,
      bytes32[] memory
    );

  /**
   * @notice Request a set of random words.
   * @param keyHash - Corresponds to a particular oracle job which uses
   * that key for generating the VRF proof. Different keyHash's have different gas price
   * ceilings, so you can select a specific one to bound your maximum per request cost.
   * @param subId  - The ID of the VRF subscription. Must be funded
   * with the minimum subscription balance required for the selected keyHash.
   * @param minimumRequestConfirmations - How many blocks you'd like the
   * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS
   * for why you may want to request more. The acceptable range is
   * [minimumRequestBlockConfirmations, 200].
   * @param callbackGasLimit - How much gas you'd like to receive in your
   * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords
   * may be slightly less than this amount because of gas used calling the function
   * (argument decoding etc.), so you may need to request slightly more than you expect
   * to have inside fulfillRandomWords. The acceptable range is
   * [0, maxGasLimit]
   * @param numWords - The number of uint256 random values you'd like to receive
   * in your fulfillRandomWords callback. Note these numbers are expanded in a
   * secure way by the VRFCoordinator from a single random value supplied by the oracle.
   * @return requestId - A unique identifier of the request. Can be used to match
   * a request to a response in fulfillRandomWords.
   */
  function requestRandomWords(
    bytes32 keyHash,
    uint64 subId,
    uint16 minimumRequestConfirmations,
    uint32 callbackGasLimit,
    uint32 numWords
  ) external returns (uint256 requestId);

  /**
   * @notice Create a VRF subscription.
   * @return subId - A unique subscription id.
   * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer.
   * @dev Note to fund the subscription, use transferAndCall. For example
   * @dev  LINKTOKEN.transferAndCall(
   * @dev    address(COORDINATOR),
   * @dev    amount,
   * @dev    abi.encode(subId));
   */
  function createSubscription() external returns (uint64 subId);

  /**
   * @notice Get a VRF subscription.
   * @param subId - ID of the subscription
   * @return balance - LINK balance of the subscription in juels.
   * @return reqCount - number of requests for this subscription, determines fee tier.
   * @return owner - owner of the subscription.
   * @return consumers - list of consumer address which are able to use this subscription.
   */
  function getSubscription(uint64 subId)
    external
    view
    returns (
      uint96 balance,
      uint64 reqCount,
      address owner,
      address[] memory consumers
    );

  /**
   * @notice Request subscription owner transfer.
   * @param subId - ID of the subscription
   * @param newOwner - proposed new owner of the subscription
   */
  function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external;

  /**
   * @notice Request subscription owner transfer.
   * @param subId - ID of the subscription
   * @dev will revert if original owner of subId has
   * not requested that msg.sender become the new owner.
   */
  function acceptSubscriptionOwnerTransfer(uint64 subId) external;

  /**
   * @notice Add a consumer to a VRF subscription.
   * @param subId - ID of the subscription
   * @param consumer - New consumer which can use the subscription
   */
  function addConsumer(uint64 subId, address consumer) external;

  /**
   * @notice Remove a consumer from a VRF subscription.
   * @param subId - ID of the subscription
   * @param consumer - Consumer to remove from the subscription
   */
  function removeConsumer(uint64 subId, address consumer) external;

  /**
   * @notice Cancel a subscription
   * @param subId - ID of the subscription
   * @param to - Where to send the remaining LINK to
   */
  function cancelSubscription(uint64 subId, address to) external;
}

File 8 of 23 : VRFConsumerBaseV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/** ****************************************************************************
 * @notice Interface for contracts using VRF randomness
 * *****************************************************************************
 * @dev PURPOSE
 *
 * @dev Reggie the Random Oracle (not his real job) wants to provide randomness
 * @dev to Vera the verifier in such a way that Vera can be sure he's not
 * @dev making his output up to suit himself. Reggie provides Vera a public key
 * @dev to which he knows the secret key. Each time Vera provides a seed to
 * @dev Reggie, he gives back a value which is computed completely
 * @dev deterministically from the seed and the secret key.
 *
 * @dev Reggie provides a proof by which Vera can verify that the output was
 * @dev correctly computed once Reggie tells it to her, but without that proof,
 * @dev the output is indistinguishable to her from a uniform random sample
 * @dev from the output space.
 *
 * @dev The purpose of this contract is to make it easy for unrelated contracts
 * @dev to talk to Vera the verifier about the work Reggie is doing, to provide
 * @dev simple access to a verifiable source of randomness. It ensures 2 things:
 * @dev 1. The fulfillment came from the VRFCoordinator
 * @dev 2. The consumer contract implements fulfillRandomWords.
 * *****************************************************************************
 * @dev USAGE
 *
 * @dev Calling contracts must inherit from VRFConsumerBase, and can
 * @dev initialize VRFConsumerBase's attributes in their constructor as
 * @dev shown:
 *
 * @dev   contract VRFConsumer {
 * @dev     constructor(<other arguments>, address _vrfCoordinator, address _link)
 * @dev       VRFConsumerBase(_vrfCoordinator) public {
 * @dev         <initialization with other arguments goes here>
 * @dev       }
 * @dev   }
 *
 * @dev The oracle will have given you an ID for the VRF keypair they have
 * @dev committed to (let's call it keyHash). Create subscription, fund it
 * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface
 * @dev subscription management functions).
 * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations,
 * @dev callbackGasLimit, numWords),
 * @dev see (VRFCoordinatorInterface for a description of the arguments).
 *
 * @dev Once the VRFCoordinator has received and validated the oracle's response
 * @dev to your request, it will call your contract's fulfillRandomWords method.
 *
 * @dev The randomness argument to fulfillRandomWords is a set of random words
 * @dev generated from your requestId and the blockHash of the request.
 *
 * @dev If your contract could have concurrent requests open, you can use the
 * @dev requestId returned from requestRandomWords to track which response is associated
 * @dev with which randomness request.
 * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind,
 * @dev if your contract could have multiple requests in flight simultaneously.
 *
 * @dev Colliding `requestId`s are cryptographically impossible as long as seeds
 * @dev differ.
 *
 * *****************************************************************************
 * @dev SECURITY CONSIDERATIONS
 *
 * @dev A method with the ability to call your fulfillRandomness method directly
 * @dev could spoof a VRF response with any random value, so it's critical that
 * @dev it cannot be directly called by anything other than this base contract
 * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method).
 *
 * @dev For your users to trust that your contract's random behavior is free
 * @dev from malicious interference, it's best if you can write it so that all
 * @dev behaviors implied by a VRF response are executed *during* your
 * @dev fulfillRandomness method. If your contract must store the response (or
 * @dev anything derived from it) and use it later, you must ensure that any
 * @dev user-significant behavior which depends on that stored value cannot be
 * @dev manipulated by a subsequent VRF request.
 *
 * @dev Similarly, both miners and the VRF oracle itself have some influence
 * @dev over the order in which VRF responses appear on the blockchain, so if
 * @dev your contract could have multiple VRF requests in flight simultaneously,
 * @dev you must ensure that the order in which the VRF responses arrive cannot
 * @dev be used to manipulate your contract's user-significant behavior.
 *
 * @dev Since the block hash of the block which contains the requestRandomness
 * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful
 * @dev miner could, in principle, fork the blockchain to evict the block
 * @dev containing the request, forcing the request to be included in a
 * @dev different block with a different hash, and therefore a different input
 * @dev to the VRF. However, such an attack would incur a substantial economic
 * @dev cost. This cost scales with the number of blocks the VRF oracle waits
 * @dev until it calls responds to a request. It is for this reason that
 * @dev that you can signal to an oracle you'd like them to wait longer before
 * @dev responding to the request (however this is not enforced in the contract
 * @dev and so remains effective only in the case of unmodified oracle software).
 */
abstract contract VRFConsumerBaseV2 {
  error OnlyCoordinatorCanFulfill(address have, address want);
  address private immutable vrfCoordinator;

  /**
   * @param _vrfCoordinator address of VRFCoordinator contract
   */
  constructor(address _vrfCoordinator) {
    vrfCoordinator = _vrfCoordinator;
  }

  /**
   * @notice fulfillRandomness handles the VRF response. Your contract must
   * @notice implement it. See "SECURITY CONSIDERATIONS" above for important
   * @notice principles to keep in mind when implementing your fulfillRandomness
   * @notice method.
   *
   * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this
   * @dev signature, and will call it once it has verified the proof
   * @dev associated with the randomness. (It is triggered via a call to
   * @dev rawFulfillRandomness, below.)
   *
   * @param requestId The Id initially returned by requestRandomness
   * @param randomWords the VRF output expanded to the requested number of words
   */
  function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual;

  // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF
  // proof. rawFulfillRandomness then calls fulfillRandomness, after validating
  // the origin of the call
  function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external {
    if (msg.sender != vrfCoordinator) {
      revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator);
    }
    fulfillRandomWords(requestId, randomWords);
  }
}

File 9 of 23 : TicketNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.8.6;

/**
* @title NFTs for the TicketCompetition to the World Cup for Metaframes
* @author MetaFrames
* @notice This is the NFT contract used as basis to determine the winner of the World Cup Ticket. This is also
* related to the AccessPassNFT
* @dev The flow of the contract is as follows:
* Deployment: Contract is deployed and configured
* -----------------------------------------------
* Airdrop: Minting TicketNFTs to 500 Random Users
*  -airdrop()
* -----------------------------------------------
* Ticket Competition: Selection of the ticket winner
*  -setRegistered() means registration was done off-chain
*  -requestRandomWord() requests the random number from VRF
*  -ticketWinners() then returns the winner
* -----------------------------------------------
* Winners Frozen: When winning tokens are barred from trading their tokens
* -----------------------------------------------
* Trading Enabled: When all trading has been enabled again
*/

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "./AccessPassNFT.sol";
import "./interfaces/IAccessPassNFT.sol";
import "./interfaces/ITicketNFT.sol";

contract TicketNFT is Ownable, ERC721Royalty, VRFConsumerBaseV2, ITicketNFT {
    using Strings for uint256;

    uint16 public constant NUMBER_OF_WINNERS = 2;

    /**
    * @dev maxTotalSupply is the amount of NFTs that can be minted
    */
    uint16 public immutable maxTotalSupply;

    /**
    * @dev contractURI is an OpenSea standard. This should point to a metadata that tells who will receive revenues
    * from OpensSea. See https://docs.opensea.io/docs/contract-level-metadata
    */
    string public contractURI;

    /**
    * @dev frozenPeriod is a timestamp for when the ticket winners can start trading again
    */
    uint256 public frozenPeriod;

    /**
    * @dev if set to true, that particular nft is a winner
    */
    mapping(uint256 => bool) public isWinner;

    /**
    * @dev array of winning ids
    */
    uint256[] public ticketWinners;

    /**
    * @dev baseURI is the base of the token metadata used in conjunction with the token id
    */
    string public baseURI;

    /**
    * @dev flag that tells if the tickets have been airdropped
    */
    bool public ticketsAirdropped;

    /**
    * @dev flag that tells if the registration has been set
    */
    bool public hasSetRegistration;

    /**
    * @dev Mapping of token id to if the owner of that token id has not registered off-chain.
    * For example:
    * 1. owner of token id 0 has registered, so 0 => false
    * 2. owner of token id 2 has NOT registered, so 1 => true
    * This was purposely made as hasNotRegistered so that we only write for values that have not registered.
    * This is to save gas since there should be more people who have registered than those who have not.
    * The registration comes from an off-chain database.
    */
    mapping(uint16 => bool) private _hasNotRegistered;

    /**
    * @dev the related AccessPassNFT to this contract
    */
    AccessPassNFT public accessPassNFT;

    /**
    * @dev The following variables are needed to request a random value from Chainlink.
    * See https://docs.chain.link/docs/vrf-contracts/
    */
    address public chainlinkCoordinator; // Chainlink Coordinator address
    uint256 public requestId;            // Chainlink request id for the selection of the ticket winner
    uint256 public randomWord;           // Random value received from Chainlink VRF

    /**
    * @notice initializes the contract
    * @param baseURI_ is the metadata's uri
    * @param contractURI_ is for OpenSeas compatability
    * @param royaltyAddress receives royalties fee from selling this token
    * @param royaltyFee is the fees taken from second-hand selling. This is expressed in _royaltyFee/1000.
    * So to do 5% means supplying 50 since 50/1000 is 5% (see ERC2981 function _setDefaultRoyalty(address receiver, uint96 feeNumerator))
    * @param accessPassNFT_ is the address of the AccessPassNFT related to this token
    * @param vrfCoordinator_ is the address of the VRF used for getting a random number
    * @param nftHolder is the temporary holder of the NFTs before the airdrop
    * @param frozenPeriod_ is a timestamp for when the ticket winners can start trading again
    */
    constructor(
        string memory baseURI_,
        string memory contractURI_,
        address royaltyAddress,
        uint96 royaltyFee,
        AccessPassNFT accessPassNFT_,
        address vrfCoordinator_,
        address nftHolder,
        uint256 frozenPeriod_
    ) ERC721("Maradona Official World Cup Ticket", "OMWC")
      VRFConsumerBaseV2(vrfCoordinator_){

        // crucial to check if there is a '/' in the end since this can no longer be changed once set
        // must have a '/' in the end since the token id follows the '/'
        bytes memory bytesBaseURI = bytes(baseURI_);
        if (bytesBaseURI[bytesBaseURI.length - 1] != bytes("/")[0]) revert IncorrectValue("baseURI");
        baseURI = baseURI_;

        if (bytes(contractURI_).length == 0) revert EmptyString("contractURI");
        contractURI = contractURI_;

        if(royaltyAddress == address(0)) revert ZeroAddress("royaltyAddress");
        // not checking royaltyFee on purpose here
        _setDefaultRoyalty(royaltyAddress, royaltyFee);

        uint16 maxTotalSupply_ = accessPassNFT_.ticketSupply();
        maxTotalSupply = maxTotalSupply_;

        bytes4 accessPassNFTInterfaceId = type(IAccessPassNFT).interfaceId;
        if(!accessPassNFT_.supportsInterface(accessPassNFTInterfaceId)) revert IncorrectValue("accessPassNFT");
        accessPassNFT = accessPassNFT_;

        if(address(vrfCoordinator_) == address(0)) revert ZeroAddress("vrfCoordinator");
        chainlinkCoordinator = vrfCoordinator_;

        if(nftHolder == address(0)) revert ZeroAddress("nftHolder");

        // sending nfts to nftHolder which will be the eventual owner of the contract who will do the airdrop
        for (uint256 i = 0; i < maxTotalSupply_; i++) {
            _safeMint(nftHolder, i);
        }

        // not checking frozenPeriod_ on purpose here because there's a way to change it later
        frozenPeriod = frozenPeriod_;

    }

    /********************** EXTERNAL ********************************/

    /**
    * @inheritdoc ITicketNFT
    */
    function airdrop(
        uint16[] calldata winners
    ) external
        override
        onlyOwner
        onlyDuring(ContractStatus.TICKETS_REVEALED)
    {
        if (winners.length != maxTotalSupply) revert IncorrectValue("winners");

        for (uint256 i = 0; i < winners.length; i++) {
            safeTransferFrom(msg.sender, accessPassNFT.ownerOf(winners[i]), i);
        }

        ticketsAirdropped = true;
        emit TicketsAirdropped(winners);
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function requestRandomWord(
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit
    ) external
        override
        onlyOwner
        onlyDuring(ContractStatus.SET_REGISTRATION)
    {

        // making sure that the request has enough callbackGasLimit to execute
        if (callbackGasLimit < 150_000) revert IncorrectValue("callbackGasLimit");

        /// Call Chainlink to receive a random word
        /// Will revert if subscription is not funded.
        VRFCoordinatorV2Interface coordinator = VRFCoordinatorV2Interface(chainlinkCoordinator);
        requestId = coordinator.requestRandomWords(
            gasLane,
            subscriptionId,
            3, /// Request confirmations
            callbackGasLimit,
            1 /// request 1 random number
        );
        /// Now Chainlink will call us back in a future transaction, see function fulfillRandomWords

        emit RandomWordRequested(requestId);
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function setContractURI(string memory uri) external override onlyOwner() {
        if (bytes(uri).length == 0) revert EmptyString("contractURI");
        emit ContractURISet(contractURI, uri);
        contractURI = uri;
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function setDefaultRoyalty(address royaltyAddress, uint96 royaltyFee) external override onlyOwner(){
        if (address(0) == royaltyAddress) revert ZeroAddress("royaltyAddress");
        _setDefaultRoyalty(royaltyAddress, royaltyFee);
        emit RoyaltiesSet(royaltyAddress, royaltyFee);
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function setRegistered(
        bool[] calldata hasRegistered_
    ) external
        override
        onlyOwner
        onlyDuring(ContractStatus.AIRDROPPED_TICKETS)
    {
        // sending an empty array means all accounts have registered
        if (hasRegistered_.length == 0) {
            hasSetRegistration = true;
        } else {
            if (hasRegistered_.length != maxTotalSupply) revert IncorrectValue("hasRegistered");
            uint16 notRegisteredCounter = 0;

            for (uint16 i = 0; i < hasRegistered_.length; i++) {
                if (!hasRegistered_[i]) {
                    // only writing for those who have not registered
                    _hasNotRegistered[i] = true;
                    // counting how many accounts have not registred
                    notRegisteredCounter++;
                }
            }

            // ensuring that there are enough registered to have enough winners
            if (maxTotalSupply - notRegisteredCounter < NUMBER_OF_WINNERS) revert IncorrectValue("notRegisteredCounter");
            hasSetRegistration = true;
        }
        emit RegistrationSet(hasRegistered_);
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function setFrozenPeriod(uint256 frozenPeriod_) external override onlyOwner() onlyBefore(ContractStatus.WINNERS_FROZEN) {
        if (frozenPeriod_ < block.timestamp && frozenPeriod_ != 0) revert IncorrectValue("frozenPeriod_");
        emit FrozenPeriodSet(frozenPeriod, frozenPeriod_);
        frozenPeriod = frozenPeriod_;
    }

    /********************** PUBLIC VIEW ********************************/

    /**
    * @notice returns a token metadata's uri
    * @param tokenId is the id of the token being queried
    */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        if(!_exists(tokenId)) revert NonExistentToken();

        return string(abi.encodePacked(baseURI, tokenId.toString(), ".json"));
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function hasRegistered(
        uint16 tokenId
    ) public
        view
        override
        onlyOnOrAfter(ContractStatus.SET_REGISTRATION)
        returns (bool)
    {
        if(tokenId >= maxTotalSupply) revert NonExistentToken();
        return !_hasNotRegistered[tokenId];
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function isAccountWinner(address account) public view override returns (bool){
        for (uint16 i = 0; i < ticketWinners.length; i++) {
            if (ownerOf(ticketWinners[i]) == account) return true;
        }
        return false;
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function contractStatus() public view override returns (ContractStatus) {
        if(randomWord != 0) {
            if(block.timestamp < frozenPeriod) return ContractStatus.WINNERS_FROZEN;
            else return ContractStatus.TRADING_ENABLED;
        }
        if(hasSetRegistration) return ContractStatus.SET_REGISTRATION;
        if(ticketsAirdropped) return ContractStatus.AIRDROPPED_TICKETS;
        if(accessPassNFT.ticketsRevealed()) return ContractStatus.TICKETS_REVEALED;
        return ContractStatus.PRE_AIRDROP;
    }

    /**
    * @inheritdoc ITicketNFT
    */
    function totalSupply() public view override returns (uint256) {
        return maxTotalSupply;
    }

    /**
    * @inheritdoc IERC165
    */
    function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721Royalty, IERC165)
    returns (bool)
    {
        return
            interfaceId == type(ITicketNFT).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /********************** INTERNAL ********************************/

    /**
    * @notice check if token is frozen before transferring
    * @inheritdoc ERC721
    * @param from is the address that will give the token
    * @param to is the address that will receive the token
    * @param tokenId is the id being transferred
    */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override {

        // not allowing winningIds to be transferred when in frozenPeriod
        if (
            block.timestamp < frozenPeriod &&
            isWinner[tokenId]
        ) revert TransferringFrozenToken(tokenId, block.timestamp, frozenPeriod);
    }

    /**
    * @notice sets the winners
    */
    function setWinners() internal {
        // Setup a pool with random values
        uint256 randomPoolSize = 16;
        uint256 batch = 0;
        uint16[] memory randomPool = randArray(randomPoolSize, batch++);

        uint256 counter = 0;
        uint16 randomId;

        for (uint16 i = 0; i < NUMBER_OF_WINNERS; i++) {
            randomId = randomPool[counter++];
            if (counter == randomPoolSize) {
                randomPool = randArray(randomPoolSize, batch++);
                counter = 0;
            }

            // only stays in the loop when the current id has not registered or if the current id already won
            while(_hasNotRegistered[randomId] || isWinner[randomId]) {
                randomId = randomPool[counter++];
                if (counter == randomPoolSize) {
                    randomPool = randArray(randomPoolSize, batch++);
                    counter = 0;
                }
            }

            ticketWinners.push(randomId);
            isWinner[randomId] = true; // Using mapping to keep track for if the id was already chosen as a winner
        }

        emit TicketWinnersFrozen(frozenPeriod);
    }

    /**
    * @notice Chainlink calls us with a random value. (See VRFConsumerBaseV2's fulfillRandomWords function)
    * @dev Note that this happens in a later transaction than the request. This approximately costs 139_000 in gas
    * @param requestId_ is the id of the request from VRF's side
    * @param randomWords is an array of random numbers generated by VRF
    */
    function fulfillRandomWords(
        uint256 requestId_,
        uint256[] memory randomWords
    ) internal override {
        if(requestId != requestId_) revert IncorrectValue("requestId");
        if(randomWord != 0) revert CallingMoreThanOnce();
        randomWord = randomWords[0];
        emit TicketWinnersSelected(randomWords[0]);

        setWinners();
    }

    /**
    * @notice Returns a list of x random numbers, in increments of 16 numbers.
    * So you may receive x random numbers or up to 15 more. The random numbers are between 0 and 499
    * Each batch will be different, you can call multiple times with different batch numbers
    * This routine is deterministic and will always return the same result if randomWord is the same
    * @param max is the max numbers needed in a batch
    * @param batch represents the batch number
    */
    function randArray(
        uint256 max,
        uint256 batch
    ) internal
        view
        returns (uint16[] memory)
    {
        uint256 mask = 0xFFFF;   // 0xFFFF == [1111111111111111], masking the last 16 bits

        uint256 mainCounterMax = max / 16;
        if (max % 16 > 0) {
            mainCounterMax +=1;
        }
        uint256 batchOffset = (batch * mainCounterMax * 16);
        uint16[] memory randomValues = new uint16[](mainCounterMax * 16);
        for (uint256 mainCounter = 0; mainCounter < mainCounterMax; mainCounter++) {
            uint256 randomValue = uint256(keccak256(abi.encode(randomWord, mainCounter + batchOffset)));
            for (uint256 subCounter = 0; subCounter < 16; subCounter++) {

                // Mask 16 bits, value between 0 .. maxTotalSupply-1
                randomValues[mainCounter * 16 + subCounter] = uint16(randomValue & mask) % maxTotalSupply;

                // Right shift 16 bits into oblivion
                randomValue = randomValue / 2 ** 16;
            }
        }
        return randomValues;
    }

    /********************** MODIFIER ********************************/

    /**
    * @notice functions like a less than to the supplied status
    * @param status is a ContractStatus in which the function must happen before in. For example:
    * setting the frozenPeriod should only happen before the ticketWinners have been selected to ensure that no one
    * messes with the trading period during ContractStatus.WINNERS_FROZEN. To do that add this modifier
    * with the parameter: ContractStatus.WINNERS_FROZEN
    */
    modifier onlyBefore(ContractStatus status) {
        // asserting here because there should be no state before PRE_AIRDROP
        assert(status != ContractStatus.PRE_AIRDROP);
        ContractStatus lastStatus = ContractStatus(uint(status) - 1);
        if (contractStatus() >= status) revert IncorrectContractStatus(contractStatus(), lastStatus);
        _;
    }

    /**
    * @notice the current status must be equal to the status in the parameter
    * @param status is the ContractStatus it must be in
    */
    modifier onlyDuring(ContractStatus status) {
        if (status != contractStatus()) revert IncorrectContractStatus(contractStatus(), status);
        _;
    }


    /**
    * @notice the current status must be greater than or equal to the status in the parameter
    * @param status that the contract must at least be in. For example:
    * getting the nftTiers should only happen when TIERS_RANDOMIZED has already happened. so the parameter will be
    * TIERS_RANDOMIZED, because the function can only work once the status is TIERS_RANDOMIZED or has passed that
    */
    modifier onlyOnOrAfter(ContractStatus status) {
        if (contractStatus() < status) revert IncorrectContractStatus(contractStatus(), status);
        _;
    }
}

File 10 of 23 : IAccessPassNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.8.6;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../TicketNFT.sol";
import "./IVerifiedSlot.sol";

/**
* @title Required interface for an AccessPassNFT compliant contract
* @author Oost & Voort, Inc
*/

interface IAccessPassNFT is IERC165, IVerifiedSlot {
    /**
    * @dev The following are the stages of the contract in order:
    * NO_MINTING: Minting is not yet allowed
    * PRIVATE_MINTING: Only people in the mint whitelist can mint
    * PUBLIC_MINTING: Everyone can mint
    * END_MINTING: When everything's been minted already
    * TIERS_RANDOMIZED: When a random number has been set for the tiers
    * TIERS_REVEALED: When the final token metadata has been uploaded to IPFS
    * TICKETS_RANDOMIZED: When a random number has been set for the tickets airdrop
    */
    enum ContractStatus {
        NO_MINTING,
        PRIVATE_MINTING,
        PUBLIC_MINTING,
        END_MINTING,
        TIERS_RANDOMIZED,
        TIERS_REVEALED,
        TICKETS_RANDOMIZED
    }

    /**
    * @dev Minting types are explained below:
    * PRIVATE_MINT: minted using the private mint function
    * PUBLIC_MINT: minted using the public mint function
    */
    enum MintingType {PRIVATE_MINT, PUBLIC_MINT}

    /**
    * @dev The on-chain property of the nft that is determined by a random number
    */
    enum Tier {BRONZE, SILVER, GOLD}

    /**
    * @dev emitted when the owner has set the private minting timestamp
    * @param oldTimestamp is for what the timestamp used to be
    * @param newTimestamp is the new value
    */
    event PrivateMintingTimestampSet(uint256 oldTimestamp, uint256 newTimestamp);


    /**
    * @dev emitted when the owner has set the public minting timestamp
    * @param oldTimestamp is for what the timestamp used to be
    * @param newTimestamp is the new value
    */
    event PublicMintingTimestampSet(uint256 oldTimestamp, uint256 newTimestamp);

    /**
    * @dev emitted when the owner has changed the max number of nfts a public user can mint
    * @param oldMaxPublicMintable is the old value for the maximum a public account can mint
    * @param newMaxPublicMintable is the new value for the maximum a public account can mint
    */
    event MaxPublicMintableSet(uint16 oldMaxPublicMintable, uint16 newMaxPublicMintable);


    /**
    * @dev emitted when the owner changes the treasury
    * @param oldTreasury is the old value for the treasury
    * @param newTreasury is the new value for the treasury
    */
    event TreasurySet(address oldTreasury, address newTreasury);

    /**
    * @dev emitted when the owner changes the minting price
    * @param oldPrice is the price the minting was set as
    * @param newPrice is the new price minting will cost as
    */
    event PriceSet(uint256 oldPrice, uint256 newPrice);

    /**
    * @dev emitted when the owner changes the royalties
    * @param newRoyalties is the new royalties set by the owner
    */
    event RoyaltyFeesSet(uint96 newRoyalties);

    /**
    * @dev emitted when the owner has changed the contract uri
    * @param oldURI is the uri it was set as before
    * @param newURI is the uri it is now set in
    */
    event ContractURISet(string oldURI, string newURI);

    /**
    * @dev emitted when the owner has changed the unrevealed uri
    * @param oldURI is the uri it was set as before
    * @param newURI is the uri it is now set in
    */
    event UnrevealedURISet(string oldURI, string newURI);

    /**
    * @dev emitted when the TicketNFT has been set
    * @param oldTicketNFT is the old TicketNFT it was pointing to
    * @param newTicketNFT is the TicketNFT it is now pointing to
    */
    event TicketNFTSet(TicketNFT oldTicketNFT, TicketNFT newTicketNFT);

    /**
    * @dev emitted when the treasury has been paid in ETH
    * @param account is the account that paid the treasury
    * @param amount is how much ETH the account sent to the treasury
    */
    event TreasuryPaid(address indexed account, uint256 amount);

    /**
    * @dev the following events must be done in order
    */

    /**
    * @dev emitted when the owner has requested a random word from VRF to set the tiers of each NFT
    * @param requestId is the id set by VRF
    */
    event TiersRandomWordRequested(uint256 requestId);

    /**
    * @dev emitted when VRF has used fulfillRandomness to set the random number
    * @param randomWord is the randomWord given back in a callback by VRF
    */
    event TiersRandomized(uint256 randomWord);

    /**
    * @dev emitted when the owner has put the final token metadata uri for the nfts
    */
    event TiersRevealed();

    /**
    * @dev emitted when the owner has requested a random word from VRF to set who will be airdropped TicketNFTs
    * @param requestId is the id set by VRF
    */
    event TicketsRandomWordRequested(uint256 requestId);

    /**
    * @dev emitted when VRF has used fulfillRandomness to set the random number
    * @param randomWord is the randomWord given back in a callback by VRF
    */
    event TicketsRandomized(uint256 randomWord);

    /**
    * @dev reverted with this error when the address being supplied is Zero Address
    * @param addressName is for whom the Zero Address is being set for
    */
    error ZeroAddress(string addressName);

    /**
    * @dev reverted with this error when a view function is asking for a Zero Address' information
    */
    error ZeroAddressQuery();

    /**
    * @dev reverted with this error when a view function is being used to look for a nonExistent Token
    */
    error NonExistentToken();

    /**
    * @dev reverted with this error when a function is being called more than once
    */
    error CallingMoreThanOnce();

    /**
    * @dev reverted with this error when a function should no longer be called
    */
    error CanNoLongerCall();

    /**
    * @dev reverted with this error when a variable being supplied is valued 0
    * @param variableName is the name of the variable being supplied with 0
    */
    error IsZero(string variableName);

    /**
    * @dev reverted with this error when a variable has an incorrect value
    * @param variableName is the name of the variable with an incorrect value
    */
    error IncorrectValue(string variableName);

    /**
    * @dev reverted with this error when a string being supplied should not be empty
    * @param stringName is the name of the string being supplied with an empty value
    */
    error EmptyString(string stringName);

    /**
    * @dev reverted with this error when a function being called should not be called with the current Contract Status
    * @param currentStatus is the contract's current status
    * @param requiredStatus is the status the current must be in for the function to not revert
    */
    error IncorrectContractStatus(ContractStatus currentStatus, ContractStatus requiredStatus);

    /**
    * @dev reverted with this error when an account that has won is trying to transfer his or her last AccessPassNFT
    * during WINNERS_FROZEN in TicketNFT
    * @param account is the address trying to transfer
    * @param currentTimestamp is the current block's timestamp
    * @param requiredTimestamp is the timestamp the block must at least be in
    */
    error TransferringFrozenAccount(address account, uint256 currentTimestamp, uint256 requiredTimestamp);

    /********************** EXTERNAL ********************************/

    /**
    * @notice private mints for people in the whitelist
    * @param verifiedSlot is a signed message by the whitelist signer that presents how many the minter can mint
    */
    function privateMint(VerifiedSlot calldata verifiedSlot) external payable;

    /*
    * @notice public mints for anyone
    */
    function publicMint() external payable;

    /**
    * @notice Randomize the NFT. This requests a random Chainlink value, which causes the tier of each nft id to be known.
    * @dev See https://docs.chain.link/docs/vrf-contracts/#configurations for Chainlink VRF documentation
    * @param subscriptionId The chainlink subscription id that pays for the call to Chainlink, needs to be setup with ChainLink beforehand
    * @param gasLane The maximum gas price you are willing to pay for a Chainlink VRF request in wei
    * @param callbackGasLimit How much gas to use for the callback request. Approximately 29_000 is used up solely by
    * fulfillRandomWords
    */
    function randomizeTiers(
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit
    ) external;

    /**
    * @notice sets the base URI for the token metadata
    * @dev This can only happen once after the generation of the token metadata in unison with the winners function.
    * @param revealedURI must end in a '/' (slash), because the tokenURI expects it to end in a slash.
    */
    function revealTiers(string memory revealedURI) external;

    /**
    * @notice Randomize the tickets. This requests a random Chainlink value, which causes the winners to be known.
    * @dev See https://docs.chain.link/docs/vrf-contracts/#configurations for Chainlink VRF documentation
    * @param subscriptionId The chainlink subscription id that pays for the call to Chainlink, needs to be setup with ChainLink beforehand
    * @param gasLane The maximum gas price you are willing to pay for a Chainlink VRF request in wei
    * @param callbackGasLimit How much gas to use for the callback request. Approximately 31_000 gas is used up
    * solely by fulfillRandomWords.
    */
    function randomizeTickets(
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit
    ) external;

    /**
    * @notice sets the whitelist signer
    * @dev immediately do this after deploying the contract
    * @param whiteListSigner_ is the signer address for verifying the minting slots
    */
    function setWhitelistSigner(address whiteListSigner_) external;

    /**
    * @notice sets the ticketNFT
    * @dev set this before selecting the TicketWinners in TicketNFT
    * @param ticketNFT_ is the TicketNFT that selects the ticketWinners
    */
    function setTicketNFT(TicketNFT ticketNFT_) external;

    /**
    * @notice sets the recipient of the eth from public and private minting and the royalty fees
    * @dev setRoyaltyFee right after setting the treasury
    * @param treasury_ could be an EOA or a gnosis contract that receives eth and royalty fees
    */
    function setTreasury(address payable treasury_) external;

    /**
    * @notice sets the royalty fee for the second hand market selling
    * @param royaltyFee is the fees taken from second-hand selling. This is expressed in a _royaltyFee/10_000.
    * So to do 5% means supplying 500 since 500/10_000 is 5% (see ERC2981 function _setDefaultRoyalty(address receiver, uint96 feeNumerator))
    */
    function setRoyaltyFee(uint96 royaltyFee) external;

    /**
    * @notice sets the price of minting. the amount is sent to the treasury right after the minting
    * @param price_ is expressed in wei
    */
    function setPrice(uint256 price_) external;

    /**
    * @notice sets the contract uri
    * @param contractURI_ points to a json file that follows OpenSeas standard (see https://docs.opensea.io/docs/contract-level-metadata)
    */
    function setContractURI(string memory contractURI_) external;

    /**
    * @notice sets the unrevealedURI
    * @param unrevealedURI_ points to a json file with the placeholder image inside
    */
    function setUnrevealedURI(string memory unrevealedURI_) external;

    /**
    * @notice sets the private minting timestamp
    * @param privateMintingTimestamp_ is when private minting is enabled. Setting this to zero disables all minting
    */
    function setPrivateMintingTimestamp(uint256 privateMintingTimestamp_) external;

    /**
    * @notice sets the public minting timestamp
    * @param publicMintingTimestamp_ is when public minting will be enabled.
    * Setting this to zero disables public minting.
    * If set, public minting must happen after private minting
    */
    function setPublicMintingTimestamp(uint256 publicMintingTimestamp_) external;

    /**
    /* @notice sets how many a minter can public mint
    /* @param maxPublicMintable_ is how many a public account can mint
    */
    function setMaxPublicMintable(uint16 maxPublicMintable_) external;

    /********************** EXTERNAL VIEW ********************************/

    /**
    * @notice returns the count an account has minted
    * @param minter is for the account being queried
    */
    function mintedBy(address minter) external view returns (uint256);

    /**
    * @notice returns the count an account has minted per type
    * @param minter is for the account being queried
    * @param mintingType is the type of minting expected
    */
    function mintedBy(address minter, MintingType mintingType) external view returns (uint256);

    /**
    * @notice Returns the tier for an nft id
    * @param tokenId is the id of the token being queried
    */
    function nftTier(uint256 tokenId) external view returns (uint16 tier);

    /**
    * @notice Returns true if the ticketsRandomWord has been set in the VRF Callback
    * @dev this is used by TicketNFT as a prerequisite for the airdrop. See TicketNFT for more info.
    */
    function ticketsRevealed() external view returns(bool);

    /**
    * @notice Returns an array of all NFT id's, with 500 winners, indicated by 1. The others are indicated by 0.
    */
    function winners() external view returns (uint16[] memory);

    /**
    * @notice returns the current supply of the NFT
    */
    function totalSupply() external view returns (uint256);

    /**
    * @notice returns the current contract status of the NFT
    */
    function contractStatus() external view returns (ContractStatus);

    /**
    * @notice Returns an array with all nft id's and their tier
    * @dev This function works by filling a pool with random values. When we exhaust the pool,
    * we refill the pool again with different values. We do it like this because we don't
    * know in advance how many random values we need.
    */
    function nftTiers() external view returns (uint16[] memory);
}

File 11 of 23 : ITicketNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.8.6;

import "@openzeppelin/contracts/utils/introspection/IERC165.sol";

/**
* @title Required interface for a TicketNFT compliant contract
* @author Oost & Voort, Inc
*/

interface ITicketNFT is IERC165 {

    /**
    * @dev The following are the stages of the contract in order:
    * PRE_AIRDROP: Before the airdrop has happened
    * TICKETS_REVEALED: when accessPassNFT has already set who the TicketWinners will be
    * AIRDROPPED_TICKETS: when the nfts have been airdropped
    * SET_REGISTRATION: when the _hasNotRegistered have been filled up
    * WINNERS_FROZEN: When the winners have been frozen from doing transfers
    * TRADING_ENABLED: When all trading has been enabled again
    */
    enum ContractStatus {
        PRE_AIRDROP,
        TICKETS_REVEALED,
        AIRDROPPED_TICKETS,
        SET_REGISTRATION,
        WINNERS_FROZEN,
        TRADING_ENABLED
    }

    /**
    * @dev emitted when the owner has changed the contract uri
    * @param oldURI is the uri it was set as before
    * @param newURI is the uri it is now set in
    */
    event ContractURISet(string oldURI, string newURI);

    /**
    * @dev emitted when the owner changes the royalties
    * @param newRoyaltyAddress is the new royalty address that will receive the royalties.
    * @param newRoyalties is the new royalties set by the owner
    */
    event RoyaltiesSet(address newRoyaltyAddress, uint96 newRoyalties);

    /**
    * @dev emitted when the frozenPeriod has been set
    * @param oldTimestamp is the old timestamp for when the frozenPeriod was set
    * @param newTimestamp is the timestamp for when the frozenPeriod will now correspond as
    */
    event FrozenPeriodSet(uint256 oldTimestamp, uint256 newTimestamp);

    /**
    * @dev the following events must be done in order
    */

    /**
    * @dev emitted when the airdrop happens
    * @param winners is the ids of winners from AccessPassNFT. See AccessPassNFT's winners function for more information.
    */
    event TicketsAirdropped(uint16[] winners);

    /**
    * @dev emitted when the registration has been set
    * @param hasRegistered is an array boolean that represents if the onwer of that index has registered off-chain
    */
    event RegistrationSet(bool[] hasRegistered);

    /**
    * @dev emitted when a random number has been requested from VRF
    * @param requestId is the id sent back by VRF to keep track of the request
    */
    event RandomWordRequested(uint256 requestId);

    /**
    * @dev emitted when a ticket winner has been selected
    * @param randomWord is used to determine the TicketWinner
    */
    event TicketWinnersSelected(uint256 randomWord);

    /**
    * @dev emitted when the trading for winners have been frozen
    * @param frozenTimestamp is until when trading for winning nfts have been frozen for
    */
    event TicketWinnersFrozen(uint256 frozenTimestamp);

    /**
    * @dev reverted with this error when the address being supplied is Zero Address
    * @param addressName is for whom the Zero Address is being set for
    */
    error ZeroAddress(string addressName);

    /**
    * @dev reverted with this error when a view function is being used to look for a nonExistent Token
    */
    error NonExistentToken();

    /**
    * @dev reverted with this error when a function is being called more than once
    */
    error CallingMoreThanOnce();

    /**
    * @dev reverted with this error when a variable has an incorrect value
    * @param variableName is the name of the variable with an incorrect value
    */
    error IncorrectValue(string variableName);

    /**
    * @dev reverted with this error when a string being supplied should not be empty
    * @param stringName is the name of the string being supplied with an empty value
    */
    error EmptyString(string stringName);

    /**
    * @dev reverted with this error when a function being called should not be called with the current Contract Status
    * @param currentStatus is the contract's current status
    * @param requiredStatus is the status the current must be in for the function to not revert
    */
    error IncorrectContractStatus(ContractStatus currentStatus, ContractStatus requiredStatus);

    /**
    * @dev reverted with this error when transferring a winningId during frozenPeriod
    * @param tokenId is the id being transferred
    * @param currentTimestamp is the current block's timestamp
    * @param requiredTimestamp is the timestamp the block must at least be in
    */
    error TransferringFrozenToken(uint256 tokenId, uint256 currentTimestamp, uint256 requiredTimestamp);

    /**
    * @notice airdrops to accessPassNFT winners
    * @param winners are accessPassNFT winners taken off-chain
    */
    function airdrop(
        uint16[] calldata winners
    ) external;

    /**
    * @notice requests a random word from VRF to be used for selecting a ticket winner
    * @dev See https://docs.chain.link/docs/vrf-contracts/#configurations for Chainlink VRF documentation
    * @param subscriptionId The chainlink subscription id that pays for the call to Chainlink, needs to be setup with ChainLink beforehand
    * @param gasLane The maximum gas price you are willing to pay for a Chainlink VRF request in wei
    * @param callbackGasLimit How much gas to use for the callback request. Approximately 139_000 gas is used up solely
    * by fulfillRandomWords.
    */
    function requestRandomWord(
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit
    ) external;

    /**
    * @notice sets the contract uri
    * @param uri points to a json file that follows OpenSeas standard (see https://docs.opensea.io/docs/contract-level-metadata)
    */
    function setContractURI(string memory uri) external;

    /**
    * @notice sets the royalty fee for the second hand market selling
    * @param royaltyAddress is the recepient of royalty fees from second hand market.
    * @param royaltyFee is the fees taken from second-hand selling. This is expressed in a _royaltyFee/1000.
    * So to do 5% means supplying 50 since 50/1000 is 5% (see ERC2981 function _setDefaultRoyalty(address receiver, uint96 feeNumerator))
    */
    function setDefaultRoyalty(address royaltyAddress, uint96 royaltyFee) external;

    /**
    * @notice sets the ids of the people who have not registered
    * @dev It is important to do this before requesting a random word. To make it cheaper gas-wise, sending an empty
    * array signifies that all token owners registered off-chain. An explanation of what the array of hasRegistered looks
    * like will follow:
    * if the owner of token id 0 has registered in the array it will show as true,
    * so [true, ...]
    * if the owner of token id 1 has not registered in the array it will show as false
    * so [true, false, ...]
    * and so on..
    * @param hasRegistered_ is an array of boolean that tells if the owner of the id has registered off-chain
    */
    function setRegistered(bool[] calldata hasRegistered_) external;

    /**
    * @notice sets the frozenPeriod for when trading winning token ids is disabled
    * @param frozenPeriod_ is a timestamp for when the ticket winners can start trading again
    */
    function setFrozenPeriod(uint256 frozenPeriod_) external;


    /**
    * @notice returns if the token id has registered or not
    * @param tokenId is the id of the token being queried
    */
    function hasRegistered(
        uint16 tokenId
    ) external view returns (bool);

    /**
    * @notice Returns if the address owns a winning nft
    * @param account is the queried address
    */
    function isAccountWinner(address account) external view returns (bool);

    /**
    * @notice returns the current contract status of the NFT
    */
    function contractStatus() external view returns (ContractStatus);

    /**
    * @notice returns the current supply of the NFT
    */
    function totalSupply() external view returns (uint256);
}

File 12 of 23 : 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 13 of 23 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.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
    }

    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");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' 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) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        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.
            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 if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } 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 (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // 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 14 of 23 : IVerifiedSlot.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IVerifiedSlot {
    struct VerifiedSlot {
        address minter;
        uint16 mintingCapacity;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }
}

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

pragma solidity ^0.8.0;

import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";

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

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

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

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

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

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

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

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

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

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

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

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

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

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

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

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

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

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

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

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

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

        _transfer(from, to, tokenId);
    }

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

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

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

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

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

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

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

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

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

        _balances[to] += 1;
        _owners[tokenId] = to;

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

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

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

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

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

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

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

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

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

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

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits a {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

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

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

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

File 16 of 23 : ERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/common/ERC2981.sol)

pragma solidity ^0.8.0;

import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
 *
 * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
 * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
 *
 * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
 * fee is specified in basis points by default.
 *
 * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
 * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
 * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
 *
 * _Available since v4.5._
 */
abstract contract ERC2981 is IERC2981, ERC165 {
    struct RoyaltyInfo {
        address receiver;
        uint96 royaltyFraction;
    }

    RoyaltyInfo private _defaultRoyaltyInfo;
    mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;

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

    /**
     * @inheritdoc IERC2981
     */
    function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
        RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];

        if (royalty.receiver == address(0)) {
            royalty = _defaultRoyaltyInfo;
        }

        uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();

        return (royalty.receiver, royaltyAmount);
    }

    /**
     * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
     * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
     * override.
     */
    function _feeDenominator() internal pure virtual returns (uint96) {
        return 10000;
    }

    /**
     * @dev Sets the royalty information that all ids in this contract will default to.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
        require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
        require(receiver != address(0), "ERC2981: invalid receiver");

        _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Removes default royalty information.
     */
    function _deleteDefaultRoyalty() internal virtual {
        delete _defaultRoyaltyInfo;
    }

    /**
     * @dev Sets the royalty information for a specific token id, overriding the global default.
     *
     * Requirements:
     *
     * - `tokenId` must be already minted.
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setTokenRoyalty(
        uint256 tokenId,
        address receiver,
        uint96 feeNumerator
    ) internal virtual {
        require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
        require(receiver != address(0), "ERC2981: Invalid parameters");

        _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Resets royalty information for the token id back to the global default.
     */
    function _resetTokenRoyalty(uint256 tokenId) internal virtual {
        delete _tokenRoyaltyInfo[tokenId];
    }
}

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

File 18 of 23 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

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

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

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

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

File 19 of 23 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

File 20 of 23 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

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

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

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

File 21 of 23 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

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

pragma solidity ^0.8.0;

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

File 23 of 23 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        returns (address receiver, uint256 royaltyAmount);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address payable","name":"treasury_","type":"address"},{"internalType":"address","name":"vrfCoordinator_","type":"address"},{"internalType":"uint16","name":"maxTotalSupply_","type":"uint16"},{"internalType":"uint16","name":"goldenTierSupply_","type":"uint16"},{"internalType":"uint16","name":"silverTierSupply_","type":"uint16"},{"internalType":"uint16","name":"ticketSupply_","type":"uint16"},{"internalType":"uint256","name":"privateMintingTimestamp_","type":"uint256"},{"internalType":"uint96","name":"royaltyFee","type":"uint96"},{"internalType":"uint256","name":"price_","type":"uint256"},{"internalType":"string","name":"contractURI_","type":"string"},{"internalType":"string","name":"unrevealedURI_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"minter","type":"address"}],"name":"CallerIsNotMinter","type":"error"},{"inputs":[],"name":"CallingMoreThanOnce","type":"error"},{"inputs":[],"name":"CanNoLongerCall","type":"error"},{"inputs":[{"internalType":"string","name":"stringName","type":"string"}],"name":"EmptyString","type":"error"},{"inputs":[{"internalType":"uint256","name":"minted","type":"uint256"}],"name":"ExceedMintingCapacity","type":"error"},{"inputs":[{"internalType":"enum IAccessPassNFT.ContractStatus","name":"currentStatus","type":"uint8"},{"internalType":"enum IAccessPassNFT.ContractStatus","name":"requiredStatus","type":"uint8"}],"name":"IncorrectContractStatus","type":"error"},{"inputs":[{"internalType":"string","name":"variableName","type":"string"}],"name":"IncorrectValue","type":"error"},{"inputs":[{"internalType":"string","name":"variableName","type":"string"}],"name":"IsZero","type":"error"},{"inputs":[],"name":"NonExistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentTimestamp","type":"uint256"},{"internalType":"uint256","name":"requiredTimestamp","type":"uint256"}],"name":"TransferringFrozenAccount","type":"error"},{"inputs":[{"internalType":"address","name":"unknownSigner","type":"address"},{"internalType":"address","name":"whitelistSigner","type":"address"}],"name":"UnknownSigner","type":"error"},{"inputs":[],"name":"WhitelistSignerIsZeroAddress","type":"error"},{"inputs":[{"internalType":"string","name":"addressName","type":"string"}],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAddressQuery","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":false,"internalType":"string","name":"oldURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldMaxPublicMintable","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newMaxPublicMintable","type":"uint16"}],"name":"MaxPublicMintableSet","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":"uint256","name":"oldPrice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"PriceSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"name":"PrivateMintingTimestampSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTimestamp","type":"uint256"}],"name":"PublicMintingTimestampSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"newRoyalties","type":"uint96"}],"name":"RoyaltyFeesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract TicketNFT","name":"oldTicketNFT","type":"address"},{"indexed":false,"internalType":"contract TicketNFT","name":"newTicketNFT","type":"address"}],"name":"TicketNFTSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"TicketsRandomWordRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"randomWord","type":"uint256"}],"name":"TicketsRandomized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"requestId","type":"uint256"}],"name":"TiersRandomWordRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"randomWord","type":"uint256"}],"name":"TiersRandomized","type":"event"},{"anonymous":false,"inputs":[],"name":"TiersRevealed","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":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TreasuryPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasurySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"oldURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"UnrevealedURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"WhitelistSignerSet","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainlinkCoordinator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractStatus","outputs":[{"internalType":"enum IAccessPassNFT.ContractStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"goldenTierSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPublicMintable","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTotalSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"enum IAccessPassNFT.MintingType","name":"mintingType","type":"uint8"}],"name":"mintedBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"mintedBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"nftTier","outputs":[{"internalType":"uint16","name":"tier","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nftTiers","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"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":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint16","name":"mintingCapacity","type":"uint16"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IVerifiedSlot.VerifiedSlot","name":"verifiedSlot","type":"tuple"}],"name":"privateMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"privateMintingTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicMintingTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"bytes32","name":"gasLane","type":"bytes32"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"}],"name":"randomizeTickets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"subscriptionId","type":"uint64"},{"internalType":"bytes32","name":"gasLane","type":"bytes32"},{"internalType":"uint32","name":"callbackGasLimit","type":"uint32"}],"name":"randomizeTiers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"revealedURI","type":"string"}],"name":"revealTiers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"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":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"contractURI_","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"maxPublicMintable_","type":"uint16"}],"name":"setMaxPublicMintable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price_","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"privateMintingTimestamp_","type":"uint256"}],"name":"setPrivateMintingTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"publicMintingTimestamp_","type":"uint256"}],"name":"setPublicMintingTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"royaltyFee","type":"uint96"}],"name":"setRoyaltyFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract TicketNFT","name":"ticketNFT_","type":"address"}],"name":"setTicketNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"treasury_","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"unrevealedURI_","type":"string"}],"name":"setUnrevealedURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whiteListSigner_","type":"address"}],"name":"setWhitelistSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"silverTierSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketNFT","outputs":[{"internalType":"contract TicketNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketsRandomWord","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketsRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketsRevealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tiersRandomWord","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tiersRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tiersRevealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenIdCounter","outputs":[{"internalType":"uint256","name":"_value","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":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"whiteListSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"winners","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"view","type":"function"}]

6101206040523480156200001257600080fd5b506040516200610e3803806200610e833981016040819052620000359162000f14565b896040518060400160405280601d81526020017f4d617261646f6e61204f6666696369616c204163636573732050617373000000815250604051806040016040528060048152602001634f4d464360e01b815250620000a36200009d6200062c60201b60201c565b62000630565b6040805160c081018252600d608082019081526c1058d8d95cdcd4185cdcd39195609a1b60a083015281528151808301835260018152603160f81b6020828101919091528201524691810191909152306060820152620001039062000680565b60015581516200011b90600590602085019062000d97565b5080516200013190600690602084019062000d97565b50505060601b6001600160601b0319166080526001600160a01b038b166200018c5760405163eac0d38960e01b8152602060048201526008602482015267747265617375727960c01b60448201526064015b60405180910390fd5b601480546001600160a01b0319166001600160a01b038d8116919091179091558a16620001ee5760405163eac0d38960e01b815260206004820152600e60248201526d3b393321b7b7b93234b730ba37b960911b604482015260640162000183565b601680546001600160a01b0319166001600160a01b038c1617905561ffff89166200024e57604051630fc3a38f60e41b815260206004820152600e60248201526d6d6178546f74616c537570706c7960901b604482015260640162000183565b6001600160f01b031960f08a901b1660a05261ffff891662000271888a620010dd565b61ffff1610620002db5760405162461bcd60e51b815260206004820152602e60248201527f5469657220537570706c696573206d757374206265206c657373207468616e2060448201526d6d6178546f74616c537570706c7960901b606482015260840162000183565b61ffff88166200032257604051630fc3a38f60e41b815260206004820152601060248201526f676f6c64656e54696572537570706c7960801b604482015260640162000183565b6001600160f01b031960f089901b1660c05261ffff87166200037b57604051630fc3a38f60e41b815260206004820152601060248201526f73696c76657254696572537570706c7960801b604482015260640162000183565b6001600160f01b031960f088901b1660e05261ffff8981169087161115620003d657604051636b6afd1760e11b815260206004820152600c60248201526b7469636b6574537570706c7960a01b604482015260640162000183565b6001600160f01b031960f087901b1661010052600d8590556001600160601b0384166200043457604051630fc3a38f60e41b815260206004820152600a602482015269726f79616c747946656560b01b604482015260640162000183565b620004408b856200071e565b826200047857604051630fc3a38f60e41b8152602060048201526005602482015264707269636560d81b604482015260640162000183565b600f839055604080518082019091526001808252602f60f81b602090920182905282518392918391620004ac919062001121565b81518110620004cb57634e487b7160e01b600052603260045260246000fd5b01602001517fff0000000000000000000000000000000000000000000000000000000000000016146200053257604051636b6afd1760e11b815260206004820152600d60248201526c756e72657665616c656455524960981b604482015260640162000183565b81516200054790601190602085019062000d97565b50825162000587576040516318a996bb60e21b815260206004820152600b60248201526a636f6e747261637455524960a81b604482015260640162000183565b82516200059c90601390602086019062000d97565b5060108054600a61ffff199091161790556000620005c7600c6200081f602090811b62002e8b17901c565b9050620005d5338262000823565b620005ec600c6200084960201b62002e8f1760201c565b336000908152600b6020526040812060019081018054919290916200061390849062001106565b90915550620011d39d5050505050505050505050505050565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82600001518051906020012083602001518051906020012084604001518560600151604051602001620007019594939291909485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b604051602081830303815290604052805190602001209050919050565b6127106001600160601b03821611156200078e5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b606482015260840162000183565b6001600160a01b038216620007e65760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640162000183565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600355565b5490565b620008458282604051806020016040528060008152506200085260201b60201c565b5050565b80546001019055565b6200085e8383620008ca565b6200086d600084848462000a20565b620008c55760405162461bcd60e51b81526020600482015260326024820152600080516020620060ee83398151915260448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606482015260840162000183565b505050565b6001600160a01b038216620009225760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640162000183565b6000818152600760205260409020546001600160a01b031615620009895760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640162000183565b620009976000838362000b89565b6001600160a01b0382166000908152600860205260408120805460019290620009c290849062001106565b909155505060008181526007602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b600062000a41846001600160a01b031662000cff60201b62002e981760201c565b1562000b7d57604051630a85bd0160e11b81526001600160a01b0385169063150b7a029062000a7b90339089908890889060040162001087565b602060405180830381600087803b15801562000a9657600080fd5b505af192505050801562000ac9575060408051601f3d908101601f1916820190925262000ac69181019062001044565b60015b62000b62573d80801562000afa576040519150601f19603f3d011682016040523d82523d6000602084013e62000aff565b606091505b50805162000b5a5760405162461bcd60e51b81526020600482015260326024820152600080516020620060ee83398151915260448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606482015260840162000183565b805181602001fd5b6001600160e01b031916630a85bd0160e11b14905062000b81565b5060015b949350505050565b6015546001600160a01b031615620008c55760155460408051632c77ddfd60e01b815290516000926001600160a01b031691632c77ddfd916004808301926020929190829003018186803b15801562000be157600080fd5b505afa15801562000bf6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c1c91906200106e565b9050804210801562000caa575060155460405163927e603d60e01b81526001600160a01b0386811660048301529091169063927e603d9060240160206040518083038186803b15801562000c6f57600080fd5b505afa15801562000c84573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000caa91906200101b565b801562000cc1575062000cbd8462000d0e565b6001145b1562000cf9576040516365e7520f60e01b81526001600160a01b03851660048201524260248201526044810182905260640162000183565b50505050565b6001600160a01b03163b151590565b60006001600160a01b03821662000d7b5760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b606482015260840162000183565b506001600160a01b031660009081526008602052604090205490565b82805462000da5906200116a565b90600052602060002090601f01602090048101928262000dc9576000855562000e14565b82601f1062000de457805160ff191683800117855562000e14565b8280016001018555821562000e14579182015b8281111562000e1457825182559160200191906001019062000df7565b5062000e2292915062000e26565b5090565b5b8082111562000e22576000815560010162000e27565b80516001600160a01b038116811462000e5557600080fd5b919050565b600082601f83011262000e6b578081fd5b81516001600160401b038082111562000e885762000e88620011bd565b604051601f8301601f19908116603f0116810190828211818310171562000eb35762000eb3620011bd565b8160405283815286602085880101111562000ecc578485fd5b62000edf8460208301602089016200113b565b9695505050505050565b805161ffff8116811462000e5557600080fd5b80516001600160601b038116811462000e5557600080fd5b60008060008060008060008060008060006101608c8e03121562000f36578687fd5b62000f418c62000e3d565b9a5062000f5160208d0162000e3d565b995062000f6160408d0162000ee9565b985062000f7160608d0162000ee9565b975062000f8160808d0162000ee9565b965062000f9160a08d0162000ee9565b955060c08c0151945062000fa860e08d0162000efc565b6101008d01516101208e015191955093506001600160401b0381111562000fcd578283fd5b62000fdb8e828f0162000e5a565b6101408e015190935090506001600160401b0381111562000ffa578182fd5b620010088e828f0162000e5a565b9150509295989b509295989b9093969950565b6000602082840312156200102d578081fd5b815180151581146200103d578182fd5b9392505050565b60006020828403121562001056578081fd5b81516001600160e01b0319811681146200103d578182fd5b60006020828403121562001080578081fd5b5051919050565b600060018060a01b038087168352808616602084015250836040830152608060608301528251806080840152620010c68160a08501602087016200113b565b601f01601f19169190910160a00195945050505050565b600061ffff808316818516808303821115620010fd57620010fd620011a7565b01949350505050565b600082198211156200111c576200111c620011a7565b500190565b600082821015620011365762001136620011a7565b500390565b60005b83811015620011585781810151838201526020016200113e565b8381111562000cf95750506000910152565b600181811c908216806200117f57607f821691505b60208210811415620011a157634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60805160601c60a05160f01c60c05160f01c60e05160f01c6101005160f01c614e8f6200125f6000396000818161065d0152611fb8015260008181610878015261236601526000818161094e015261220301526000818161052901528181611f3b01528181612186015281816127070152613886015260008181610e9c0152610ef70152614e8f6000f3fe6080604052600436106103975760003560e01c8063938e3d7b116101dc578063c6ee20d211610102578063e985e9c5116100a0578063f56153921161006f578063f561539214610ad9578063faf6f4a714610af9578063fe2c7fee14610b0f578063ff9d21f014610b2f57600080fd5b8063e985e9c514610a30578063f0f4426014610a79578063f2fde38b14610a99578063f4f5457214610ab957600080fd5b8063d0bb2189116100dc578063d0bb2189146109c5578063d3381438146109db578063e59af732146109fb578063e8a3d48514610a1b57600080fd5b8063c6ee20d214610970578063c788839b14610992578063c87b56dd146109a557600080fd5b8063ae51dace1161017a578063b882ac9611610149578063b882ac96146108f0578063b88d4fde14610906578063ba11509414610926578063c5b6cc121461093c57600080fd5b8063ae51dace14610866578063b27f8ddc1461089a578063b393391b146108b0578063b4332f32146108d057600080fd5b8063a035b1fe116101b6578063a035b1fe146107f9578063a22cb4651461080f578063a487bcd81461082f578063ad6e30c21461085157600080fd5b8063938e3d7b146107ad57806395d89b41146107cd57806398bdf6f5146107e257600080fd5b806340dd7320116102c15780636966f3a91161025f57806376d5862c1161022e57806376d5862c1461073457806379984efc146107545780638da5cb5b1461076f57806391b7f5ed1461078d57600080fd5b80636966f3a9146106bf5780636ade389b146106df57806370a08231146106ff578063715018a61461071f57600080fd5b80635d62e4681161029b5780635d62e4681461062b5780635d83c2b81461064b57806361d027b31461067f5780636352211e1461069f57600080fd5b806340dd7320146105cb57806342842e0e146105eb578063521331991461060b57600080fd5b806323b872dd1161033957806331faafb41161030857806331faafb41461055e5780633c893ecb1461057e5780633cef28d2146105945780633f3ac92c146105b457600080fd5b806323b872dd146104b057806326092b83146104d05780632a55205a146104d85780632ab4d0521461051757600080fd5b8063095ea7b311610375578063095ea7b31461042b57806318160ddd1461044d5780631d575cf5146104705780631fe543e31461049057600080fd5b806301ffc9a71461039c57806306fdde03146103d1578063081812fc146103f3575b600080fd5b3480156103a857600080fd5b506103bc6103b7366004614756565b610b4f565b60405190151581526020015b60405180910390f35b3480156103dd57600080fd5b506103e6610b93565b6040516103c89190614bd1565b3480156103ff57600080fd5b5061041361040e3660046148a8565b610c25565b6040516001600160a01b0390911681526020016103c8565b34801561043757600080fd5b5061044b61044636600461470f565b610cbf565b005b34801561045957600080fd5b50610462610df1565b6040519081526020016103c8565b34801561047c57600080fd5b5061046261048b3660046146df565b610e01565b34801561049c57600080fd5b5061044b6104ab3660046148d8565b610e91565b3480156104bc57600080fd5b5061044b6104cb3660046145f5565b610f32565b61044b610fb9565b3480156104e457600080fd5b506104f86104f336600461498c565b611080565b604080516001600160a01b0390931683526020830191909152016103c8565b34801561052357600080fd5b5061054b7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff90911681526020016103c8565b34801561056a57600080fd5b5061044b610579366004614a02565b61113b565b34801561058a57600080fd5b5061046260185481565b3480156105a057600080fd5b506104626105af3660046145a1565b6111dd565b3480156105c057600080fd5b50601a5415156103bc565b3480156105d757600080fd5b5061044b6105e63660046149ad565b611230565b3480156105f757600080fd5b5061044b6106063660046145f5565b611414565b34801561061757600080fd5b5061054b6106263660046148a8565b61142f565b34801561063757600080fd5b5061044b6106463660046147ad565b6114d6565b34801561065757600080fd5b5061054b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561068b57600080fd5b50601454610413906001600160a01b031681565b3480156106ab57600080fd5b506104136106ba3660046148a8565b611693565b3480156106cb57600080fd5b5061044b6106da3660046148a8565b61171e565b3480156106eb57600080fd5b5061044b6106fa3660046145a1565b61188b565b34801561070b57600080fd5b5061046261071a3660046145a1565b611b09565b34801561072b57600080fd5b5061044b611ba3565b34801561074057600080fd5b5061044b61074f36600461488e565b611bf7565b34801561076057600080fd5b5060105461054b9061ffff1681565b34801561077b57600080fd5b506000546001600160a01b0316610413565b34801561079957600080fd5b5061044b6107a83660046148a8565b611ceb565b3480156107b957600080fd5b5061044b6107c83660046147ad565b611dc2565b3480156107d957600080fd5b506103e6611ebf565b3480156107ee57600080fd5b50600c546104629081565b34801561080557600080fd5b50610462600f5481565b34801561081b57600080fd5b5061044b61082a3660046146b2565b611ece565b34801561083b57600080fd5b50610844611ed9565b6040516103c89190614b60565b34801561085d57600080fd5b5061084461212a565b34801561087257600080fd5b5061054b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156108a657600080fd5b50610462600d5481565b3480156108bc57600080fd5b50601554610413906001600160a01b031681565b3480156108dc57600080fd5b5061044b6108eb3660046148a8565b6124c3565b3480156108fc57600080fd5b5061046260195481565b34801561091257600080fd5b5061044b610921366004614635565b61263d565b34801561093257600080fd5b50610462600e5481565b34801561094857600080fd5b5061054b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561097c57600080fd5b506109856126cb565b6040516103c89190614ba8565b61044b6109a03660046147f3565b61279c565b3480156109b157600080fd5b506103e66109c03660046148a8565b61280b565b3480156109d157600080fd5b50610462601a5481565b3480156109e757600080fd5b5061044b6109f63660046145a1565b612890565b348015610a0757600080fd5b50601654610413906001600160a01b031681565b348015610a2757600080fd5b506103e66128e1565b348015610a3c57600080fd5b506103bc610a4b3660046145bd565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b348015610a8557600080fd5b5061044b610a943660046145a1565b61296f565b348015610aa557600080fd5b5061044b610ab43660046145a1565b612a90565b348015610ac557600080fd5b506010546103bc9062010000900460ff1681565b348015610ae557600080fd5b50600254610413906001600160a01b031681565b348015610b0557600080fd5b5061046260175481565b348015610b1b57600080fd5b5061044b610b2a3660046147ad565b612b5d565b348015610b3b57600080fd5b5061044b610b4a3660046149ad565b612cb2565b60006001600160e01b031982167fb75e1f9f000000000000000000000000000000000000000000000000000000001480610b8d5750610b8d82612ea7565b92915050565b606060058054610ba290614d39565b80601f0160208091040260200160405190810160405280929190818152602001828054610bce90614d39565b8015610c1b5780601f10610bf057610100808354040283529160200191610c1b565b820191906000526020600020905b815481529060010190602001808311610bfe57829003601f168201915b5050505050905090565b6000818152600760205260408120546001600160a01b0316610ca35760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600960205260409020546001600160a01b031690565b6000610cca82611693565b9050806001600160a01b0316836001600160a01b03161415610d545760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610c9a565b336001600160a01b0382161480610d705750610d708133610a4b565b610de25760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610c9a565b610dec8383612eb2565b505050565b6000610dfc600c5490565b905090565b60006001600160a01b038316610e2a5760405163331715f760e11b815260040160405180910390fd5b6000826001811115610e4c57634e487b7160e01b600052602160045260246000fd5b1415610e7457506001600160a01b0382166000908152600b6020526040902060010154610b8d565b50506001600160a01b03166000908152600b602052604090205490565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f24576040517f1cf993f40000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166024820152604401610c9a565b610f2e8282612f20565b5050565b610f3c3382613094565b610fae5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610c9a565b610dec83838361318b565b600280610fc46126cb565b6006811115610fe357634e487b7160e01b600052602160045260246000fd5b1461102557610ff06126cb565b816040517ff975326c000000000000000000000000000000000000000000000000000000008152600401610c9a929190614bb6565b601054336000908152600b602052604090205461ffff9091161161107157336000908152600b602052604090819020549051631ebf81cf60e21b81526004810191909152602401610c9a565b61107d33346001613363565b50565b60008281526004602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046bffffffffffffffffffffffff169282019290925282916110ff5750604080518082019091526003546001600160a01b0381168252600160a01b90046bffffffffffffffffffffffff1660208201525b602081015160009061271090611123906bffffffffffffffffffffffff1687614cd7565b61112d9190614cc3565b915196919550909350505050565b6000546001600160a01b031633146111835760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b601454611199906001600160a01b0316826134fc565b6040516bffffffffffffffffffffffff821681527ff4220e27e94f63cac283717e73a4c580428428bc7149f113d01665ea64d6718f9060200160405180910390a150565b60006001600160a01b0382166112065760405163331715f760e11b815260040160405180910390fd5b6001600160a01b0382166000908152600b602052604090208054600190910154610b8d9190614cab565b6000546001600160a01b031633146112785760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6003806112836126cb565b60068111156112a257634e487b7160e01b600052602160045260246000fd5b10156112b057610ff06126cb565b601854156112d1576040516311cfd2ad60e01b815260040160405180910390fd5b619c408263ffffffff16101561132a57604051636b6afd1760e11b815260206004820152601060248201527f63616c6c6261636b4761734c696d6974000000000000000000000000000000006044820152606401610c9a565b6016546040516305d3b1d360e41b81526004810185905267ffffffffffffffff861660248201526003604482015263ffffffff84166064820152600160848201526001600160a01b03909116908190635d3b1d309060a401602060405180830381600087803b15801561139c57600080fd5b505af11580156113b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d491906148c0565b60178190556040519081527f2a88d24fc50b57dbdb005dcfbcaa7b17a93129c4c00f6e1743023f0091cde801906020015b60405180910390a15050505050565b610dec8383836040518060200160405280600081525061263d565b600060048061143c6126cb565b600681111561145b57634e487b7160e01b600052602160045260246000fd5b101561146957610ff06126cb565b6000838152600760205260409020546001600160a01b031661149e57604051634a1850bf60e11b815260040160405180910390fd5b6114a661212a565b83815181106114c557634e487b7160e01b600052603260045260246000fd5b602002602001015191505b50919050565b6000546001600160a01b0316331461151e5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6004806115296126cb565b600681111561154857634e487b7160e01b600052602160045260246000fd5b101561155657610ff06126cb565b60105462010000900460ff16156115805760405163ba4ace8d60e01b815260040160405180910390fd5b604080518082019091526001808252602f60f81b6020909201829052835184929183916115ad9190614cf6565b815181106115cb57634e487b7160e01b600052603260045260246000fd5b01602001517fff00000000000000000000000000000000000000000000000000000000000000161461164057604051636b6afd1760e11b815260206004820152600b60248201527f72657665616c65645552490000000000000000000000000000000000000000006044820152606401610c9a565b82516116539060129060208601906144a2565b506010805462ff00001916620100001790556040517f1e4137ab05aad9af97415bad5605b301d36fbc9eb3f28e0753d4d819c565f87b90600090a1505050565b6000818152600760205260408120546001600160a01b031680610b8d5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610c9a565b6000546001600160a01b031633146117665760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b60026000611775600183614cf6565b600681111561179457634e487b7160e01b600052602160045260246000fd5b90508160068111156117b657634e487b7160e01b600052602160045260246000fd5b6117be6126cb565b60068111156117dd57634e487b7160e01b600052602160045260246000fd5b106117ea57610ff06126cb565b600d54831080156117fa57508215155b1561184857604051636b6afd1760e11b815260206004820152601660248201527f7075626c69634d696e74696e6754696d657374616d70000000000000000000006044820152606401610c9a565b600e5460408051918252602082018590527f0bb04c825da052df0301d5b2b1292d51aa85c2d379b4c4d03f2d998ad2c57a86910160405180910390a15050600e55565b6000546001600160a01b031633146118d35760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6040516301ffc9a760e01b81527f89a32daf0000000000000000000000000000000000000000000000000000000060048201819052906001600160a01b038316906301ffc9a79060240160206040518083038186803b15801561193557600080fd5b505afa158015611949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196d919061473a565b6119ba57604051636b6afd1760e11b815260206004820152600a60248201527f7469636b65744e46545f000000000000000000000000000000000000000000006044820152606401610c9a565b6015546001600160a01b031615611a9f57601554604080517fc6ee20d200000000000000000000000000000000000000000000000000000000815290516001926001600160a01b03169163c6ee20d2916004808301926020929190829003018186803b158015611a2957600080fd5b505afa158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a61919061478e565b6005811115611a8057634e487b7160e01b600052602160045260246000fd5b1115611a9f576040516311cfd2ad60e01b815260040160405180910390fd5b601554604080516001600160a01b03928316815291841660208301527fecb905e703386325d99f190a7cac2df474bcefe4e4d59a55a8c2798047aeba13910160405180910390a150601580546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038216611b875760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610c9a565b506001600160a01b031660009081526008602052604090205490565b6000546001600160a01b03163314611beb5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b611bf56000613616565b565b6000546001600160a01b03163314611c3f5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b61ffff8116611c9157604051630fc3a38f60e41b815260206004820152601160248201527f6d61785075626c69634d696e7461626c650000000000000000000000000000006044820152606401610c9a565b6010546040805161ffff928316815291831660208301527fb8d7b99ec4233306f8a0b1f89da0eaebba724b9fbe56261e064e9a6bc31e2bbc910160405180910390a16010805461ffff191661ffff92909216919091179055565b6000546001600160a01b03163314611d335760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b80611d8157604051630fc3a38f60e41b815260206004820152600560248201527f70726963650000000000000000000000000000000000000000000000000000006044820152606401610c9a565b600f5460408051918252602082018390527fa0f1665b7b659537b52deec61ea64d134a3bccda74c7f4e79f2246e7a8187a8a910160405180910390a1600f55565b6000546001600160a01b03163314611e0a5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b8051611e72576040517f62a65aec00000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f636f6e74726163745552490000000000000000000000000000000000000000006044820152606401610c9a565b7fd144c5914915e649557dfce6d3199a18bae1ec7c249c1766603a2b76ade11c06601382604051611ea4929190614be4565b60405180910390a18051610f2e9060139060208401906144a2565b606060068054610ba290614d39565b610f2e338383613666565b6060600680611ee66126cb565b6006811115611f0557634e487b7160e01b600052602160045260246000fd5b1015611f1357610ff06126cb565b600060649050600080611f35601a54848480611f2e90614d6e565b9550613735565b905060007f000000000000000000000000000000000000000000000000000000000000000061ffff1667ffffffffffffffff811115611f8457634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611fad578160200160208202803683370190505b50905060008060005b7f000000000000000000000000000000000000000000000000000000000000000061ffff1681101561211c578483611fed81614d6e565b94508151811061200d57634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156120435761203c601a5488888061203590614d6e565b9950613735565b9450600092505b83828151811061206357634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff166000146120d557848361208181614d6e565b9450815181106120a157634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156120d0576120c9601a5488888061203590614d6e565b9450600092505b612043565b60018483815181106120f757634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101528061211481614d6e565b915050611fb6565b5091965050505050505b5090565b60606004806121376126cb565b600681111561215657634e487b7160e01b600052602160045260246000fd5b101561216457610ff06126cb565b60006101f49050600080612180601854848480611f2e90614d6e565b905060007f000000000000000000000000000000000000000000000000000000000000000061ffff1667ffffffffffffffff8111156121cf57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156121f8578160200160208202803683370190505b50905060008060005b7f000000000000000000000000000000000000000000000000000000000000000061ffff1681101561236057848361223881614d6e565b94508151811061225857634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156122875761228060185488888061203590614d6e565b9450600092505b8382815181106122a757634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff166000146123195784836122c581614d6e565b9450815181106122e557634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156123145761230d60185488888061203590614d6e565b9450600092505b612287565b600284838151811061233b57634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101528061235881614d6e565b915050612201565b5060005b7f000000000000000000000000000000000000000000000000000000000000000061ffff1681101561211c57848361239b81614d6e565b9450815181106123bb57634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156123ea576123e360185488888061203590614d6e565b9450600092505b83828151811061240a57634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff1660001461247c57848361242881614d6e565b94508151811061244857634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156124775761247060185488888061203590614d6e565b9450600092505b6123ea565b600184838151811061249e57634e487b7160e01b600052603260045260246000fd5b61ffff90921660209283029190910190910152806124bb81614d6e565b915050612364565b6000546001600160a01b0316331461250b5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b600160006125198280614cf6565b600681111561253857634e487b7160e01b600052602160045260246000fd5b905081600681111561255a57634e487b7160e01b600052602160045260246000fd5b6125626126cb565b600681111561258157634e487b7160e01b600052602160045260246000fd5b1061258e57610ff06126cb565b600e54831015801561259f57508215155b80156125ac5750600e5415155b156125fa57604051636b6afd1760e11b815260206004820152601760248201527f707269766174654d696e74696e6754696d657374616d700000000000000000006044820152606401610c9a565b600d5460408051918252602082018590527fb49b0d2203b2bce8f0c1930d69dabfc245275b5ec32dc6f328806e33a4d71581910160405180910390a15050600d55565b6126473383613094565b6126b95760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610c9a565b6126c584848484613939565b50505050565b6000601a546000146126dd5750600690565b60105462010000900460ff16156126f45750600590565b601854156127025750600490565b600c547f000000000000000000000000000000000000000000000000000000000000000061ffff1614156127365750600390565b600d5442101580156127495750600d5415155b80156127605750600e544210806127605750600e54155b1561276b5750600190565b600e54421015801561277e5750600e5415155b801561278b5750600d5415155b156127965750600290565b50600090565b6001806127a76126cb565b60068111156127c657634e487b7160e01b600052602160045260246000fd5b146127d357610ff06126cb565b336000818152600b60205260409020600101546127ff91906127fa36869003860186614804565b6139b7565b610f2e33346000613363565b6000818152600760205260409020546060906001600160a01b031661284357604051634a1850bf60e11b815260040160405180910390fd5b60105462010000900460ff1661288557601161285e83613adc565b60405160200161286f929190614a7c565b6040516020818303038152906040529050919050565b601261285e83613adc565b6000546001600160a01b031633146128d85760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b61107d81613c2a565b601380546128ee90614d39565b80601f016020809104026020016040519081016040528092919081815260200182805461291a90614d39565b80156129675780601f1061293c57610100808354040283529160200191612967565b820191906000526020600020905b81548152906001019060200180831161294a57829003601f168201915b505050505081565b6000546001600160a01b031633146129b75760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6001600160a01b038116612a27576040517feac0d38900000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f74726561737572790000000000000000000000000000000000000000000000006044820152606401610c9a565b601454604080516001600160a01b03928316815291831660208301527f21eb548722a564f6e09f039f7aa858ae94c911910f3823b37af2250eeca4f403910160405180910390a1601480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314612ad85760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6001600160a01b038116612b545760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c9a565b61107d81613616565b6000546001600160a01b03163314612ba55760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b604080518082019091526001808252602f60f81b602090920182905282518392918391612bd29190614cf6565b81518110612bf057634e487b7160e01b600052603260045260246000fd5b01602001517fff000000000000000000000000000000000000000000000000000000000000001614612c6557604051636b6afd1760e11b815260206004820152600d60248201527f756e72657665616c6564555249000000000000000000000000000000000000006044820152606401610c9a565b7f8191e07a9f461509729f31da9b0bb812915c3252f697cbf19fc60a700c14e379601183604051612c97929190614be4565b60405180910390a18151610dec9060119060208501906144a2565b6000546001600160a01b03163314612cfa5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b600380612d056126cb565b6006811115612d2457634e487b7160e01b600052602160045260246000fd5b1015612d3257610ff06126cb565b601a5415612d53576040516311cfd2ad60e01b815260040160405180910390fd5b619c408263ffffffff161015612dac57604051636b6afd1760e11b815260206004820152601060248201527f63616c6c6261636b4761734c696d6974000000000000000000000000000000006044820152606401610c9a565b6016546040516305d3b1d360e41b81526004810185905267ffffffffffffffff861660248201526003604482015263ffffffff84166064820152600160848201526001600160a01b03909116908190635d3b1d309060a401602060405180830381600087803b158015612e1e57600080fd5b505af1158015612e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5691906148c0565b60198190556040519081527f386f7e0e864241c7e92166f1441c88d40259979d0d6fe045ae15c5e0011c7a7290602001611405565b5490565b80546001019055565b6001600160a01b03163b151590565b6000610b8d82613cba565b600081815260096020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612ee782611693565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b81612f6e57604051630fc3a38f60e41b815260206004820152600960248201527f72657175657374496400000000000000000000000000000000000000000000006044820152606401610c9a565b6017548214156130075760185415612f995760405163ba4ace8d60e01b815260040160405180910390fd5b80600081518110612fba57634e487b7160e01b600052603260045260246000fd5b60200260200101516018819055507f260b0d780ce5d3acea4dbce31d432406bb72fea1d4b7e2571b4558445a45c8d6601854604051612ffb91815260200190565b60405180910390a15050565b601954821415610f2e57601a54156130325760405163ba4ace8d60e01b815260040160405180910390fd5b8060008151811061305357634e487b7160e01b600052603260045260246000fd5b6020026020010151601a819055507f1acc627535151d4af646035fc4bc45bb7f1f35139d354287404bd6a074bfaf69601a54604051612ffb91815260200190565b6000818152600760205260408120546001600160a01b031661310d5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610c9a565b600061311883611693565b9050806001600160a01b0316846001600160a01b0316148061315f57506001600160a01b038082166000908152600a602090815260408083209388168352929052205460ff165b806131835750836001600160a01b031661317884610c25565b6001600160a01b0316145b949350505050565b826001600160a01b031661319e82611693565b6001600160a01b03161461321a5760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152608401610c9a565b6001600160a01b0382166132955760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610c9a565b6132a0838383613d2c565b6132ab600082612eb2565b6001600160a01b03831660009081526008602052604081208054600192906132d4908490614cf6565b90915550506001600160a01b0382166000908152600860205260408120805460019290613302908490614cab565b909155505060008181526007602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60036000613372600183614cf6565b600681111561339157634e487b7160e01b600052602160045260246000fd5b90508160068111156133b357634e487b7160e01b600052602160045260246000fd5b6133bb6126cb565b60068111156133da57634e487b7160e01b600052602160045260246000fd5b106133e757610ff06126cb565b600f54841461343957604051636b6afd1760e11b815260206004820152600a60248201527f616d6f756e7450616964000000000000000000000000000000000000000000006044820152606401610c9a565b6000613444600c5490565b90506134508686613ed8565b61345e600c80546001019055565b83600181111561347e57634e487b7160e01b600052602160045260246000fd5b6134bb576001600160a01b0386166000908152600b6020526040812060019081018054919290916134b0908490614cab565b909155506134ea9050565b6001600160a01b0386166000908152600b602052604081208054600192906134e4908490614cab565b90915550505b6134f48682613fc3565b505050505050565b6127106bffffffffffffffffffffffff821611156135825760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c2065786365656460448201527f2073616c655072696365000000000000000000000000000000000000000000006064820152608401610c9a565b6001600160a01b0382166135d85760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610c9a565b604080518082019091526001600160a01b039092168083526bffffffffffffffffffffffff9091166020909201829052600160a01b90910217600355565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b816001600160a01b0316836001600160a01b031614156136c85760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610c9a565b6001600160a01b038381166000818152600a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60608361378557604051630fc3a38f60e41b815260206004820152600a60248201527f72616e646f6d576f7264000000000000000000000000000000000000000000006044820152606401610c9a565b61ffff6000613795601086614cc3565b905060006137a4601087614daa565b11156137b8576137b5600182614cab565b90505b60006137c48286614cd7565b6137cf906010614cd7565b905060006137de836010614cd7565b67ffffffffffffffff81111561380457634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561382d578160200160208202803683370190505b50905060005b8381101561392b576000896138488584614cab565b6040805160208101939093528201526060016040516020818303038152906040528051906020012060001c905060005b6010811015613916576138ad7f0000000000000000000000000000000000000000000000000000000000000000838916614d89565b84826138ba866010614cd7565b6138c49190614cab565b815181106138e257634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101526139026201000083614cc3565b91508061390e81614d6e565b915050613878565b5050808061392390614d6e565b915050613833565b5093505050505b9392505050565b61394484848461318b565b61395084848484613fdd565b6126c55760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610c9a565b6002546001600160a01b03166139e05760405163a75e096760e01b815260040160405180910390fd5b826001600160a01b031681600001516001600160a01b031614613a455780516040517ff1a669ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301529091166024820152604401610c9a565b81816020015161ffff1611613a7057604051631ebf81cf60e21b815260048101839052602401610c9a565b6000613a7b82614135565b6002549091506001600160a01b038083169116146126c5576002546040517f6cd82d240000000000000000000000000000000000000000000000000000000081526001600160a01b0380841660048301529091166024820152604401610c9a565b606081613b1c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115613b465780613b3081614d6e565b9150613b3f9050600a83614cc3565b9150613b20565b60008167ffffffffffffffff811115613b6f57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613b99576020820181803683370190505b5090505b841561318357613bae600183614cf6565b9150613bbb600a86614daa565b613bc6906030614cab565b60f81b818381518110613be957634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613c23600a86614cc3565b9450613b9d565b6001600160a01b038116613c515760405163a75e096760e01b815260040160405180910390fd5b600254604080516001600160a01b03928316815291831660208301527f9fed3c0e42aa7f73947a13ac6757a3d73c8f820c1c1d45bfdb2a3f9d3f812a07910160405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480613d1d57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610b8d5750610b8d82614211565b6015546001600160a01b031615610dec57601554604080517f2c77ddfd00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691632c77ddfd916004808301926020929190829003018186803b158015613d9b57600080fd5b505afa158015613daf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dd391906148c0565b90508042108015613e7557506015546040517f927e603d0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301529091169063927e603d9060240160206040518083038186803b158015613e3d57600080fd5b505afa158015613e51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e75919061473a565b8015613e895750613e8584611b09565b6001145b156126c5576040517f65e7520f0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015242602482015260448101829052606401610c9a565b6014546040516000916001600160a01b03169083908381818185875af1925050503d8060008114613f25576040519150601f19603f3d011682016040523d82523d6000602084013e613f2a565b606091505b5050905080613f7b5760405162461bcd60e51b815260206004820152601660248201527f436f756c64206e6f7420706179207472656173757279000000000000000000006044820152606401610c9a565b826001600160a01b03167fb5668d929317b36d7b61952ab446b7e4dd82c4d9f90788b407c35e90440f567883604051613fb691815260200190565b60405180910390a2505050565b610f2e82826040518060200160405280600081525061425f565b60006001600160a01b0384163b1561412a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614021903390899088908890600401614b24565b602060405180830381600087803b15801561403b57600080fd5b505af192505050801561406b575060408051601f3d908101601f1916820190925261406891810190614772565b60015b614110573d808015614099576040519150601f19603f3d011682016040523d82523d6000602084013e61409e565b606091505b5080516141085760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610c9a565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050613183565b506001949350505050565b600080600154614144846142dd565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101929092526042820152606201604051602081830303815290604052805190602001209050600181846040015185606001518660800151604051600081526020016040526040516141dd949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156141ff573d6000803e3d6000fd5b5050604051601f190151949350505050565b60006001600160e01b031982167f2a55205a000000000000000000000000000000000000000000000000000000001480610b8d57506301ffc9a760e01b6001600160e01b0319831614610b8d565b6142698383614354565b6142766000848484613fdd565b610dec5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610c9a565b8051602080830151604051600093614337937f9016184a70237a58286b5c611a44cf3c4b67b9ec2da552661f6a04c1395282d5939192019283526001600160a01b0391909116602083015261ffff16604082015260600190565b604051602081830303815290604052805190602001209050919050565b6001600160a01b0382166143aa5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610c9a565b6000818152600760205260409020546001600160a01b03161561440f5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610c9a565b61441b60008383613d2c565b6001600160a01b0382166000908152600860205260408120805460019290614444908490614cab565b909155505060008181526007602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b8280546144ae90614d39565b90600052602060002090601f0160209004810192826144d05760008555614516565b82601f106144e957805160ff1916838001178555614516565b82800160010185558215614516579182015b828111156145165782518255916020019190600101906144fb565b506121269291505b80821115612126576000815560010161451e565b600067ffffffffffffffff83111561454c5761454c614dea565b61455f601f8401601f1916602001614c7a565b905082815283838301111561457357600080fd5b828260208301376000602084830101529392505050565b803561ffff8116811461459c57600080fd5b919050565b6000602082840312156145b2578081fd5b813561393281614e00565b600080604083850312156145cf578081fd5b82356145da81614e00565b915060208301356145ea81614e00565b809150509250929050565b600080600060608486031215614609578081fd5b833561461481614e00565b9250602084013561462481614e00565b929592945050506040919091013590565b6000806000806080858703121561464a578182fd5b843561465581614e00565b9350602085013561466581614e00565b925060408501359150606085013567ffffffffffffffff811115614687578182fd5b8501601f81018713614697578182fd5b6146a687823560208401614532565b91505092959194509250565b600080604083850312156146c4578182fd5b82356146cf81614e00565b915060208301356145ea81614e15565b600080604083850312156146f1578182fd5b82356146fc81614e00565b91506020830135600281106145ea578182fd5b60008060408385031215614721578182fd5b823561472c81614e00565b946020939093013593505050565b60006020828403121561474b578081fd5b815161393281614e15565b600060208284031215614767578081fd5b813561393281614e23565b600060208284031215614783578081fd5b815161393281614e23565b60006020828403121561479f578081fd5b815160068110613932578182fd5b6000602082840312156147be578081fd5b813567ffffffffffffffff8111156147d4578182fd5b8201601f810184136147e4578182fd5b61318384823560208401614532565b600060a082840312156114d0578081fd5b600060a08284031215614815578081fd5b60405160a0810181811067ffffffffffffffff8211171561483857614838614dea565b604052823561484681614e00565b81526148546020840161458a565b6020820152604083013560ff8116811461486c578283fd5b6040820152606083810135908201526080928301359281019290925250919050565b60006020828403121561489f578081fd5b6139328261458a565b6000602082840312156148b9578081fd5b5035919050565b6000602082840312156148d1578081fd5b5051919050565b600080604083850312156148ea578182fd5b8235915060208084013567ffffffffffffffff80821115614909578384fd5b818601915086601f83011261491c578384fd5b81358181111561492e5761492e614dea565b8060051b915061493f848301614c7a565b8181528481019084860184860187018b1015614959578788fd5b8795505b8386101561497b57803583526001959095019491860191860161495d565b508096505050505050509250929050565b6000806040838503121561499e578182fd5b50508035926020909101359150565b6000806000606084860312156149c1578081fd5b833567ffffffffffffffff811681146149d8578182fd5b925060208401359150604084013563ffffffff811681146149f7578182fd5b809150509250925092565b600060208284031215614a13578081fd5b81356bffffffffffffffffffffffff81168114613932578182fd5b60008151808452614a46816020860160208601614d0d565b601f01601f19169290920160200192915050565b60078110614a7857634e487b7160e01b600052602160045260246000fd5b9052565b6000808454614a8a81614d39565b60018281168015614aa25760018114614ab357614adf565b60ff19841687528287019450614adf565b8886526020808720875b85811015614ad65781548a820152908401908201614abd565b50505082870194505b505050508351614af3818360208801614d0d565b7f2e6a736f6e0000000000000000000000000000000000000000000000000000009101908152600501949350505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614b566080830184614a2e565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015614b9c57835161ffff1683529284019291840191600101614b7c565b50909695505050505050565b60208101610b8d8284614a5a565b60408101614bc48285614a5a565b6139326020830184614a5a565b6020815260006139326020830184614a2e565b604081526000808454614bf681614d39565b8060408601526060600180841660008114614c185760018114614c2c57614c5a565b60ff19851688840152608088019550614c5a565b8987526020808820885b86811015614c515781548b8201870152908401908201614c36565b8a018501975050505b50505050508281036020840152614c718185614a2e565b95945050505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ca357614ca3614dea565b604052919050565b60008219821115614cbe57614cbe614dbe565b500190565b600082614cd257614cd2614dd4565b500490565b6000816000190483118215151615614cf157614cf1614dbe565b500290565b600082821015614d0857614d08614dbe565b500390565b60005b83811015614d28578181015183820152602001614d10565b838111156126c55750506000910152565b600181811c90821680614d4d57607f821691505b602082108114156114d057634e487b7160e01b600052602260045260246000fd5b6000600019821415614d8257614d82614dbe565b5060010190565b600061ffff80841680614d9e57614d9e614dd4565b92169190910692915050565b600082614db957614db9614dd4565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461107d57600080fd5b801515811461107d57600080fd5b6001600160e01b03198116811461107d57600080fdfe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220b3144f75f071b381966b4b44338ff0d329f69549cf83d122078d79f583a3dadc64736f6c634300080400334552433732313a207472616e7366657220746f206e6f6e204552433732315265000000000000000000000000455ad5835b5f732a8c28d0ad79abf7942f586906000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000004e200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000632c403000000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000214e8348c4f0000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f73332e65752d776573742d322e616d617a6f6e6177732e636f6d2f6d617261646f6e616f6666696369616c2e696f2f61636365737350617373436f6e74726163745552492e6a736f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d5a346e696a4e546b5933556a3766327a71766d6b5a57386873344e6e42345878514d35474c7277554a4d52522f00000000000000000000

Deployed Bytecode

0x6080604052600436106103975760003560e01c8063938e3d7b116101dc578063c6ee20d211610102578063e985e9c5116100a0578063f56153921161006f578063f561539214610ad9578063faf6f4a714610af9578063fe2c7fee14610b0f578063ff9d21f014610b2f57600080fd5b8063e985e9c514610a30578063f0f4426014610a79578063f2fde38b14610a99578063f4f5457214610ab957600080fd5b8063d0bb2189116100dc578063d0bb2189146109c5578063d3381438146109db578063e59af732146109fb578063e8a3d48514610a1b57600080fd5b8063c6ee20d214610970578063c788839b14610992578063c87b56dd146109a557600080fd5b8063ae51dace1161017a578063b882ac9611610149578063b882ac96146108f0578063b88d4fde14610906578063ba11509414610926578063c5b6cc121461093c57600080fd5b8063ae51dace14610866578063b27f8ddc1461089a578063b393391b146108b0578063b4332f32146108d057600080fd5b8063a035b1fe116101b6578063a035b1fe146107f9578063a22cb4651461080f578063a487bcd81461082f578063ad6e30c21461085157600080fd5b8063938e3d7b146107ad57806395d89b41146107cd57806398bdf6f5146107e257600080fd5b806340dd7320116102c15780636966f3a91161025f57806376d5862c1161022e57806376d5862c1461073457806379984efc146107545780638da5cb5b1461076f57806391b7f5ed1461078d57600080fd5b80636966f3a9146106bf5780636ade389b146106df57806370a08231146106ff578063715018a61461071f57600080fd5b80635d62e4681161029b5780635d62e4681461062b5780635d83c2b81461064b57806361d027b31461067f5780636352211e1461069f57600080fd5b806340dd7320146105cb57806342842e0e146105eb578063521331991461060b57600080fd5b806323b872dd1161033957806331faafb41161030857806331faafb41461055e5780633c893ecb1461057e5780633cef28d2146105945780633f3ac92c146105b457600080fd5b806323b872dd146104b057806326092b83146104d05780632a55205a146104d85780632ab4d0521461051757600080fd5b8063095ea7b311610375578063095ea7b31461042b57806318160ddd1461044d5780631d575cf5146104705780631fe543e31461049057600080fd5b806301ffc9a71461039c57806306fdde03146103d1578063081812fc146103f3575b600080fd5b3480156103a857600080fd5b506103bc6103b7366004614756565b610b4f565b60405190151581526020015b60405180910390f35b3480156103dd57600080fd5b506103e6610b93565b6040516103c89190614bd1565b3480156103ff57600080fd5b5061041361040e3660046148a8565b610c25565b6040516001600160a01b0390911681526020016103c8565b34801561043757600080fd5b5061044b61044636600461470f565b610cbf565b005b34801561045957600080fd5b50610462610df1565b6040519081526020016103c8565b34801561047c57600080fd5b5061046261048b3660046146df565b610e01565b34801561049c57600080fd5b5061044b6104ab3660046148d8565b610e91565b3480156104bc57600080fd5b5061044b6104cb3660046145f5565b610f32565b61044b610fb9565b3480156104e457600080fd5b506104f86104f336600461498c565b611080565b604080516001600160a01b0390931683526020830191909152016103c8565b34801561052357600080fd5b5061054b7f000000000000000000000000000000000000000000000000000000000000138881565b60405161ffff90911681526020016103c8565b34801561056a57600080fd5b5061044b610579366004614a02565b61113b565b34801561058a57600080fd5b5061046260185481565b3480156105a057600080fd5b506104626105af3660046145a1565b6111dd565b3480156105c057600080fd5b50601a5415156103bc565b3480156105d757600080fd5b5061044b6105e63660046149ad565b611230565b3480156105f757600080fd5b5061044b6106063660046145f5565b611414565b34801561061757600080fd5b5061054b6106263660046148a8565b61142f565b34801561063757600080fd5b5061044b6106463660046147ad565b6114d6565b34801561065757600080fd5b5061054b7f00000000000000000000000000000000000000000000000000000000000001f481565b34801561068b57600080fd5b50601454610413906001600160a01b031681565b3480156106ab57600080fd5b506104136106ba3660046148a8565b611693565b3480156106cb57600080fd5b5061044b6106da3660046148a8565b61171e565b3480156106eb57600080fd5b5061044b6106fa3660046145a1565b61188b565b34801561070b57600080fd5b5061046261071a3660046145a1565b611b09565b34801561072b57600080fd5b5061044b611ba3565b34801561074057600080fd5b5061044b61074f36600461488e565b611bf7565b34801561076057600080fd5b5060105461054b9061ffff1681565b34801561077b57600080fd5b506000546001600160a01b0316610413565b34801561079957600080fd5b5061044b6107a83660046148a8565b611ceb565b3480156107b957600080fd5b5061044b6107c83660046147ad565b611dc2565b3480156107d957600080fd5b506103e6611ebf565b3480156107ee57600080fd5b50600c546104629081565b34801561080557600080fd5b50610462600f5481565b34801561081b57600080fd5b5061044b61082a3660046146b2565b611ece565b34801561083b57600080fd5b50610844611ed9565b6040516103c89190614b60565b34801561085d57600080fd5b5061084461212a565b34801561087257600080fd5b5061054b7f00000000000000000000000000000000000000000000000000000000000004e281565b3480156108a657600080fd5b50610462600d5481565b3480156108bc57600080fd5b50601554610413906001600160a01b031681565b3480156108dc57600080fd5b5061044b6108eb3660046148a8565b6124c3565b3480156108fc57600080fd5b5061046260195481565b34801561091257600080fd5b5061044b610921366004614635565b61263d565b34801561093257600080fd5b50610462600e5481565b34801561094857600080fd5b5061054b7f00000000000000000000000000000000000000000000000000000000000002ee81565b34801561097c57600080fd5b506109856126cb565b6040516103c89190614ba8565b61044b6109a03660046147f3565b61279c565b3480156109b157600080fd5b506103e66109c03660046148a8565b61280b565b3480156109d157600080fd5b50610462601a5481565b3480156109e757600080fd5b5061044b6109f63660046145a1565b612890565b348015610a0757600080fd5b50601654610413906001600160a01b031681565b348015610a2757600080fd5b506103e66128e1565b348015610a3c57600080fd5b506103bc610a4b3660046145bd565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205460ff1690565b348015610a8557600080fd5b5061044b610a943660046145a1565b61296f565b348015610aa557600080fd5b5061044b610ab43660046145a1565b612a90565b348015610ac557600080fd5b506010546103bc9062010000900460ff1681565b348015610ae557600080fd5b50600254610413906001600160a01b031681565b348015610b0557600080fd5b5061046260175481565b348015610b1b57600080fd5b5061044b610b2a3660046147ad565b612b5d565b348015610b3b57600080fd5b5061044b610b4a3660046149ad565b612cb2565b60006001600160e01b031982167fb75e1f9f000000000000000000000000000000000000000000000000000000001480610b8d5750610b8d82612ea7565b92915050565b606060058054610ba290614d39565b80601f0160208091040260200160405190810160405280929190818152602001828054610bce90614d39565b8015610c1b5780601f10610bf057610100808354040283529160200191610c1b565b820191906000526020600020905b815481529060010190602001808311610bfe57829003601f168201915b5050505050905090565b6000818152600760205260408120546001600160a01b0316610ca35760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600960205260409020546001600160a01b031690565b6000610cca82611693565b9050806001600160a01b0316836001600160a01b03161415610d545760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610c9a565b336001600160a01b0382161480610d705750610d708133610a4b565b610de25760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610c9a565b610dec8383612eb2565b505050565b6000610dfc600c5490565b905090565b60006001600160a01b038316610e2a5760405163331715f760e11b815260040160405180910390fd5b6000826001811115610e4c57634e487b7160e01b600052602160045260246000fd5b1415610e7457506001600160a01b0382166000908152600b6020526040902060010154610b8d565b50506001600160a01b03166000908152600b602052604090205490565b336001600160a01b037f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699091614610f24576040517f1cf993f40000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b037f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909166024820152604401610c9a565b610f2e8282612f20565b5050565b610f3c3382613094565b610fae5760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610c9a565b610dec83838361318b565b600280610fc46126cb565b6006811115610fe357634e487b7160e01b600052602160045260246000fd5b1461102557610ff06126cb565b816040517ff975326c000000000000000000000000000000000000000000000000000000008152600401610c9a929190614bb6565b601054336000908152600b602052604090205461ffff9091161161107157336000908152600b602052604090819020549051631ebf81cf60e21b81526004810191909152602401610c9a565b61107d33346001613363565b50565b60008281526004602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046bffffffffffffffffffffffff169282019290925282916110ff5750604080518082019091526003546001600160a01b0381168252600160a01b90046bffffffffffffffffffffffff1660208201525b602081015160009061271090611123906bffffffffffffffffffffffff1687614cd7565b61112d9190614cc3565b915196919550909350505050565b6000546001600160a01b031633146111835760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b601454611199906001600160a01b0316826134fc565b6040516bffffffffffffffffffffffff821681527ff4220e27e94f63cac283717e73a4c580428428bc7149f113d01665ea64d6718f9060200160405180910390a150565b60006001600160a01b0382166112065760405163331715f760e11b815260040160405180910390fd5b6001600160a01b0382166000908152600b602052604090208054600190910154610b8d9190614cab565b6000546001600160a01b031633146112785760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6003806112836126cb565b60068111156112a257634e487b7160e01b600052602160045260246000fd5b10156112b057610ff06126cb565b601854156112d1576040516311cfd2ad60e01b815260040160405180910390fd5b619c408263ffffffff16101561132a57604051636b6afd1760e11b815260206004820152601060248201527f63616c6c6261636b4761734c696d6974000000000000000000000000000000006044820152606401610c9a565b6016546040516305d3b1d360e41b81526004810185905267ffffffffffffffff861660248201526003604482015263ffffffff84166064820152600160848201526001600160a01b03909116908190635d3b1d309060a401602060405180830381600087803b15801561139c57600080fd5b505af11580156113b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d491906148c0565b60178190556040519081527f2a88d24fc50b57dbdb005dcfbcaa7b17a93129c4c00f6e1743023f0091cde801906020015b60405180910390a15050505050565b610dec8383836040518060200160405280600081525061263d565b600060048061143c6126cb565b600681111561145b57634e487b7160e01b600052602160045260246000fd5b101561146957610ff06126cb565b6000838152600760205260409020546001600160a01b031661149e57604051634a1850bf60e11b815260040160405180910390fd5b6114a661212a565b83815181106114c557634e487b7160e01b600052603260045260246000fd5b602002602001015191505b50919050565b6000546001600160a01b0316331461151e5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6004806115296126cb565b600681111561154857634e487b7160e01b600052602160045260246000fd5b101561155657610ff06126cb565b60105462010000900460ff16156115805760405163ba4ace8d60e01b815260040160405180910390fd5b604080518082019091526001808252602f60f81b6020909201829052835184929183916115ad9190614cf6565b815181106115cb57634e487b7160e01b600052603260045260246000fd5b01602001517fff00000000000000000000000000000000000000000000000000000000000000161461164057604051636b6afd1760e11b815260206004820152600b60248201527f72657665616c65645552490000000000000000000000000000000000000000006044820152606401610c9a565b82516116539060129060208601906144a2565b506010805462ff00001916620100001790556040517f1e4137ab05aad9af97415bad5605b301d36fbc9eb3f28e0753d4d819c565f87b90600090a1505050565b6000818152600760205260408120546001600160a01b031680610b8d5760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201527f656e7420746f6b656e00000000000000000000000000000000000000000000006064820152608401610c9a565b6000546001600160a01b031633146117665760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b60026000611775600183614cf6565b600681111561179457634e487b7160e01b600052602160045260246000fd5b90508160068111156117b657634e487b7160e01b600052602160045260246000fd5b6117be6126cb565b60068111156117dd57634e487b7160e01b600052602160045260246000fd5b106117ea57610ff06126cb565b600d54831080156117fa57508215155b1561184857604051636b6afd1760e11b815260206004820152601660248201527f7075626c69634d696e74696e6754696d657374616d70000000000000000000006044820152606401610c9a565b600e5460408051918252602082018590527f0bb04c825da052df0301d5b2b1292d51aa85c2d379b4c4d03f2d998ad2c57a86910160405180910390a15050600e55565b6000546001600160a01b031633146118d35760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6040516301ffc9a760e01b81527f89a32daf0000000000000000000000000000000000000000000000000000000060048201819052906001600160a01b038316906301ffc9a79060240160206040518083038186803b15801561193557600080fd5b505afa158015611949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061196d919061473a565b6119ba57604051636b6afd1760e11b815260206004820152600a60248201527f7469636b65744e46545f000000000000000000000000000000000000000000006044820152606401610c9a565b6015546001600160a01b031615611a9f57601554604080517fc6ee20d200000000000000000000000000000000000000000000000000000000815290516001926001600160a01b03169163c6ee20d2916004808301926020929190829003018186803b158015611a2957600080fd5b505afa158015611a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a61919061478e565b6005811115611a8057634e487b7160e01b600052602160045260246000fd5b1115611a9f576040516311cfd2ad60e01b815260040160405180910390fd5b601554604080516001600160a01b03928316815291841660208301527fecb905e703386325d99f190a7cac2df474bcefe4e4d59a55a8c2798047aeba13910160405180910390a150601580546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160a01b038216611b875760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610c9a565b506001600160a01b031660009081526008602052604090205490565b6000546001600160a01b03163314611beb5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b611bf56000613616565b565b6000546001600160a01b03163314611c3f5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b61ffff8116611c9157604051630fc3a38f60e41b815260206004820152601160248201527f6d61785075626c69634d696e7461626c650000000000000000000000000000006044820152606401610c9a565b6010546040805161ffff928316815291831660208301527fb8d7b99ec4233306f8a0b1f89da0eaebba724b9fbe56261e064e9a6bc31e2bbc910160405180910390a16010805461ffff191661ffff92909216919091179055565b6000546001600160a01b03163314611d335760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b80611d8157604051630fc3a38f60e41b815260206004820152600560248201527f70726963650000000000000000000000000000000000000000000000000000006044820152606401610c9a565b600f5460408051918252602082018390527fa0f1665b7b659537b52deec61ea64d134a3bccda74c7f4e79f2246e7a8187a8a910160405180910390a1600f55565b6000546001600160a01b03163314611e0a5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b8051611e72576040517f62a65aec00000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f636f6e74726163745552490000000000000000000000000000000000000000006044820152606401610c9a565b7fd144c5914915e649557dfce6d3199a18bae1ec7c249c1766603a2b76ade11c06601382604051611ea4929190614be4565b60405180910390a18051610f2e9060139060208401906144a2565b606060068054610ba290614d39565b610f2e338383613666565b6060600680611ee66126cb565b6006811115611f0557634e487b7160e01b600052602160045260246000fd5b1015611f1357610ff06126cb565b600060649050600080611f35601a54848480611f2e90614d6e565b9550613735565b905060007f000000000000000000000000000000000000000000000000000000000000138861ffff1667ffffffffffffffff811115611f8457634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611fad578160200160208202803683370190505b50905060008060005b7f00000000000000000000000000000000000000000000000000000000000001f461ffff1681101561211c578483611fed81614d6e565b94508151811061200d57634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156120435761203c601a5488888061203590614d6e565b9950613735565b9450600092505b83828151811061206357634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff166000146120d557848361208181614d6e565b9450815181106120a157634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156120d0576120c9601a5488888061203590614d6e565b9450600092505b612043565b60018483815181106120f757634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101528061211481614d6e565b915050611fb6565b5091965050505050505b5090565b60606004806121376126cb565b600681111561215657634e487b7160e01b600052602160045260246000fd5b101561216457610ff06126cb565b60006101f49050600080612180601854848480611f2e90614d6e565b905060007f000000000000000000000000000000000000000000000000000000000000138861ffff1667ffffffffffffffff8111156121cf57634e487b7160e01b600052604160045260246000fd5b6040519080825280602002602001820160405280156121f8578160200160208202803683370190505b50905060008060005b7f00000000000000000000000000000000000000000000000000000000000002ee61ffff1681101561236057848361223881614d6e565b94508151811061225857634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156122875761228060185488888061203590614d6e565b9450600092505b8382815181106122a757634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff166000146123195784836122c581614d6e565b9450815181106122e557634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156123145761230d60185488888061203590614d6e565b9450600092505b612287565b600284838151811061233b57634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101528061235881614d6e565b915050612201565b5060005b7f00000000000000000000000000000000000000000000000000000000000004e261ffff1681101561211c57848361239b81614d6e565b9450815181106123bb57634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156123ea576123e360185488888061203590614d6e565b9450600092505b83828151811061240a57634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff1660001461247c57848361242881614d6e565b94508151811061244857634e487b7160e01b600052603260045260246000fd5b602002602001015161ffff169150868314156124775761247060185488888061203590614d6e565b9450600092505b6123ea565b600184838151811061249e57634e487b7160e01b600052603260045260246000fd5b61ffff90921660209283029190910190910152806124bb81614d6e565b915050612364565b6000546001600160a01b0316331461250b5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b600160006125198280614cf6565b600681111561253857634e487b7160e01b600052602160045260246000fd5b905081600681111561255a57634e487b7160e01b600052602160045260246000fd5b6125626126cb565b600681111561258157634e487b7160e01b600052602160045260246000fd5b1061258e57610ff06126cb565b600e54831015801561259f57508215155b80156125ac5750600e5415155b156125fa57604051636b6afd1760e11b815260206004820152601760248201527f707269766174654d696e74696e6754696d657374616d700000000000000000006044820152606401610c9a565b600d5460408051918252602082018590527fb49b0d2203b2bce8f0c1930d69dabfc245275b5ec32dc6f328806e33a4d71581910160405180910390a15050600d55565b6126473383613094565b6126b95760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610c9a565b6126c584848484613939565b50505050565b6000601a546000146126dd5750600690565b60105462010000900460ff16156126f45750600590565b601854156127025750600490565b600c547f000000000000000000000000000000000000000000000000000000000000138861ffff1614156127365750600390565b600d5442101580156127495750600d5415155b80156127605750600e544210806127605750600e54155b1561276b5750600190565b600e54421015801561277e5750600e5415155b801561278b5750600d5415155b156127965750600290565b50600090565b6001806127a76126cb565b60068111156127c657634e487b7160e01b600052602160045260246000fd5b146127d357610ff06126cb565b336000818152600b60205260409020600101546127ff91906127fa36869003860186614804565b6139b7565b610f2e33346000613363565b6000818152600760205260409020546060906001600160a01b031661284357604051634a1850bf60e11b815260040160405180910390fd5b60105462010000900460ff1661288557601161285e83613adc565b60405160200161286f929190614a7c565b6040516020818303038152906040529050919050565b601261285e83613adc565b6000546001600160a01b031633146128d85760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b61107d81613c2a565b601380546128ee90614d39565b80601f016020809104026020016040519081016040528092919081815260200182805461291a90614d39565b80156129675780601f1061293c57610100808354040283529160200191612967565b820191906000526020600020905b81548152906001019060200180831161294a57829003601f168201915b505050505081565b6000546001600160a01b031633146129b75760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6001600160a01b038116612a27576040517feac0d38900000000000000000000000000000000000000000000000000000000815260206004820152600860248201527f74726561737572790000000000000000000000000000000000000000000000006044820152606401610c9a565b601454604080516001600160a01b03928316815291831660208301527f21eb548722a564f6e09f039f7aa858ae94c911910f3823b37af2250eeca4f403910160405180910390a1601480546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314612ad85760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b6001600160a01b038116612b545760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610c9a565b61107d81613616565b6000546001600160a01b03163314612ba55760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b604080518082019091526001808252602f60f81b602090920182905282518392918391612bd29190614cf6565b81518110612bf057634e487b7160e01b600052603260045260246000fd5b01602001517fff000000000000000000000000000000000000000000000000000000000000001614612c6557604051636b6afd1760e11b815260206004820152600d60248201527f756e72657665616c6564555249000000000000000000000000000000000000006044820152606401610c9a565b7f8191e07a9f461509729f31da9b0bb812915c3252f697cbf19fc60a700c14e379601183604051612c97929190614be4565b60405180910390a18151610dec9060119060208501906144a2565b6000546001600160a01b03163314612cfa5760405162461bcd60e51b81526020600482018190526024820152600080516020614e3a8339815191526044820152606401610c9a565b600380612d056126cb565b6006811115612d2457634e487b7160e01b600052602160045260246000fd5b1015612d3257610ff06126cb565b601a5415612d53576040516311cfd2ad60e01b815260040160405180910390fd5b619c408263ffffffff161015612dac57604051636b6afd1760e11b815260206004820152601060248201527f63616c6c6261636b4761734c696d6974000000000000000000000000000000006044820152606401610c9a565b6016546040516305d3b1d360e41b81526004810185905267ffffffffffffffff861660248201526003604482015263ffffffff84166064820152600160848201526001600160a01b03909116908190635d3b1d309060a401602060405180830381600087803b158015612e1e57600080fd5b505af1158015612e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5691906148c0565b60198190556040519081527f386f7e0e864241c7e92166f1441c88d40259979d0d6fe045ae15c5e0011c7a7290602001611405565b5490565b80546001019055565b6001600160a01b03163b151590565b6000610b8d82613cba565b600081815260096020526040902080546001600160a01b0319166001600160a01b0384169081179091558190612ee782611693565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b81612f6e57604051630fc3a38f60e41b815260206004820152600960248201527f72657175657374496400000000000000000000000000000000000000000000006044820152606401610c9a565b6017548214156130075760185415612f995760405163ba4ace8d60e01b815260040160405180910390fd5b80600081518110612fba57634e487b7160e01b600052603260045260246000fd5b60200260200101516018819055507f260b0d780ce5d3acea4dbce31d432406bb72fea1d4b7e2571b4558445a45c8d6601854604051612ffb91815260200190565b60405180910390a15050565b601954821415610f2e57601a54156130325760405163ba4ace8d60e01b815260040160405180910390fd5b8060008151811061305357634e487b7160e01b600052603260045260246000fd5b6020026020010151601a819055507f1acc627535151d4af646035fc4bc45bb7f1f35139d354287404bd6a074bfaf69601a54604051612ffb91815260200190565b6000818152600760205260408120546001600160a01b031661310d5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610c9a565b600061311883611693565b9050806001600160a01b0316846001600160a01b0316148061315f57506001600160a01b038082166000908152600a602090815260408083209388168352929052205460ff165b806131835750836001600160a01b031661317884610c25565b6001600160a01b0316145b949350505050565b826001600160a01b031661319e82611693565b6001600160a01b03161461321a5760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152608401610c9a565b6001600160a01b0382166132955760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610c9a565b6132a0838383613d2c565b6132ab600082612eb2565b6001600160a01b03831660009081526008602052604081208054600192906132d4908490614cf6565b90915550506001600160a01b0382166000908152600860205260408120805460019290613302908490614cab565b909155505060008181526007602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b60036000613372600183614cf6565b600681111561339157634e487b7160e01b600052602160045260246000fd5b90508160068111156133b357634e487b7160e01b600052602160045260246000fd5b6133bb6126cb565b60068111156133da57634e487b7160e01b600052602160045260246000fd5b106133e757610ff06126cb565b600f54841461343957604051636b6afd1760e11b815260206004820152600a60248201527f616d6f756e7450616964000000000000000000000000000000000000000000006044820152606401610c9a565b6000613444600c5490565b90506134508686613ed8565b61345e600c80546001019055565b83600181111561347e57634e487b7160e01b600052602160045260246000fd5b6134bb576001600160a01b0386166000908152600b6020526040812060019081018054919290916134b0908490614cab565b909155506134ea9050565b6001600160a01b0386166000908152600b602052604081208054600192906134e4908490614cab565b90915550505b6134f48682613fc3565b505050505050565b6127106bffffffffffffffffffffffff821611156135825760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c2065786365656460448201527f2073616c655072696365000000000000000000000000000000000000000000006064820152608401610c9a565b6001600160a01b0382166135d85760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610c9a565b604080518082019091526001600160a01b039092168083526bffffffffffffffffffffffff9091166020909201829052600160a01b90910217600355565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b816001600160a01b0316836001600160a01b031614156136c85760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610c9a565b6001600160a01b038381166000818152600a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b60608361378557604051630fc3a38f60e41b815260206004820152600a60248201527f72616e646f6d576f7264000000000000000000000000000000000000000000006044820152606401610c9a565b61ffff6000613795601086614cc3565b905060006137a4601087614daa565b11156137b8576137b5600182614cab565b90505b60006137c48286614cd7565b6137cf906010614cd7565b905060006137de836010614cd7565b67ffffffffffffffff81111561380457634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561382d578160200160208202803683370190505b50905060005b8381101561392b576000896138488584614cab565b6040805160208101939093528201526060016040516020818303038152906040528051906020012060001c905060005b6010811015613916576138ad7f0000000000000000000000000000000000000000000000000000000000001388838916614d89565b84826138ba866010614cd7565b6138c49190614cab565b815181106138e257634e487b7160e01b600052603260045260246000fd5b61ffff909216602092830291909101909101526139026201000083614cc3565b91508061390e81614d6e565b915050613878565b5050808061392390614d6e565b915050613833565b5093505050505b9392505050565b61394484848461318b565b61395084848484613fdd565b6126c55760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610c9a565b6002546001600160a01b03166139e05760405163a75e096760e01b815260040160405180910390fd5b826001600160a01b031681600001516001600160a01b031614613a455780516040517ff1a669ce0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301529091166024820152604401610c9a565b81816020015161ffff1611613a7057604051631ebf81cf60e21b815260048101839052602401610c9a565b6000613a7b82614135565b6002549091506001600160a01b038083169116146126c5576002546040517f6cd82d240000000000000000000000000000000000000000000000000000000081526001600160a01b0380841660048301529091166024820152604401610c9a565b606081613b1c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115613b465780613b3081614d6e565b9150613b3f9050600a83614cc3565b9150613b20565b60008167ffffffffffffffff811115613b6f57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015613b99576020820181803683370190505b5090505b841561318357613bae600183614cf6565b9150613bbb600a86614daa565b613bc6906030614cab565b60f81b818381518110613be957634e487b7160e01b600052603260045260246000fd5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350613c23600a86614cc3565b9450613b9d565b6001600160a01b038116613c515760405163a75e096760e01b815260040160405180910390fd5b600254604080516001600160a01b03928316815291831660208301527f9fed3c0e42aa7f73947a13ac6757a3d73c8f820c1c1d45bfdb2a3f9d3f812a07910160405180910390a1600280546001600160a01b0319166001600160a01b0392909216919091179055565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480613d1d57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610b8d5750610b8d82614211565b6015546001600160a01b031615610dec57601554604080517f2c77ddfd00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691632c77ddfd916004808301926020929190829003018186803b158015613d9b57600080fd5b505afa158015613daf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613dd391906148c0565b90508042108015613e7557506015546040517f927e603d0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301529091169063927e603d9060240160206040518083038186803b158015613e3d57600080fd5b505afa158015613e51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e75919061473a565b8015613e895750613e8584611b09565b6001145b156126c5576040517f65e7520f0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015242602482015260448101829052606401610c9a565b6014546040516000916001600160a01b03169083908381818185875af1925050503d8060008114613f25576040519150601f19603f3d011682016040523d82523d6000602084013e613f2a565b606091505b5050905080613f7b5760405162461bcd60e51b815260206004820152601660248201527f436f756c64206e6f7420706179207472656173757279000000000000000000006044820152606401610c9a565b826001600160a01b03167fb5668d929317b36d7b61952ab446b7e4dd82c4d9f90788b407c35e90440f567883604051613fb691815260200190565b60405180910390a2505050565b610f2e82826040518060200160405280600081525061425f565b60006001600160a01b0384163b1561412a57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290614021903390899088908890600401614b24565b602060405180830381600087803b15801561403b57600080fd5b505af192505050801561406b575060408051601f3d908101601f1916820190925261406891810190614772565b60015b614110573d808015614099576040519150601f19603f3d011682016040523d82523d6000602084013e61409e565b606091505b5080516141085760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610c9a565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050613183565b506001949350505050565b600080600154614144846142dd565b6040517f1901000000000000000000000000000000000000000000000000000000000000602082015260228101929092526042820152606201604051602081830303815290604052805190602001209050600181846040015185606001518660800151604051600081526020016040526040516141dd949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156141ff573d6000803e3d6000fd5b5050604051601f190151949350505050565b60006001600160e01b031982167f2a55205a000000000000000000000000000000000000000000000000000000001480610b8d57506301ffc9a760e01b6001600160e01b0319831614610b8d565b6142698383614354565b6142766000848484613fdd565b610dec5760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610c9a565b8051602080830151604051600093614337937f9016184a70237a58286b5c611a44cf3c4b67b9ec2da552661f6a04c1395282d5939192019283526001600160a01b0391909116602083015261ffff16604082015260600190565b604051602081830303815290604052805190602001209050919050565b6001600160a01b0382166143aa5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610c9a565b6000818152600760205260409020546001600160a01b03161561440f5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610c9a565b61441b60008383613d2c565b6001600160a01b0382166000908152600860205260408120805460019290614444908490614cab565b909155505060008181526007602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b8280546144ae90614d39565b90600052602060002090601f0160209004810192826144d05760008555614516565b82601f106144e957805160ff1916838001178555614516565b82800160010185558215614516579182015b828111156145165782518255916020019190600101906144fb565b506121269291505b80821115612126576000815560010161451e565b600067ffffffffffffffff83111561454c5761454c614dea565b61455f601f8401601f1916602001614c7a565b905082815283838301111561457357600080fd5b828260208301376000602084830101529392505050565b803561ffff8116811461459c57600080fd5b919050565b6000602082840312156145b2578081fd5b813561393281614e00565b600080604083850312156145cf578081fd5b82356145da81614e00565b915060208301356145ea81614e00565b809150509250929050565b600080600060608486031215614609578081fd5b833561461481614e00565b9250602084013561462481614e00565b929592945050506040919091013590565b6000806000806080858703121561464a578182fd5b843561465581614e00565b9350602085013561466581614e00565b925060408501359150606085013567ffffffffffffffff811115614687578182fd5b8501601f81018713614697578182fd5b6146a687823560208401614532565b91505092959194509250565b600080604083850312156146c4578182fd5b82356146cf81614e00565b915060208301356145ea81614e15565b600080604083850312156146f1578182fd5b82356146fc81614e00565b91506020830135600281106145ea578182fd5b60008060408385031215614721578182fd5b823561472c81614e00565b946020939093013593505050565b60006020828403121561474b578081fd5b815161393281614e15565b600060208284031215614767578081fd5b813561393281614e23565b600060208284031215614783578081fd5b815161393281614e23565b60006020828403121561479f578081fd5b815160068110613932578182fd5b6000602082840312156147be578081fd5b813567ffffffffffffffff8111156147d4578182fd5b8201601f810184136147e4578182fd5b61318384823560208401614532565b600060a082840312156114d0578081fd5b600060a08284031215614815578081fd5b60405160a0810181811067ffffffffffffffff8211171561483857614838614dea565b604052823561484681614e00565b81526148546020840161458a565b6020820152604083013560ff8116811461486c578283fd5b6040820152606083810135908201526080928301359281019290925250919050565b60006020828403121561489f578081fd5b6139328261458a565b6000602082840312156148b9578081fd5b5035919050565b6000602082840312156148d1578081fd5b5051919050565b600080604083850312156148ea578182fd5b8235915060208084013567ffffffffffffffff80821115614909578384fd5b818601915086601f83011261491c578384fd5b81358181111561492e5761492e614dea565b8060051b915061493f848301614c7a565b8181528481019084860184860187018b1015614959578788fd5b8795505b8386101561497b57803583526001959095019491860191860161495d565b508096505050505050509250929050565b6000806040838503121561499e578182fd5b50508035926020909101359150565b6000806000606084860312156149c1578081fd5b833567ffffffffffffffff811681146149d8578182fd5b925060208401359150604084013563ffffffff811681146149f7578182fd5b809150509250925092565b600060208284031215614a13578081fd5b81356bffffffffffffffffffffffff81168114613932578182fd5b60008151808452614a46816020860160208601614d0d565b601f01601f19169290920160200192915050565b60078110614a7857634e487b7160e01b600052602160045260246000fd5b9052565b6000808454614a8a81614d39565b60018281168015614aa25760018114614ab357614adf565b60ff19841687528287019450614adf565b8886526020808720875b85811015614ad65781548a820152908401908201614abd565b50505082870194505b505050508351614af3818360208801614d0d565b7f2e6a736f6e0000000000000000000000000000000000000000000000000000009101908152600501949350505050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614b566080830184614a2e565b9695505050505050565b6020808252825182820181905260009190848201906040850190845b81811015614b9c57835161ffff1683529284019291840191600101614b7c565b50909695505050505050565b60208101610b8d8284614a5a565b60408101614bc48285614a5a565b6139326020830184614a5a565b6020815260006139326020830184614a2e565b604081526000808454614bf681614d39565b8060408601526060600180841660008114614c185760018114614c2c57614c5a565b60ff19851688840152608088019550614c5a565b8987526020808820885b86811015614c515781548b8201870152908401908201614c36565b8a018501975050505b50505050508281036020840152614c718185614a2e565b95945050505050565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ca357614ca3614dea565b604052919050565b60008219821115614cbe57614cbe614dbe565b500190565b600082614cd257614cd2614dd4565b500490565b6000816000190483118215151615614cf157614cf1614dbe565b500290565b600082821015614d0857614d08614dbe565b500390565b60005b83811015614d28578181015183820152602001614d10565b838111156126c55750506000910152565b600181811c90821680614d4d57607f821691505b602082108114156114d057634e487b7160e01b600052602260045260246000fd5b6000600019821415614d8257614d82614dbe565b5060010190565b600061ffff80841680614d9e57614d9e614dd4565b92169190910692915050565b600082614db957614db9614dd4565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461107d57600080fd5b801515811461107d57600080fd5b6001600160e01b03198116811461107d57600080fdfe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220b3144f75f071b381966b4b44338ff0d329f69549cf83d122078d79f583a3dadc64736f6c63430008040033

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

000000000000000000000000455ad5835b5f732a8c28d0ad79abf7942f586906000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000004e200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000632c403000000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000214e8348c4f0000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000005168747470733a2f2f73332e65752d776573742d322e616d617a6f6e6177732e636f6d2f6d617261646f6e616f6666696369616c2e696f2f61636365737350617373436f6e74726163745552492e6a736f6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d5a346e696a4e546b5933556a3766327a71766d6b5a57386873344e6e42345878514d35474c7277554a4d52522f00000000000000000000

-----Decoded View---------------
Arg [0] : treasury_ (address): 0x455AD5835B5f732A8C28d0ad79abF7942f586906
Arg [1] : vrfCoordinator_ (address): 0x271682DEB8C4E0901D1a1550aD2e64D568E69909
Arg [2] : maxTotalSupply_ (uint16): 5000
Arg [3] : goldenTierSupply_ (uint16): 750
Arg [4] : silverTierSupply_ (uint16): 1250
Arg [5] : ticketSupply_ (uint16): 500
Arg [6] : privateMintingTimestamp_ (uint256): 1663844400
Arg [7] : royaltyFee (uint96): 850
Arg [8] : price_ (uint256): 150000000000000000
Arg [9] : contractURI_ (string): https://s3.eu-west-2.amazonaws.com/maradonaofficial.io/accessPassContractURI.json
Arg [10] : unrevealedURI_ (string): ipfs://QmZ4nijNTkY3Uj7f2zqvmkZW8hs4NnB4XxQM5GLrwUJMRR/

-----Encoded View---------------
18 Constructor Arguments found :
Arg [0] : 000000000000000000000000455ad5835b5f732a8c28d0ad79abf7942f586906
Arg [1] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [2] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [3] : 00000000000000000000000000000000000000000000000000000000000002ee
Arg [4] : 00000000000000000000000000000000000000000000000000000000000004e2
Arg [5] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [6] : 00000000000000000000000000000000000000000000000000000000632c4030
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000352
Arg [8] : 0000000000000000000000000000000000000000000000000214e8348c4f0000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [10] : 00000000000000000000000000000000000000000000000000000000000001e0
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000051
Arg [12] : 68747470733a2f2f73332e65752d776573742d322e616d617a6f6e6177732e63
Arg [13] : 6f6d2f6d617261646f6e616f6666696369616c2e696f2f616363657373506173
Arg [14] : 73436f6e74726163745552492e6a736f6e000000000000000000000000000000
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000036
Arg [16] : 697066733a2f2f516d5a346e696a4e546b5933556a3766327a71766d6b5a5738
Arg [17] : 6873344e6e42345878514d35474c7277554a4d52522f00000000000000000000


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.