ETH Price: $3,405.97 (-0.55%)

Token

PUNKS Comic 3 (COMIC3)
 

Overview

Max Total Supply

15,000 COMIC3

Holders

3,477

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
2 COMIC3
0x9B338FdDc58A3A28042ff3Fc9Ae3eCbcFE0de267
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Meet the PUNKS! Everyone’s favorite misfit crew of collectors, rebels, and crypto degens from the metaverse. A project by Pixel Vault.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
PunksThreeVRF

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 50000 runs

Other Settings:
default evmVersion
File 1 of 13 : PunksThreeVRF.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

import "./ERC721Enumerable.sol";

contract PunksThreeVRF is VRFConsumerBaseV2, ERC721Enumerable {
    using ECDSA for bytes32;

    struct Window {
        uint128 startWindow;
        uint128 endWindow;
    }

    struct Prize {
        bool tokenType; //1155 is 0, 721 is 1
        bool mint;
        address tokenAddress;
    }
    
    address constant FOUNDERS_DAO = 0x580A96BC816C2324Bdff5eb2a7E159AE7ee63022;
    address signer;
    address immutable tokenHolder;

    uint256 public immutable PRICE;

    VRFCoordinatorV2Interface immutable COORDINATOR;
    bytes32 keyHash;
    uint32 callbackGasLimit = 2500000;
    uint16 requestConfirmations = 3;
    uint64 subscriptionId;
    
    uint256 public maxSale;
    uint8[] public remainingTokens;
    uint256 public amountSold;
    uint256 prizeCounter; 
    uint256 stageCounter; 

    mapping(uint256 => address) public requestToAddress;
    mapping(address => uint256) public amountMinted;
    mapping(uint256 => Window) public stages;
    mapping(uint256 => Prize) public prizes;

    Window publicWindow;

    error windowClosed();
    error signatureInvalid();
    error amountInvalid();
    error allPrizesDistributed();
    error insufficientPayment();
    error soldOut();
    error withdrawFailed();
    error addStagesFailed();
    error callerNotOwnerNorApproved();
    error notSameLength();
    error maxSupplyExceeded();

    constructor(
        address _vrfCoordinator,
        bytes32 _keyHash,
        uint64 _subscriptionId,
        address _signer,
        address _tokenHolder,
        string memory _name,
        string memory _symbol,
        string memory _uri,
        uint256 _price
    ) PVERC721(_name, _symbol, _uri, 15000) VRFConsumerBaseV2(_vrfCoordinator) {        
        COORDINATOR = VRFCoordinatorV2Interface(_vrfCoordinator);
        subscriptionId = _subscriptionId;
        keyHash = _keyHash;

        signer = _signer;
        tokenHolder = _tokenHolder;

        PRICE = _price;

        _internalMint(FOUNDERS_DAO);
    }   

    function fillRemainingTokens(uint8 _prizeId, uint256 _amount) public onlyOwner {
        for(uint256 i; i < _amount;) {

            remainingTokens.push(_prizeId);
            
            unchecked {
                ++i;
            }
        }

        maxSale += _amount;
    }

    function clearRemainingTokens(uint256 _newMaxSale) external onlyOwner {
        remainingTokens = new uint8[](0);
        maxSale = _newMaxSale;
    }

    function setPublicWindow(Window calldata window) external onlyOwner {
        publicWindow.startWindow = window.startWindow;
        publicWindow.endWindow = window.endWindow;
    }

    function setSigner(address _signer) external onlyOwner {
        signer = _signer;
    }

    function addStages(Window[] memory windows) external onlyOwner {
        for (uint256 i; i < windows.length; i++) {
            
            if(windows[i].startWindow >= windows[i].endWindow) {
                revert addStagesFailed();
            }

            Window storage p = stages[stageCounter];
            p.startWindow = windows[i].startWindow;
            p.endWindow = windows[i].endWindow;
            
            ++stageCounter;
        }
    }

    function editStage(uint256 _id, uint128 _startWindow, uint128 _endWindow) external onlyOwner {
        stages[_id].startWindow = _startWindow;
        stages[_id].endWindow = _endWindow;       
    }

    function addTieredPrizes(address _tokenAddress, bool _tokenType, bool _mint, uint256 _amount) external onlyOwner {
        Prize storage p = prizes[prizeCounter];
        p.tokenType = _tokenType;
        p.tokenAddress = _tokenAddress;
        p.mint = _mint;

        fillRemainingTokens(uint8(prizeCounter), _amount);

        ++prizeCounter;
    }

    function editTieredPrize(uint256 _id, address _tokenAddress, bool _tokenType, bool _mint) external onlyOwner {
        prizes[_id].tokenType = _tokenType;
        prizes[_id].tokenAddress = _tokenAddress;
        prizes[_id].mint = _mint;        
    }

    function burn(uint256 tokenId) external {        
        if(!isApprovedForAll[ownerOf(tokenId)][msg.sender] && getApproved[tokenId] != msg.sender && ownerOf(tokenId) != msg.sender ) {
            revert callerNotOwnerNorApproved();
        }

        _burn(tokenId);
    }

    function ownerMint (
        address[] calldata _to, 
        uint256[] calldata _amount
    ) external onlyOwner {

        if(_to.length != _amount.length) {
            revert notSameLength();
        }

        for(uint256 i; i < _to.length; i++) {
            
            if(tokenCounter + _amount[i] > MAX_SUPPLY) {
                revert maxSupplyExceeded();
            }

            _mintMany(_to[i], _amount[i]);
        }
    }  

    function setKeyHash(bytes32 _keyHash) external onlyOwner {
        keyHash = _keyHash;
    }

    function setCallbackGasLimit(uint32 _callbackGasLimit) external onlyOwner {
        callbackGasLimit = _callbackGasLimit;
    }

    function setRequestConfirmations(uint16 _requestConfirmations) external onlyOwner {
        requestConfirmations = _requestConfirmations;
    }

    function setSubscriptionId(uint64 _subscriptionId) external onlyOwner {
        subscriptionId = _subscriptionId;
    }    

    function withdraw(address payable _to, uint256 _amount) external onlyOwner {
        (bool sent, bytes memory data) = _to.call{value: _amount}("");

        if(!sent)  {
            revert withdrawFailed();
        }
    } 

    function mint(        
        bytes calldata _signature,
        uint256 _stage,
        uint256 _maxAtCurrentStage,
        uint32 _amount
    ) external payable {

        if(_amount + amountSold > maxSale) {
            revert soldOut();
        }

        if(_amount * PRICE != msg.value) {
            revert insufficientPayment();
        }
        
        if(block.timestamp < stages[_stage].startWindow || block.timestamp > stages[_stage].endWindow) {
            revert windowClosed();
        }

        bytes32 hash = keccak256(abi.encodePacked(msg.sender, _stage, _maxAtCurrentStage));
        if (hash.toEthSignedMessageHash().recover(_signature) != signer) {
            revert signatureInvalid();
        }

        if(_amount + amountMinted[msg.sender] > _maxAtCurrentStage){
            revert amountInvalid();
        }

        amountMinted[msg.sender] += _amount;
        amountSold += _amount;

        sendVRFRequests(_amount);
    }                       

    function publicMint(        
        uint32 _amount
    ) external payable {

        if(_amount + amountSold > maxSale) {
            revert soldOut();
        }
        if(_amount * PRICE != msg.value) {
            revert insufficientPayment();
        }
        if(block.timestamp < publicWindow.startWindow || block.timestamp > publicWindow.endWindow) {
            revert windowClosed();
        }
        if(_amount > 20){
            revert amountInvalid();
        }

        amountSold += _amount;

        sendVRFRequests(_amount);
    }

    function sendPrize(
        uint256 prizeId,
        address receiver
    ) external onlyOwner {
        Prize memory prize = prizes[prizeId];

        address tokenAddress = prize.tokenAddress;

        if (tokenAddress == address(this)) {
            _internalMint(receiver);
        } else {
            if(prize.mint) {
                IComicThreeSE(tokenAddress).mint(receiver);
            } else if (prize.tokenType) {
                IERC721Enumerable token = IERC721Enumerable(tokenAddress);
                token.transferFrom(tokenHolder, receiver, token.tokenOfOwnerByIndex(tokenHolder,0));
            } else {
                IERC1155(prize.tokenAddress).safeTransferFrom(tokenHolder, receiver, 0, 1, "");
            }
        }
    }

    function sendVRFRequests (
        uint32 _tokenAmount
    ) internal {

        while (_tokenAmount > 0) {

            uint32 _amountTemp = _tokenAmount > 10 ? 10 : _tokenAmount;
            _tokenAmount -= _amountTemp;

            uint256 s_requestId = COORDINATOR.requestRandomWords(
              keyHash,
              subscriptionId,
              requestConfirmations,
              callbackGasLimit,
              _amountTemp
            );

            requestToAddress[s_requestId] = msg.sender;
        }

    }

    function fulfillRandomWords(
        uint256 requestId,
        uint256[] memory randomWords
    ) internal override {

        for(uint256 i; i < randomWords.length;) {
            
            uint256 amountRemaining = remainingTokens.length;
            uint256 pickedIndex = randomWords[i] % amountRemaining;

            Prize memory prize = prizes[remainingTokens[pickedIndex]];

            remainingTokens[pickedIndex] = remainingTokens[amountRemaining - 1];
            remainingTokens.pop();

            address receiver = requestToAddress[requestId];
            address tokenAddress = prize.tokenAddress;

            if (tokenAddress == address(this)) {
                _internalMint(receiver);
            } else {
                if(prize.mint) {
                    IComicThreeSE(tokenAddress).mint(receiver);
                } else if (prize.tokenType) {
                    IERC721Enumerable token = IERC721Enumerable(tokenAddress);
                    token.transferFrom(tokenHolder, receiver, token.tokenOfOwnerByIndex(tokenHolder,0));
                } else {
                    IERC1155(prize.tokenAddress).safeTransferFrom(tokenHolder, receiver, 0, 1, "");
                }
            }

            unchecked {
                ++i;
            }
        }
    } 
}

interface IComicThreeSE {
    function mint(address to) external;
}

File 2 of 13 : 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 3 of 13 : 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 4 of 13 : 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 5 of 13 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

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

File 6 of 13 : ERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "./PVERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is PVERC721 {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

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

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual returns (uint256) {
        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @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` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */

    function transferFrom(address from, address to, uint256 id) public override {
        _beforeTokenTransfer(from, to, id);
        super.transferFrom(from, to, id);
    }

    function _mint(address to, uint256 id) internal override {
        _beforeTokenTransfer(address(0), to, id);
        super._mint(to, id);
    }

    function _burn(uint256 id) internal override {
        _beforeTokenTransfer(_ownerOf[id], address(0), id);
        super._burn(id);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        if (from == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}

File 7 of 13 : 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 8 of 13 : 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 9 of 13 : PVERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.15;

import "@rari-capital/solmate/src/auth/Owned.sol";
import "@rari-capital/solmate/src/tokens/ERC721.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract PVERC721 is ERC721, Owned {
    using Strings for uint256;

    uint256 tokenCounter;
    string uri;

    uint256 immutable MAX_SUPPLY;

    error notExists();

    constructor(
        string memory _name,
        string memory _symbol,
        string memory _uri,
        uint256 _maxSupply
    ) ERC721(_name, _symbol) Owned(msg.sender) {
        uri = _uri;

        MAX_SUPPLY = _maxSupply;
    }

    function _mintMany(address _account, uint256 _amount) internal {
        for (uint256 i; i < _amount; ) {
            _internalMint(_account);

            unchecked {
                i++;
            }
        }
    }

    function _internalMint(address _account) internal {
        require(tokenCounter < MAX_SUPPLY, "Max supply reached");

        ++tokenCounter;
        _mint(_account, tokenCounter);
    }

    function setURI(string memory _uri) external onlyOwner {
        uri = _uri;
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        if (tokenCounter < tokenId) {
            revert notExists();
        }

        return uri;
    }
}

File 10 of 13 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

File 11 of 13 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnerUpdated(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnerUpdated(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function setOwner(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnerUpdated(msg.sender, newOwner);
    }
}

File 12 of 13 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        require(
            to.code.length == 0 ||
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                ERC721TokenReceiver.onERC721Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

File 13 of 13 : 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);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_vrfCoordinator","type":"address"},{"internalType":"bytes32","name":"_keyHash","type":"bytes32"},{"internalType":"uint64","name":"_subscriptionId","type":"uint64"},{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_tokenHolder","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_uri","type":"string"},{"internalType":"uint256","name":"_price","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"have","type":"address"},{"internalType":"address","name":"want","type":"address"}],"name":"OnlyCoordinatorCanFulfill","type":"error"},{"inputs":[],"name":"addStagesFailed","type":"error"},{"inputs":[],"name":"allPrizesDistributed","type":"error"},{"inputs":[],"name":"amountInvalid","type":"error"},{"inputs":[],"name":"callerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"insufficientPayment","type":"error"},{"inputs":[],"name":"maxSupplyExceeded","type":"error"},{"inputs":[],"name":"notExists","type":"error"},{"inputs":[],"name":"notSameLength","type":"error"},{"inputs":[],"name":"signatureInvalid","type":"error"},{"inputs":[],"name":"soldOut","type":"error"},{"inputs":[],"name":"windowClosed","type":"error"},{"inputs":[],"name":"withdrawFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","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":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"startWindow","type":"uint128"},{"internalType":"uint128","name":"endWindow","type":"uint128"}],"internalType":"struct PunksThreeVRF.Window[]","name":"windows","type":"tuple[]"}],"name":"addStages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"bool","name":"_tokenType","type":"bool"},{"internalType":"bool","name":"_mint","type":"bool"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addTieredPrizes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"amountMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amountSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxSale","type":"uint256"}],"name":"clearRemainingTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint128","name":"_startWindow","type":"uint128"},{"internalType":"uint128","name":"_endWindow","type":"uint128"}],"name":"editStage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"bool","name":"_tokenType","type":"bool"},{"internalType":"bool","name":"_mint","type":"bool"}],"name":"editTieredPrize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_prizeId","type":"uint8"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"fillRemainingTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSale","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_signature","type":"bytes"},{"internalType":"uint256","name":"_stage","type":"uint256"},{"internalType":"uint256","name":"_maxAtCurrentStage","type":"uint256"},{"internalType":"uint32","name":"_amount","type":"uint32"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_to","type":"address[]"},{"internalType":"uint256[]","name":"_amount","type":"uint256[]"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"prizes","outputs":[{"internalType":"bool","name":"tokenType","type":"bool"},{"internalType":"bool","name":"mint","type":"bool"},{"internalType":"address","name":"tokenAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_amount","type":"uint32"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256[]","name":"randomWords","type":"uint256[]"}],"name":"rawFulfillRandomWords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"remainingTokens","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requestToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","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":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"prizeId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"sendPrize","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":"uint32","name":"_callbackGasLimit","type":"uint32"}],"name":"setCallbackGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_keyHash","type":"bytes32"}],"name":"setKeyHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"startWindow","type":"uint128"},{"internalType":"uint128","name":"endWindow","type":"uint128"}],"internalType":"struct PunksThreeVRF.Window","name":"window","type":"tuple"}],"name":"setPublicWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_requestConfirmations","type":"uint16"}],"name":"setRequestConfirmations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_subscriptionId","type":"uint64"}],"name":"setSubscriptionId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stages","outputs":[{"internalType":"uint128","name":"startWindow","type":"uint128"},{"internalType":"uint128","name":"endWindow","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"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":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610120604052600f805465ffffffffffff19166403002625a01790553480156200002857600080fd5b5060405162005aa038038062005aa08339810160408190526200004b91620006ff565b6001600160a01b038916608052838383613a9833848460006200006f83826200087e565b5060016200007e82826200087e565b5050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a3506008620000db83826200087e565b5060a0525050506001600160a01b0389811661010052600f8054600160301b600160701b03191666010000000000006001600160401b038b1602179055600e899055600d80546001600160a01b031916888316179055851660c05260e08190526200015a73580a96bc816c2324bdff5eb2a7e159ae7ee6302262000169565b505050505050505050620009c2565b60a05160075410620001b75760405162461bcd60e51b815260206004820152601260248201527113585e081cdd5c1c1b1e481c995858da195960721b60448201526064015b60405180910390fd5b600760008154620001c89062000960565b90915550600754620001dc908290620001df565b50565b620001ed6000838362000208565b620002048282620002d160201b62002d911760201c565b5050565b6001600160a01b03831662000266576200026081600b80546000838152600c60205260408120829055600182018355919091527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90155565b6200028c565b816001600160a01b0316836001600160a01b0316146200028c576200028c8382620003e0565b6001600160a01b038216620002ab57620002a6816200048d565b505050565b826001600160a01b0316826001600160a01b031614620002a657620002a6828262000547565b6001600160a01b0382166200031d5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401620001ae565b6000818152600260205260409020546001600160a01b031615620003755760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401620001ae565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60006001620003fa846200059860201b620017d51760201c565b6200040691906200097c565b6000838152600a60205260409020549091508082146200045a576001600160a01b03841660009081526009602090815260408083208584528252808320548484528184208190558352600a90915290208190555b506000918252600a602090815260408084208490556001600160a01b039094168352600981528383209183525290812055565b600b54600090620004a1906001906200097c565b6000838152600c6020526040812054600b8054939450909284908110620004cc57620004cc62000996565b9060005260206000200154905080600b8381548110620004f057620004f062000996565b6000918252602080832090910192909255828152600c9091526040808220849055858252812055600b8054806200052b576200052b620009ac565b6001900381819060005260206000200160009055905550505050565b60006200055f836200059860201b620017d51760201c565b6001600160a01b0390931660009081526009602090815260408083208684528252808320859055938252600a9052919091209190915550565b60006001600160a01b038216620005e15760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401620001ae565b506001600160a01b031660009081526003602052604090205490565b80516001600160a01b03811681146200061557600080fd5b919050565b80516001600160401b03811681146200061557600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200065a57600080fd5b81516001600160401b038082111562000677576200067762000632565b604051601f8301601f19908116603f01168101908282118183101715620006a257620006a262000632565b81604052838152602092508683858801011115620006bf57600080fd5b600091505b83821015620006e35785820183015181830184015290820190620006c4565b83821115620006f55760008385830101525b9695505050505050565b60008060008060008060008060006101208a8c0312156200071f57600080fd5b6200072a8a620005fd565b985060208a015197506200074160408b016200061a565b96506200075160608b01620005fd565b95506200076160808b01620005fd565b60a08b01519095506001600160401b03808211156200077f57600080fd5b6200078d8d838e0162000648565b955060c08c0151915080821115620007a457600080fd5b620007b28d838e0162000648565b945060e08c0151915080821115620007c957600080fd5b50620007d88c828d0162000648565b9250506101008a015190509295985092959850929598565b600181811c908216806200080557607f821691505b6020821081036200082657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002a657600081815260208120601f850160051c81016020861015620008555750805b601f850160051c820191505b81811015620008765782815560010162000861565b505050505050565b81516001600160401b038111156200089a576200089a62000632565b620008b281620008ab8454620007f0565b846200082c565b602080601f831160018114620008ea5760008415620008d15750858301515b600019600386901b1c1916600185901b17855562000876565b600085815260208120601f198616915b828110156200091b57888601518255948401946001909101908401620008fa565b50858210156200093a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b6000600182016200097557620009756200094a565b5060010190565b6000828210156200099157620009916200094a565b500390565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c05160e0516101005161506862000a386000396000613aa70152600081816106ff01528181611e670152612a86015260008181611b7b01528181611cec015281816132aa015261341b01526000818161162f01526138db015260008181610f860152610fee01526150686000f3fe6080604052600436106102fd5760003560e01c8063845ddcb21161018f578063b88d4fde116100e1578063e985e9c51161008a578063f151d79111610064578063f151d791146109df578063f3fef3a3146109f2578063ff69b94b14610a1257600080fd5b8063e985e9c5146108f9578063ea7b4f7714610934578063eccb3a4f1461095457600080fd5b8063c87b56dd116100bb578063c87b56dd14610876578063d1a4647714610896578063d84058f3146108b657600080fd5b8063b88d4fde14610816578063bfecafe514610836578063c6ca404f1461085657600080fd5b80639854471011610143578063a4be83431161011d578063a4be8343146107c3578063a4eb718c146107d6578063af676625146107f657600080fd5b80639854471014610763578063a0e59e2e14610783578063a22cb465146107a357600080fd5b80638d859f3e116101745780638d859f3e146106ed5780638da5cb5b1461072157806395d89b411461074e57600080fd5b8063845ddcb21461064d5780638824f5a7146106cd57600080fd5b80632f745c59116102535780634f6ccce7116101fc57806369f7d2f2116101d657806369f7d2f2146105ed5780636c19e7831461060d57806370a082311461062d57600080fd5b80634f6ccce71461059757806352a16bb0146105b75780636352211e146105cd57600080fd5b806342842e0e1161022d57806342842e0e1461052a57806342966c681461054a578063438a67e71461056a57600080fd5b80632f745c59146104d457806335d305ad146104f45780633e30046a1461051457600080fd5b8063095ea7b3116102b557806318160ddd1161028f57806318160ddd146104755780631fe543e31461049457806323b872dd146104b457600080fd5b8063095ea7b31461040357806313af403514610423578063171ee95a1461044357600080fd5b806304c624d0116102e657806304c624d01461035957806306fdde0314610379578063081812fc1461039b57600080fd5b806301ffc9a71461030257806302fe530514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004614393565b610a32565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061035761035236600461445e565b610a8e565b005b34801561036557600080fd5b50610357610374366004614543565b610b24565b34801561038557600080fd5b5061038e610c70565b60405161032e9190614590565b3480156103a757600080fd5b506103de6103b6366004614603565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161032e565b34801561040f57600080fd5b5061035761041e36600461461c565b610cfe565b34801561042f57600080fd5b5061035761043e366004614648565b610e48565b34801561044f57600080fd5b5061046361045e366004614603565b610f3a565b60405160ff909116815260200161032e565b34801561048157600080fd5b50600b545b60405190815260200161032e565b3480156104a057600080fd5b506103576104af366004614689565b610f6e565b3480156104c057600080fd5b506103576104cf36600461472b565b611025565b3480156104e057600080fd5b506104866104ef36600461461c565b611040565b34801561050057600080fd5b5061035761050f36600461478c565b61110f565b34801561052057600080fd5b5061048660105481565b34801561053657600080fd5b5061035761054536600461472b565b6111d2565b34801561055657600080fd5b50610357610565366004614603565b611337565b34801561057657600080fd5b50610486610585366004614648565b60166020526000908152604090205481565b3480156105a357600080fd5b506104866105b2366004614603565b611419565b3480156105c357600080fd5b5061048660125481565b3480156105d957600080fd5b506103de6105e8366004614603565b6114d7565b3480156105f957600080fd5b5061035761060836600461480d565b611568565b34801561061957600080fd5b50610357610628366004614648565b61170d565b34801561063957600080fd5b50610486610648366004614648565b6117d5565b34801561065957600080fd5b506106a4610668366004614603565b6017602052600090815260409020546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041682565b604080516fffffffffffffffffffffffffffffffff93841681529290911660208301520161032e565b3480156106d957600080fd5b506103576106e8366004614879565b61187d565b3480156106f957600080fd5b506104867f000000000000000000000000000000000000000000000000000000000000000081565b34801561072d57600080fd5b506006546103de9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561075a57600080fd5b5061038e61193b565b34801561076f57600080fd5b5061035761077e366004614603565b611948565b34801561078f57600080fd5b5061035761079e36600461489d565b6119ce565b3480156107af57600080fd5b506103576107be3660046148cd565b611d7c565b6103576107d1366004614958565b611e13565b3480156107e257600080fd5b506103576107f13660046149bf565b61213c565b34801561080257600080fd5b506103576108113660046149da565b6121f4565b34801561082257600080fd5b50610357610831366004614a29565b61232a565b34801561084257600080fd5b50610357610851366004614a9c565b61247d565b34801561086257600080fd5b50610357610871366004614b61565b612685565b34801561088257600080fd5b5061038e610891366004614603565b612787565b3480156108a257600080fd5b506103576108b1366004614b85565b612857565b3480156108c257600080fd5b506103de6108d1366004614603565b60156020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561090557600080fd5b50610322610914366004614b9d565b600560209081526000928352604080842090915290825290205460ff1681565b34801561094057600080fd5b5061035761094f366004614bcb565b61296c565b34801561096057600080fd5b506109ac61096f366004614603565b60186020526000908152604090205460ff8082169161010081049091169062010000900473ffffffffffffffffffffffffffffffffffffffff1683565b604080519315158452911515602084015273ffffffffffffffffffffffffffffffffffffffff169082015260600161032e565b6103576109ed3660046149bf565b612a32565b3480156109fe57600080fd5b50610357610a0d36600461461c565b612bd0565b348015610a1e57600080fd5b50610357610a2d366004614603565b612ced565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610a885750610a8882612f2a565b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610b14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6008610b208282614c88565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610ba5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60138054600090815260186020526040902080547fffffffffffffffffffff0000000000000000000000000000000000000000ff00168515157fffffffffffffffffffff0000000000000000000000000000000000000000ffff16176201000073ffffffffffffffffffffffffffffffffffffffff881602177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100851515021781559054610c569083612685565b601360008154610c6590614dd1565b909155505050505050565b60008054610c7d90614bf5565b80601f0160208091040260200160405190810160405280929190818152602001828054610ca990614bf5565b8015610cf65780601f10610ccb57610100808354040283529160200191610cf6565b820191906000526020600020905b815481529060010190602001808311610cd957829003601f168201915b505050505081565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633811480610d61575073ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152604080832033845290915290205460ff165b610dc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a45440000000000000000000000000000000000006044820152606401610b0b565b60008281526004602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610ec9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b60118181548110610f4a57600080fd5b9060005260206000209060209182820401919006915054906101000a900460ff1681565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461101b576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166024820152604401610b0b565b610b20828261300b565b6110308383836134b5565b61103b8383836135bb565b505050565b600061104b836117d5565b82106110d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610b0b565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600960209081526040808320938352929052205490565b60065473ffffffffffffffffffffffffffffffffffffffff163314611190576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6000928352601760205260409092206fffffffffffffffffffffffffffffffff9283167001000000000000000000000000000000000292909116919091179055565b6111dd838383611025565b73ffffffffffffffffffffffffffffffffffffffff82163b15806112d157506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ad9190614e09565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b61103b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e54000000000000000000000000000000006044820152606401610b0b565b60056000611344836114d7565b73ffffffffffffffffffffffffffffffffffffffff1681526020808201929092526040908101600090812033825290925290205460ff161580156113ac575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b80156113d65750336113bd826114d7565b73ffffffffffffffffffffffffffffffffffffffff1614155b1561140d576040517f770f9e9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61141681613882565b50565b6000611424600b5490565b82106114b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610b0b565b600b82815481106114c5576114c5614e26565b90600052602060002001549050919050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611563576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152606401610b0b565b919050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146115e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b828114611622576040517fcebbe75800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b83811015611706577f000000000000000000000000000000000000000000000000000000000000000083838381811061166057611660614e26565b905060200201356007546116749190614e55565b11156116ac576040517f73132c2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116f48585838181106116c1576116c1614e26565b90506020020160208101906116d69190614648565b8484848181106116e8576116e8614e26565b905060200201356138bd565b806116fe81614dd1565b915050611625565b5050505050565b60065473ffffffffffffffffffffffffffffffffffffffff16331461178e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600073ffffffffffffffffffffffffffffffffffffffff8216611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152606401610b0b565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b60065473ffffffffffffffffffffffffffffffffffffffff1633146118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600f805461ffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff909216919091179055565b60018054610c7d90614bf5565b60065473ffffffffffffffffffffffffffffffffffffffff1633146119c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600e55565b60065473ffffffffffffffffffffffffffffffffffffffff163314611a4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6000828152601860209081526040918290208251606081018452905460ff808216151583526101008204161515928201929092526201000090910473ffffffffffffffffffffffffffffffffffffffff1691810182905290308103611abc57611ab7836138d9565b611d76565b816020015115611b4c576040517f6a62784200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152821690636a62784290602401600060405180830381600087803b158015611b2f57600080fd5b505af1158015611b43573d6000803e3d6000fd5b50505050611d76565b815115611caa576040517f2f745c590000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8181166004840152600060248401528392908316916323b872dd9187908490632f745c5990604401602060405180830381865afa158015611bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c189190614e6d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b158015611c8c57600080fd5b505af1158015611ca0573d6000803e3d6000fd5b5050505050611d76565b60408281015190517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015285811660248301526000604483018190526001606484015260a0608484015260a48301529091169063f242432a9060c401600060405180830381600087803b158015611d5d57600080fd5b505af1158015611d71573d6000803e3d6000fd5b505050505b50505050565b33600081815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b601054601254611e299063ffffffff8416614e55565b1115611e61576040517f893da6c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34611e927f000000000000000000000000000000000000000000000000000000000000000063ffffffff8416614e86565b14611ec9576040517f3716a68d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152601760205260409020546fffffffffffffffffffffffffffffffff16421080611f2a575060008381526017602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1642115b15611f61576040517f4db894d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810184905260548101839052600090607401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600d54601f8a01839004830285018301909352888452935073ffffffffffffffffffffffffffffffffffffffff9091169161203a91899089908190840183828082843760009201919091525061203492508691506139859050565b906139d8565b73ffffffffffffffffffffffffffffffffffffffff1614612087576040517f0db90c6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526016602052604090205483906120a99063ffffffff8516614e55565b11156120e1576040517f60a7a10800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152601660205260408120805463ffffffff85169290612106908490614e55565b925050819055508163ffffffff16601260008282546121259190614e55565b909155506121349050826139fc565b505050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146121bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff92909216919091179055565b60065473ffffffffffffffffffffffffffffffffffffffff163314612275576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60009384526018602052604090932080547fffffffffffffffffffff0000000000000000000000000000000000000000ff00169115157fffffffffffffffffffff0000000000000000000000000000000000000000ffff16919091176201000073ffffffffffffffffffffffffffffffffffffffff9390931692909202919091177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010092151592909202919091179055565b612335858585611025565b73ffffffffffffffffffffffffffffffffffffffff84163b158061241757506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a02906123b09033908a90899089908990600401614ec3565b6020604051808303816000875af11580156123cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f39190614e09565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b611706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e54000000000000000000000000000000006044820152606401610b0b565b60065473ffffffffffffffffffffffffffffffffffffffff1633146124fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60005b8151811015610b205781818151811061251c5761251c614e26565b6020026020010151602001516fffffffffffffffffffffffffffffffff1682828151811061254c5761254c614e26565b6020026020010151600001516fffffffffffffffffffffffffffffffff16106125a1576040517fd965c05e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601454600090815260176020526040902082518390839081106125c6576125c6614e26565b60209081029190910101515181547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff909116178155825183908390811061262157612621614e26565b602090810291909101810151015181546fffffffffffffffffffffffffffffffff9182167001000000000000000000000000000000000291161781556014805460009061266d90614dd1565b9091555081905061267d81614dd1565b915050612501565b60065473ffffffffffffffffffffffffffffffffffffffff163314612706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60005b8181101561276b576011805460018181018355600092909252602081047f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801805460ff808816601f9094166101000a9384029302191691909117905501612709565b50806010600082825461277e9190614e55565b90915550505050565b60608160075410156127c5576040517f0b39e1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600880546127d290614bf5565b80601f01602080910402602001604051908101604052809291908181526020018280546127fe90614bf5565b801561284b5780601f106128205761010080835404028352916020019161284b565b820191906000526020600020905b81548152906001019060200180831161282e57829003601f168201915b50505050509050919050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146128d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6128e56020820182614f42565b601980547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff929092169190911790556129366040820160208301614f42565b601980546fffffffffffffffffffffffffffffffff92831670010000000000000000000000000000000002921691909117905550565b60065473ffffffffffffffffffffffffffffffffffffffff1633146129ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600f805467ffffffffffffffff9092166601000000000000027fffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffff909216919091179055565b601054601254612a489063ffffffff8416614e55565b1115612a80576040517f893da6c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34612ab17f000000000000000000000000000000000000000000000000000000000000000063ffffffff8416614e86565b14612ae8576040517f3716a68d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6019546fffffffffffffffffffffffffffffffff16421080612b31575060195470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1642115b15612b68576040517f4db894d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148163ffffffff161115612ba9576040517f60a7a10800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8063ffffffff1660126000828254612bc19190614e55565b909155506114169050816139fc565b60065473ffffffffffffffffffffffffffffffffffffffff163314612c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114612cac576040519150601f19603f3d011682016040523d82523d6000602084013e612cb1565b606091505b509150915081611d76576040517f67b2cd0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065473ffffffffffffffffffffffffffffffffffffffff163314612d6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6040805160008152602081019182905251612d8b916011916142aa565b50601055565b73ffffffffffffffffffffffffffffffffffffffff8216612e0e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e540000000000000000000000000000006044820152606401610b0b565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612e9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e5445440000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260036020908152604080832080546001019055848352600290915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480612fbd57507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610a885750507fffffffff00000000000000000000000000000000000000000000000000000000167f5b5e139f000000000000000000000000000000000000000000000000000000001490565b60005b815181101561103b576011548251600090829085908590811061303357613033614e26565b60200260200101516130459190614f5d565b90506000601860006011848154811061306057613060614e26565b600091825260208083208183040154601f90921661010090810a90920460ff9081168552848201959095526040938401909220835160608101855290548086161515825291820490941615159184019190915262010000900473ffffffffffffffffffffffffffffffffffffffff1690820152905060116130e2600185614f98565b815481106130f2576130f2614e26565b90600052602060002090602091828204019190069054906101000a900460ff166011838154811061312557613125614e26565b90600052602060002090602091828204019190066101000a81548160ff021916908360ff160217905550601180548061316057613160614faf565b600082815260208082207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909301818104909301805460ff601f86166101000a02191690559190925587825260159052604090819020549082015173ffffffffffffffffffffffffffffffffffffffff9182169130908216036131eb576131e6826138d9565b6134a5565b82602001511561327b576040517f6a62784200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152821690636a62784290602401600060405180830381600087803b15801561325e57600080fd5b505af1158015613272573d6000803e3d6000fd5b505050506134a5565b8251156133d9576040517f2f745c590000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8181166004840152600060248401528392908316916323b872dd9186908490632f745c5990604401602060405180830381865afa158015613323573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133479190614e6d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b1580156133bb57600080fd5b505af11580156133cf573d6000803e3d6000fd5b50505050506134a5565b60408381015190517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015284811660248301526000604483018190526001606484015260a0608484015260a48301529091169063f242432a9060c401600060405180830381600087803b15801561348c57600080fd5b505af11580156134a0573d6000803e3d6000fd5b505050505b856001019550505050505061300e565b73ffffffffffffffffffffffffffffffffffffffff831661351d5761351881600b80546000838152600c60205260408120829055600182018355919091527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90155565b61355a565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461355a5761355a8382613b67565b73ffffffffffffffffffffffffffffffffffffffff821661357e5761103b81613c1e565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161461103b5761103b8282613ccd565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff84811691161461364b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f57524f4e475f46524f4d000000000000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff82166136c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e540000000000000000000000000000006044820152606401610b0b565b3373ffffffffffffffffffffffffffffffffffffffff8416148061371c575073ffffffffffffffffffffffffffffffffffffffff8316600090815260056020908152604080832033845290915290205460ff165b8061374a575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633145b6137b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a45440000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055938616808352848320805460010190558583526002825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6000818152600260205260408120546138b49173ffffffffffffffffffffffffffffffffffffffff90911690836134b5565b61141681613d1e565b60005b8181101561103b576138d1836138d9565b6001016138c0565b7f000000000000000000000000000000000000000000000000000000000000000060075410613964576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4d617820737570706c79207265616368656400000000000000000000000000006044820152606401610b0b565b60076000815461397390614dd1565b90915550600754611416908290613e68565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b60008060006139e78585613e7e565b915091506139f481613eec565b509392505050565b63ffffffff811615611416576000600a8263ffffffff1611613a1e5781613a21565b600a5b9050613a2d8183614fde565b600e54600f546040517f5d3b1d3000000000000000000000000000000000000000000000000000000000815260048101929092526601000000000000810467ffffffffffffffff166024830152640100000000810461ffff16604483015263ffffffff9081166064830152831660848201529092506000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a4016020604051808303816000875af1158015613b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b299190614e6d565b600090815260156020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055506139fc9050565b60006001613b74846117d5565b613b7e9190614f98565b6000838152600a6020526040902054909150808214613bde5773ffffffffffffffffffffffffffffffffffffffff841660009081526009602090815260408083208584528252808320548484528184208190558352600a90915290208190555b506000918252600a6020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600981528383209183525290812055565b600b54600090613c3090600190614f98565b6000838152600c6020526040812054600b8054939450909284908110613c5857613c58614e26565b9060005260206000200154905080600b8381548110613c7957613c79614e26565b6000918252602080832090910192909255828152600c9091526040808220849055858252812055600b805480613cb157613cb1614faf565b6001900381819060005260206000200160009055905550505050565b6000613cd8836117d5565b73ffffffffffffffffffffffffffffffffffffffff90931660009081526009602090815260408083208684528252808320859055938252600a9052919091209190915550565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613daa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190558583526002825280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b613e74600083836134b5565b610b208282612d91565b6000808251604103613eb45760208301516040840151606085015160001a613ea887828585614140565b94509450505050613ee5565b8251604003613edd5760208301516040840151613ed2868383614258565b935093505050613ee5565b506000905060025b9250929050565b6000816004811115613f0057613f00615003565b03613f085750565b6001816004811115613f1c57613f1c615003565b03613f83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b0b565b6002816004811115613f9757613f97615003565b03613ffe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b0b565b600381600481111561401257614012615003565b0361409f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b0b565b60048160048111156140b3576140b3615003565b03611416576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b0b565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614177575060009050600361424f565b8460ff16601b1415801561418f57508460ff16601c14155b156141a0575060009050600461424f565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156141f4573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166142485760006001925092505061424f565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161428e60ff86901c601b614e55565b905061429c87828885614140565b935093505050935093915050565b82805482825590600052602060002090601f016020900481019282156143405791602002820160005b8382111561431157835183826101000a81548160ff021916908360ff16021790555092602001926001016020816000010492830192600103026142d3565b801561433e5782816101000a81549060ff0219169055600101602081600001049283019260010302614311565b505b5061434c929150614350565b5090565b5b8082111561434c5760008155600101614351565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461141657600080fd5b6000602082840312156143a557600080fd5b81356143b081614365565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715614409576144096143b7565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614456576144566143b7565b604052919050565b6000602080838503121561447157600080fd5b823567ffffffffffffffff8082111561448957600080fd5b818501915085601f83011261449d57600080fd5b8135818111156144af576144af6143b7565b6144df847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161440f565b915080825286848285010111156144f557600080fd5b8084840185840137600090820190930192909252509392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461141657600080fd5b8035801515811461156357600080fd5b6000806000806080858703121561455957600080fd5b843561456481614511565b935061457260208601614533565b925061458060408601614533565b9396929550929360600135925050565b600060208083528351808285015260005b818110156145bd578581018301518582016040015282016145a1565b818111156145cf576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561461557600080fd5b5035919050565b6000806040838503121561462f57600080fd5b823561463a81614511565b946020939093013593505050565b60006020828403121561465a57600080fd5b81356143b081614511565b600067ffffffffffffffff82111561467f5761467f6143b7565b5060051b60200190565b6000806040838503121561469c57600080fd5b8235915060208084013567ffffffffffffffff8111156146bb57600080fd5b8401601f810186136146cc57600080fd5b80356146df6146da82614665565b61440f565b81815260059190911b820183019083810190888311156146fe57600080fd5b928401925b8284101561471c57833582529284019290840190614703565b80955050505050509250929050565b60008060006060848603121561474057600080fd5b833561474b81614511565b9250602084013561475b81614511565b929592945050506040919091013590565b80356fffffffffffffffffffffffffffffffff8116811461156357600080fd5b6000806000606084860312156147a157600080fd5b833592506147b16020850161476c565b91506147bf6040850161476c565b90509250925092565b60008083601f8401126147da57600080fd5b50813567ffffffffffffffff8111156147f257600080fd5b6020830191508360208260051b8501011115613ee557600080fd5b6000806000806040858703121561482357600080fd5b843567ffffffffffffffff8082111561483b57600080fd5b614847888389016147c8565b9096509450602087013591508082111561486057600080fd5b5061486d878288016147c8565b95989497509550505050565b60006020828403121561488b57600080fd5b813561ffff811681146143b057600080fd5b600080604083850312156148b057600080fd5b8235915060208301356148c281614511565b809150509250929050565b600080604083850312156148e057600080fd5b82356148eb81614511565b91506148f960208401614533565b90509250929050565b60008083601f84011261491457600080fd5b50813567ffffffffffffffff81111561492c57600080fd5b602083019150836020828501011115613ee557600080fd5b803563ffffffff8116811461156357600080fd5b60008060008060006080868803121561497057600080fd5b853567ffffffffffffffff81111561498757600080fd5b61499388828901614902565b90965094505060208601359250604086013591506149b360608701614944565b90509295509295909350565b6000602082840312156149d157600080fd5b6143b082614944565b600080600080608085870312156149f057600080fd5b843593506020850135614a0281614511565b9250614a1060408601614533565b9150614a1e60608601614533565b905092959194509250565b600080600080600060808688031215614a4157600080fd5b8535614a4c81614511565b94506020860135614a5c81614511565b935060408601359250606086013567ffffffffffffffff811115614a7f57600080fd5b614a8b88828901614902565b969995985093965092949392505050565b60006020808385031215614aaf57600080fd5b823567ffffffffffffffff811115614ac657600080fd5b8301601f81018513614ad757600080fd5b8035614ae56146da82614665565b81815260069190911b82018301908381019087831115614b0457600080fd5b928401925b82841015614b565760408489031215614b225760008081fd5b614b2a6143e6565b614b338561476c565b8152614b4086860161476c565b8187015282526040939093019290840190614b09565b979650505050505050565b60008060408385031215614b7457600080fd5b823560ff8116811461463a57600080fd5b600060408284031215614b9757600080fd5b50919050565b60008060408385031215614bb057600080fd5b8235614bbb81614511565b915060208301356148c281614511565b600060208284031215614bdd57600080fd5b813567ffffffffffffffff811681146143b057600080fd5b600181811c90821680614c0957607f821691505b602082108103614b97577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561103b57600081815260208120601f850160051c81016020861015614c695750805b601f850160051c820191505b8181101561213457828155600101614c75565b815167ffffffffffffffff811115614ca257614ca26143b7565b614cb681614cb08454614bf5565b84614c42565b602080601f831160018114614d095760008415614cd35750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555612134565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614d5657888601518255948401946001909101908401614d37565b5085821015614d9257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614e0257614e02614da2565b5060010190565b600060208284031215614e1b57600080fd5b81516143b081614365565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115614e6857614e68614da2565b500190565b600060208284031215614e7f57600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ebe57614ebe614da2565b500290565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509695505050505050565b600060208284031215614f5457600080fd5b6143b08261476c565b600082614f93577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600082821015614faa57614faa614da2565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600063ffffffff83811690831681811015614ffb57614ffb614da2565b039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220b3787f1c0442129146dc2167c9ec1391f227ef854fc8d4c6d91045ccab1f8fee64736f6c634300080f0033000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699098af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000000a9000000000000000000000000f27276ef311886b6433865db600fa7e3d4d86b13000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c0620000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000000d50554e4b5320436f6d69632033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006434f4d49433300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d5a66693833795a396b45347154683366417a72725532526f4547516444514d774a6673324e6e39466f4b65432f00000000000000000000

Deployed Bytecode

0x6080604052600436106102fd5760003560e01c8063845ddcb21161018f578063b88d4fde116100e1578063e985e9c51161008a578063f151d79111610064578063f151d791146109df578063f3fef3a3146109f2578063ff69b94b14610a1257600080fd5b8063e985e9c5146108f9578063ea7b4f7714610934578063eccb3a4f1461095457600080fd5b8063c87b56dd116100bb578063c87b56dd14610876578063d1a4647714610896578063d84058f3146108b657600080fd5b8063b88d4fde14610816578063bfecafe514610836578063c6ca404f1461085657600080fd5b80639854471011610143578063a4be83431161011d578063a4be8343146107c3578063a4eb718c146107d6578063af676625146107f657600080fd5b80639854471014610763578063a0e59e2e14610783578063a22cb465146107a357600080fd5b80638d859f3e116101745780638d859f3e146106ed5780638da5cb5b1461072157806395d89b411461074e57600080fd5b8063845ddcb21461064d5780638824f5a7146106cd57600080fd5b80632f745c59116102535780634f6ccce7116101fc57806369f7d2f2116101d657806369f7d2f2146105ed5780636c19e7831461060d57806370a082311461062d57600080fd5b80634f6ccce71461059757806352a16bb0146105b75780636352211e146105cd57600080fd5b806342842e0e1161022d57806342842e0e1461052a57806342966c681461054a578063438a67e71461056a57600080fd5b80632f745c59146104d457806335d305ad146104f45780633e30046a1461051457600080fd5b8063095ea7b3116102b557806318160ddd1161028f57806318160ddd146104755780631fe543e31461049457806323b872dd146104b457600080fd5b8063095ea7b31461040357806313af403514610423578063171ee95a1461044357600080fd5b806304c624d0116102e657806304c624d01461035957806306fdde0314610379578063081812fc1461039b57600080fd5b806301ffc9a71461030257806302fe530514610337575b600080fd5b34801561030e57600080fd5b5061032261031d366004614393565b610a32565b60405190151581526020015b60405180910390f35b34801561034357600080fd5b5061035761035236600461445e565b610a8e565b005b34801561036557600080fd5b50610357610374366004614543565b610b24565b34801561038557600080fd5b5061038e610c70565b60405161032e9190614590565b3480156103a757600080fd5b506103de6103b6366004614603565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161032e565b34801561040f57600080fd5b5061035761041e36600461461c565b610cfe565b34801561042f57600080fd5b5061035761043e366004614648565b610e48565b34801561044f57600080fd5b5061046361045e366004614603565b610f3a565b60405160ff909116815260200161032e565b34801561048157600080fd5b50600b545b60405190815260200161032e565b3480156104a057600080fd5b506103576104af366004614689565b610f6e565b3480156104c057600080fd5b506103576104cf36600461472b565b611025565b3480156104e057600080fd5b506104866104ef36600461461c565b611040565b34801561050057600080fd5b5061035761050f36600461478c565b61110f565b34801561052057600080fd5b5061048660105481565b34801561053657600080fd5b5061035761054536600461472b565b6111d2565b34801561055657600080fd5b50610357610565366004614603565b611337565b34801561057657600080fd5b50610486610585366004614648565b60166020526000908152604090205481565b3480156105a357600080fd5b506104866105b2366004614603565b611419565b3480156105c357600080fd5b5061048660125481565b3480156105d957600080fd5b506103de6105e8366004614603565b6114d7565b3480156105f957600080fd5b5061035761060836600461480d565b611568565b34801561061957600080fd5b50610357610628366004614648565b61170d565b34801561063957600080fd5b50610486610648366004614648565b6117d5565b34801561065957600080fd5b506106a4610668366004614603565b6017602052600090815260409020546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041682565b604080516fffffffffffffffffffffffffffffffff93841681529290911660208301520161032e565b3480156106d957600080fd5b506103576106e8366004614879565b61187d565b3480156106f957600080fd5b506104867f00000000000000000000000000000000000000000000000002c68af0bb14000081565b34801561072d57600080fd5b506006546103de9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561075a57600080fd5b5061038e61193b565b34801561076f57600080fd5b5061035761077e366004614603565b611948565b34801561078f57600080fd5b5061035761079e36600461489d565b6119ce565b3480156107af57600080fd5b506103576107be3660046148cd565b611d7c565b6103576107d1366004614958565b611e13565b3480156107e257600080fd5b506103576107f13660046149bf565b61213c565b34801561080257600080fd5b506103576108113660046149da565b6121f4565b34801561082257600080fd5b50610357610831366004614a29565b61232a565b34801561084257600080fd5b50610357610851366004614a9c565b61247d565b34801561086257600080fd5b50610357610871366004614b61565b612685565b34801561088257600080fd5b5061038e610891366004614603565b612787565b3480156108a257600080fd5b506103576108b1366004614b85565b612857565b3480156108c257600080fd5b506103de6108d1366004614603565b60156020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b34801561090557600080fd5b50610322610914366004614b9d565b600560209081526000928352604080842090915290825290205460ff1681565b34801561094057600080fd5b5061035761094f366004614bcb565b61296c565b34801561096057600080fd5b506109ac61096f366004614603565b60186020526000908152604090205460ff8082169161010081049091169062010000900473ffffffffffffffffffffffffffffffffffffffff1683565b604080519315158452911515602084015273ffffffffffffffffffffffffffffffffffffffff169082015260600161032e565b6103576109ed3660046149bf565b612a32565b3480156109fe57600080fd5b50610357610a0d36600461461c565b612bd0565b348015610a1e57600080fd5b50610357610a2d366004614603565b612ced565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610a885750610a8882612f2a565b92915050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610b14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b6008610b208282614c88565b5050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610ba5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60138054600090815260186020526040902080547fffffffffffffffffffff0000000000000000000000000000000000000000ff00168515157fffffffffffffffffffff0000000000000000000000000000000000000000ffff16176201000073ffffffffffffffffffffffffffffffffffffffff881602177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100851515021781559054610c569083612685565b601360008154610c6590614dd1565b909155505050505050565b60008054610c7d90614bf5565b80601f0160208091040260200160405190810160405280929190818152602001828054610ca990614bf5565b8015610cf65780601f10610ccb57610100808354040283529160200191610cf6565b820191906000526020600020905b815481529060010190602001808311610cd957829003601f168201915b505050505081565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1633811480610d61575073ffffffffffffffffffffffffffffffffffffffff8116600090815260056020908152604080832033845290915290205460ff165b610dc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a45440000000000000000000000000000000000006044820152606401610b0b565b60008281526004602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff87811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b60065473ffffffffffffffffffffffffffffffffffffffff163314610ec9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b60118181548110610f4a57600080fd5b9060005260206000209060209182820401919006915054906101000a900460ff1681565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909161461101b576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909166024820152604401610b0b565b610b20828261300b565b6110308383836134b5565b61103b8383836135bb565b505050565b600061104b836117d5565b82106110d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610b0b565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600960209081526040808320938352929052205490565b60065473ffffffffffffffffffffffffffffffffffffffff163314611190576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6000928352601760205260409092206fffffffffffffffffffffffffffffffff9283167001000000000000000000000000000000000292909116919091179055565b6111dd838383611025565b73ffffffffffffffffffffffffffffffffffffffff82163b15806112d157506040517f150b7a020000000000000000000000000000000000000000000000000000000080825233600483015273ffffffffffffffffffffffffffffffffffffffff858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af1158015611289573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ad9190614e09565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b61103b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e54000000000000000000000000000000006044820152606401610b0b565b60056000611344836114d7565b73ffffffffffffffffffffffffffffffffffffffff1681526020808201929092526040908101600090812033825290925290205460ff161580156113ac575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b80156113d65750336113bd826114d7565b73ffffffffffffffffffffffffffffffffffffffff1614155b1561140d576040517f770f9e9600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61141681613882565b50565b6000611424600b5490565b82106114b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610b0b565b600b82815481106114c5576114c5614e26565b90600052602060002001549050919050565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611563576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152606401610b0b565b919050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146115e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b828114611622576040517fcebbe75800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b83811015611706577f0000000000000000000000000000000000000000000000000000000000003a9883838381811061166057611660614e26565b905060200201356007546116749190614e55565b11156116ac576040517f73132c2800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116f48585838181106116c1576116c1614e26565b90506020020160208101906116d69190614648565b8484848181106116e8576116e8614e26565b905060200201356138bd565b806116fe81614dd1565b915050611625565b5050505050565b60065473ffffffffffffffffffffffffffffffffffffffff16331461178e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600073ffffffffffffffffffffffffffffffffffffffff8216611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5a45524f5f4144445245535300000000000000000000000000000000000000006044820152606401610b0b565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b60065473ffffffffffffffffffffffffffffffffffffffff1633146118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600f805461ffff909216640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff909216919091179055565b60018054610c7d90614bf5565b60065473ffffffffffffffffffffffffffffffffffffffff1633146119c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600e55565b60065473ffffffffffffffffffffffffffffffffffffffff163314611a4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6000828152601860209081526040918290208251606081018452905460ff808216151583526101008204161515928201929092526201000090910473ffffffffffffffffffffffffffffffffffffffff1691810182905290308103611abc57611ab7836138d9565b611d76565b816020015115611b4c576040517f6a62784200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152821690636a62784290602401600060405180830381600087803b158015611b2f57600080fd5b505af1158015611b43573d6000803e3d6000fd5b50505050611d76565b815115611caa576040517f2f745c590000000000000000000000000000000000000000000000000000000081527f000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c06273ffffffffffffffffffffffffffffffffffffffff8181166004840152600060248401528392908316916323b872dd9187908490632f745c5990604401602060405180830381865afa158015611bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c189190614e6d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b158015611c8c57600080fd5b505af1158015611ca0573d6000803e3d6000fd5b5050505050611d76565b60408281015190517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c0628116600483015285811660248301526000604483018190526001606484015260a0608484015260a48301529091169063f242432a9060c401600060405180830381600087803b158015611d5d57600080fd5b505af1158015611d71573d6000803e3d6000fd5b505050505b50505050565b33600081815260056020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b601054601254611e299063ffffffff8416614e55565b1115611e61576040517f893da6c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34611e927f00000000000000000000000000000000000000000000000002c68af0bb14000063ffffffff8416614e86565b14611ec9576040517f3716a68d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152601760205260409020546fffffffffffffffffffffffffffffffff16421080611f2a575060008381526017602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1642115b15611f61576040517f4db894d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810184905260548101839052600090607401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600d54601f8a01839004830285018301909352888452935073ffffffffffffffffffffffffffffffffffffffff9091169161203a91899089908190840183828082843760009201919091525061203492508691506139859050565b906139d8565b73ffffffffffffffffffffffffffffffffffffffff1614612087576040517f0db90c6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526016602052604090205483906120a99063ffffffff8516614e55565b11156120e1576040517f60a7a10800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152601660205260408120805463ffffffff85169290612106908490614e55565b925050819055508163ffffffff16601260008282546121259190614e55565b909155506121349050826139fc565b505050505050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146121bd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff92909216919091179055565b60065473ffffffffffffffffffffffffffffffffffffffff163314612275576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60009384526018602052604090932080547fffffffffffffffffffff0000000000000000000000000000000000000000ff00169115157fffffffffffffffffffff0000000000000000000000000000000000000000ffff16919091176201000073ffffffffffffffffffffffffffffffffffffffff9390931692909202919091177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010092151592909202919091179055565b612335858585611025565b73ffffffffffffffffffffffffffffffffffffffff84163b158061241757506040517f150b7a02000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063150b7a02906123b09033908a90899089908990600401614ec3565b6020604051808303816000875af11580156123cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f39190614e09565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b611706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f554e534146455f524543495049454e54000000000000000000000000000000006044820152606401610b0b565b60065473ffffffffffffffffffffffffffffffffffffffff1633146124fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60005b8151811015610b205781818151811061251c5761251c614e26565b6020026020010151602001516fffffffffffffffffffffffffffffffff1682828151811061254c5761254c614e26565b6020026020010151600001516fffffffffffffffffffffffffffffffff16106125a1576040517fd965c05e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601454600090815260176020526040902082518390839081106125c6576125c6614e26565b60209081029190910101515181547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff909116178155825183908390811061262157612621614e26565b602090810291909101810151015181546fffffffffffffffffffffffffffffffff9182167001000000000000000000000000000000000291161781556014805460009061266d90614dd1565b9091555081905061267d81614dd1565b915050612501565b60065473ffffffffffffffffffffffffffffffffffffffff163314612706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b60005b8181101561276b576011805460018181018355600092909252602081047f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801805460ff808816601f9094166101000a9384029302191691909117905501612709565b50806010600082825461277e9190614e55565b90915550505050565b60608160075410156127c5576040517f0b39e1bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600880546127d290614bf5565b80601f01602080910402602001604051908101604052809291908181526020018280546127fe90614bf5565b801561284b5780601f106128205761010080835404028352916020019161284b565b820191906000526020600020905b81548152906001019060200180831161282e57829003601f168201915b50505050509050919050565b60065473ffffffffffffffffffffffffffffffffffffffff1633146128d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6128e56020820182614f42565b601980547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff929092169190911790556129366040820160208301614f42565b601980546fffffffffffffffffffffffffffffffff92831670010000000000000000000000000000000002921691909117905550565b60065473ffffffffffffffffffffffffffffffffffffffff1633146129ed576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b600f805467ffffffffffffffff9092166601000000000000027fffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffff909216919091179055565b601054601254612a489063ffffffff8416614e55565b1115612a80576040517f893da6c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34612ab17f00000000000000000000000000000000000000000000000002c68af0bb14000063ffffffff8416614e86565b14612ae8576040517f3716a68d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6019546fffffffffffffffffffffffffffffffff16421080612b31575060195470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1642115b15612b68576040517f4db894d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60148163ffffffff161115612ba9576040517f60a7a10800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8063ffffffff1660126000828254612bc19190614e55565b909155506114169050816139fc565b60065473ffffffffffffffffffffffffffffffffffffffff163314612c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405160006040518083038185875af1925050503d8060008114612cac576040519150601f19603f3d011682016040523d82523d6000602084013e612cb1565b606091505b509150915081611d76576040517f67b2cd0500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60065473ffffffffffffffffffffffffffffffffffffffff163314612d6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152606401610b0b565b6040805160008152602081019182905251612d8b916011916142aa565b50601055565b73ffffffffffffffffffffffffffffffffffffffff8216612e0e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e540000000000000000000000000000006044820152606401610b0b565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612e9a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f414c52454144595f4d494e5445440000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260036020908152604080832080546001019055848352600290915280822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480612fbd57507f80ac58cd000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b80610a885750507fffffffff00000000000000000000000000000000000000000000000000000000167f5b5e139f000000000000000000000000000000000000000000000000000000001490565b60005b815181101561103b576011548251600090829085908590811061303357613033614e26565b60200260200101516130459190614f5d565b90506000601860006011848154811061306057613060614e26565b600091825260208083208183040154601f90921661010090810a90920460ff9081168552848201959095526040938401909220835160608101855290548086161515825291820490941615159184019190915262010000900473ffffffffffffffffffffffffffffffffffffffff1690820152905060116130e2600185614f98565b815481106130f2576130f2614e26565b90600052602060002090602091828204019190069054906101000a900460ff166011838154811061312557613125614e26565b90600052602060002090602091828204019190066101000a81548160ff021916908360ff160217905550601180548061316057613160614faf565b600082815260208082207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909301818104909301805460ff601f86166101000a02191690559190925587825260159052604090819020549082015173ffffffffffffffffffffffffffffffffffffffff9182169130908216036131eb576131e6826138d9565b6134a5565b82602001511561327b576040517f6a62784200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152821690636a62784290602401600060405180830381600087803b15801561325e57600080fd5b505af1158015613272573d6000803e3d6000fd5b505050506134a5565b8251156133d9576040517f2f745c590000000000000000000000000000000000000000000000000000000081527f000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c06273ffffffffffffffffffffffffffffffffffffffff8181166004840152600060248401528392908316916323b872dd9186908490632f745c5990604401602060405180830381865afa158015613323573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133479190614e6d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526044820152606401600060405180830381600087803b1580156133bb57600080fd5b505af11580156133cf573d6000803e3d6000fd5b50505050506134a5565b60408381015190517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c0628116600483015284811660248301526000604483018190526001606484015260a0608484015260a48301529091169063f242432a9060c401600060405180830381600087803b15801561348c57600080fd5b505af11580156134a0573d6000803e3d6000fd5b505050505b856001019550505050505061300e565b73ffffffffffffffffffffffffffffffffffffffff831661351d5761351881600b80546000838152600c60205260408120829055600182018355919091527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90155565b61355a565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161461355a5761355a8382613b67565b73ffffffffffffffffffffffffffffffffffffffff821661357e5761103b81613c1e565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161461103b5761103b8282613ccd565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff84811691161461364b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f57524f4e475f46524f4d000000000000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff82166136c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f494e56414c49445f524543495049454e540000000000000000000000000000006044820152606401610b0b565b3373ffffffffffffffffffffffffffffffffffffffff8416148061371c575073ffffffffffffffffffffffffffffffffffffffff8316600090815260056020908152604080832033845290915290205460ff165b8061374a575060008181526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1633145b6137b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e4f545f415554484f52495a45440000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff808416600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055938616808352848320805460010190558583526002825284832080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6000818152600260205260408120546138b49173ffffffffffffffffffffffffffffffffffffffff90911690836134b5565b61141681613d1e565b60005b8181101561103b576138d1836138d9565b6001016138c0565b7f0000000000000000000000000000000000000000000000000000000000003a9860075410613964576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4d617820737570706c79207265616368656400000000000000000000000000006044820152606401610b0b565b60076000815461397390614dd1565b90915550600754611416908290613e68565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b60008060006139e78585613e7e565b915091506139f481613eec565b509392505050565b63ffffffff811615611416576000600a8263ffffffff1611613a1e5781613a21565b600a5b9050613a2d8183614fde565b600e54600f546040517f5d3b1d3000000000000000000000000000000000000000000000000000000000815260048101929092526601000000000000810467ffffffffffffffff166024830152640100000000810461ffff16604483015263ffffffff9081166064830152831660848201529092506000907f000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e6990973ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a4016020604051808303816000875af1158015613b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b299190614e6d565b600090815260156020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055506139fc9050565b60006001613b74846117d5565b613b7e9190614f98565b6000838152600a6020526040902054909150808214613bde5773ffffffffffffffffffffffffffffffffffffffff841660009081526009602090815260408083208584528252808320548484528184208190558352600a90915290208190555b506000918252600a6020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600981528383209183525290812055565b600b54600090613c3090600190614f98565b6000838152600c6020526040812054600b8054939450909284908110613c5857613c58614e26565b9060005260206000200154905080600b8381548110613c7957613c79614e26565b6000918252602080832090910192909255828152600c9091526040808220849055858252812055600b805480613cb157613cb1614faf565b6001900381819060005260206000200160009055905550505050565b6000613cd8836117d5565b73ffffffffffffffffffffffffffffffffffffffff90931660009081526009602090815260408083208684528252808320859055938252600a9052919091209190915550565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1680613daa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4e4f545f4d494e544544000000000000000000000000000000000000000000006044820152606401610b0b565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190558583526002825280832080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b613e74600083836134b5565b610b208282612d91565b6000808251604103613eb45760208301516040840151606085015160001a613ea887828585614140565b94509450505050613ee5565b8251604003613edd5760208301516040840151613ed2868383614258565b935093505050613ee5565b506000905060025b9250929050565b6000816004811115613f0057613f00615003565b03613f085750565b6001816004811115613f1c57613f1c615003565b03613f83576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b0b565b6002816004811115613f9757613f97615003565b03613ffe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b0b565b600381600481111561401257614012615003565b0361409f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b0b565b60048160048111156140b3576140b3615003565b03611416576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b0b565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614177575060009050600361424f565b8460ff16601b1415801561418f57508460ff16601c14155b156141a0575060009050600461424f565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156141f4573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166142485760006001925092505061424f565b9150600090505b94509492505050565b6000807f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168161428e60ff86901c601b614e55565b905061429c87828885614140565b935093505050935093915050565b82805482825590600052602060002090601f016020900481019282156143405791602002820160005b8382111561431157835183826101000a81548160ff021916908360ff16021790555092602001926001016020816000010492830192600103026142d3565b801561433e5782816101000a81549060ff0219169055600101602081600001049283019260010302614311565b505b5061434c929150614350565b5090565b5b8082111561434c5760008155600101614351565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461141657600080fd5b6000602082840312156143a557600080fd5b81356143b081614365565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715614409576144096143b7565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614456576144566143b7565b604052919050565b6000602080838503121561447157600080fd5b823567ffffffffffffffff8082111561448957600080fd5b818501915085601f83011261449d57600080fd5b8135818111156144af576144af6143b7565b6144df847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161440f565b915080825286848285010111156144f557600080fd5b8084840185840137600090820190930192909252509392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461141657600080fd5b8035801515811461156357600080fd5b6000806000806080858703121561455957600080fd5b843561456481614511565b935061457260208601614533565b925061458060408601614533565b9396929550929360600135925050565b600060208083528351808285015260005b818110156145bd578581018301518582016040015282016145a1565b818111156145cf576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561461557600080fd5b5035919050565b6000806040838503121561462f57600080fd5b823561463a81614511565b946020939093013593505050565b60006020828403121561465a57600080fd5b81356143b081614511565b600067ffffffffffffffff82111561467f5761467f6143b7565b5060051b60200190565b6000806040838503121561469c57600080fd5b8235915060208084013567ffffffffffffffff8111156146bb57600080fd5b8401601f810186136146cc57600080fd5b80356146df6146da82614665565b61440f565b81815260059190911b820183019083810190888311156146fe57600080fd5b928401925b8284101561471c57833582529284019290840190614703565b80955050505050509250929050565b60008060006060848603121561474057600080fd5b833561474b81614511565b9250602084013561475b81614511565b929592945050506040919091013590565b80356fffffffffffffffffffffffffffffffff8116811461156357600080fd5b6000806000606084860312156147a157600080fd5b833592506147b16020850161476c565b91506147bf6040850161476c565b90509250925092565b60008083601f8401126147da57600080fd5b50813567ffffffffffffffff8111156147f257600080fd5b6020830191508360208260051b8501011115613ee557600080fd5b6000806000806040858703121561482357600080fd5b843567ffffffffffffffff8082111561483b57600080fd5b614847888389016147c8565b9096509450602087013591508082111561486057600080fd5b5061486d878288016147c8565b95989497509550505050565b60006020828403121561488b57600080fd5b813561ffff811681146143b057600080fd5b600080604083850312156148b057600080fd5b8235915060208301356148c281614511565b809150509250929050565b600080604083850312156148e057600080fd5b82356148eb81614511565b91506148f960208401614533565b90509250929050565b60008083601f84011261491457600080fd5b50813567ffffffffffffffff81111561492c57600080fd5b602083019150836020828501011115613ee557600080fd5b803563ffffffff8116811461156357600080fd5b60008060008060006080868803121561497057600080fd5b853567ffffffffffffffff81111561498757600080fd5b61499388828901614902565b90965094505060208601359250604086013591506149b360608701614944565b90509295509295909350565b6000602082840312156149d157600080fd5b6143b082614944565b600080600080608085870312156149f057600080fd5b843593506020850135614a0281614511565b9250614a1060408601614533565b9150614a1e60608601614533565b905092959194509250565b600080600080600060808688031215614a4157600080fd5b8535614a4c81614511565b94506020860135614a5c81614511565b935060408601359250606086013567ffffffffffffffff811115614a7f57600080fd5b614a8b88828901614902565b969995985093965092949392505050565b60006020808385031215614aaf57600080fd5b823567ffffffffffffffff811115614ac657600080fd5b8301601f81018513614ad757600080fd5b8035614ae56146da82614665565b81815260069190911b82018301908381019087831115614b0457600080fd5b928401925b82841015614b565760408489031215614b225760008081fd5b614b2a6143e6565b614b338561476c565b8152614b4086860161476c565b8187015282526040939093019290840190614b09565b979650505050505050565b60008060408385031215614b7457600080fd5b823560ff8116811461463a57600080fd5b600060408284031215614b9757600080fd5b50919050565b60008060408385031215614bb057600080fd5b8235614bbb81614511565b915060208301356148c281614511565b600060208284031215614bdd57600080fd5b813567ffffffffffffffff811681146143b057600080fd5b600181811c90821680614c0957607f821691505b602082108103614b97577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b601f82111561103b57600081815260208120601f850160051c81016020861015614c695750805b601f850160051c820191505b8181101561213457828155600101614c75565b815167ffffffffffffffff811115614ca257614ca26143b7565b614cb681614cb08454614bf5565b84614c42565b602080601f831160018114614d095760008415614cd35750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555612134565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015614d5657888601518255948401946001909101908401614d37565b5085821015614d9257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614e0257614e02614da2565b5060010190565b600060208284031215614e1b57600080fd5b81516143b081614365565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115614e6857614e68614da2565b500190565b600060208284031215614e7f57600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614ebe57614ebe614da2565b500290565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015260806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011683010190509695505050505050565b600060208284031215614f5457600080fd5b6143b08261476c565b600082614f93577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500690565b600082821015614faa57614faa614da2565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600063ffffffff83811690831681811015614ffb57614ffb614da2565b039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220b3787f1c0442129146dc2167c9ec1391f227ef854fc8d4c6d91045ccab1f8fee64736f6c634300080f0033

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

000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e699098af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef00000000000000000000000000000000000000000000000000000000000000a9000000000000000000000000f27276ef311886b6433865db600fa7e3d4d86b13000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c0620000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000000d50554e4b5320436f6d69632033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006434f4d49433300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d5a66693833795a396b45347154683366417a72725532526f4547516444514d774a6673324e6e39466f4b65432f00000000000000000000

-----Decoded View---------------
Arg [0] : _vrfCoordinator (address): 0x271682DEB8C4E0901D1a1550aD2e64D568E69909
Arg [1] : _keyHash (bytes32): 0x8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [2] : _subscriptionId (uint64): 169
Arg [3] : _signer (address): 0xF27276eF311886b6433865Db600fa7E3D4D86b13
Arg [4] : _tokenHolder (address): 0xcf3bC13C0F19B9549364CC5F4b7EA807b737C062
Arg [5] : _name (string): PUNKS Comic 3
Arg [6] : _symbol (string): COMIC3
Arg [7] : _uri (string): ipfs://QmZfi83yZ9kE4qTh3fAzrrU2RoEGQdDQMwJfs2Nn9FoKeC/
Arg [8] : _price (uint256): 200000000000000000

-----Encoded View---------------
16 Constructor Arguments found :
Arg [0] : 000000000000000000000000271682deb8c4e0901d1a1550ad2e64d568e69909
Arg [1] : 8af398995b04c28e9951adb9721ef74c74f93e6a478f39e7e0777be13527e7ef
Arg [2] : 00000000000000000000000000000000000000000000000000000000000000a9
Arg [3] : 000000000000000000000000f27276ef311886b6433865db600fa7e3d4d86b13
Arg [4] : 000000000000000000000000cf3bc13c0f19b9549364cc5f4b7ea807b737c062
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [7] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [8] : 00000000000000000000000000000000000000000000000002c68af0bb140000
Arg [9] : 000000000000000000000000000000000000000000000000000000000000000d
Arg [10] : 50554e4b5320436f6d6963203300000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [12] : 434f4d4943330000000000000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000036
Arg [14] : 697066733a2f2f516d5a66693833795a396b45347154683366417a7272553252
Arg [15] : 6f4547516444514d774a6673324e6e39466f4b65432f00000000000000000000


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.