ETH Price: $3,344.52 (-1.47%)

Token

Nuclear Nerds Comic (NERDSCOMIC)
 

Overview

Max Total Supply

0 NERDSCOMIC

Holders

3,121

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A

Other Info

Filtered by Token Holder
TATR tech: Deployer
Balance
1 NERDSCOMIC
0xee96703614ea707b0b99ecb55da74c04ff70f2ed
Loading...
Loading
Loading...
Loading
Loading...
Loading

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

Contract Source Code Verified (Exact Match)

Contract Name:
MimeticComic

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 16 : MimeticComic.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

import { ERC721 } from "./ERC721/ERC721.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IMimeticComic } from "./IMimeticComic.sol";
import { Base64 } from "./Base64.sol"; 
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IMirror } from "./IMirror.sol";
import { IERC2981 } from "@openzeppelin/contracts/interfaces/IERC2981.sol";

/**
 * @title Mimetic Comic w/ Phantom Ownership
 * @author @nftchance and @masonthechain 
 * @dev Implementation of EIP-721 Non-Fungible Token Standard, including the 
 *      Metadata extension and combining with the usage of Mimetic Metadata, 
 *      Phantom Ownership, and EIP-2309. Many of the features included in this 
 *      contract will be limited time use / reserved for the future. 
 * @dev The use of hooks is not enabled by default which will leave some 
 *      indexers not having the most up to date ownership record. Hooks solve 
 *      this, however full benefits can only be enjoyed after migration.
 */
contract MimeticComic is
      ERC721
    , Ownable
    , IMimeticComic
{
    using Strings for uint8;
    using Strings for uint256;

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

    ///@dev Comic series metadata info and redemption time period.
    struct Series {
        string description;     // Token description in displays
        string ipfsHash;        // Comic book cover
        uint256 issuanceEnd;    // When this issue can no longer be focused
    }

    ///@dev Comic series index to series data.
    mapping(uint8 => Series) public seriesToSeries;

    ///@dev Token id to comic series index.
    mapping(uint256 => uint256) internal tokenToSeries;

    ///@dev Number of comic series indexes stored in a single index.
    uint256 public constant PACKED = 64;
    
    ///@dev Number of bytes a series can take up.
    uint256 public constant PACKED_SHIFT = 4;
    
    ///@dev Number of tokens required for end-of-road redemption.
    uint256 public constant REDEMPTION_QUALIFIER = 13;

    ///@dev Nuclear Nerds token id to comic wildcard condition truth.
    mapping(uint256 => bool) internal nerdToWildcard;

    ///@dev The default description of the collection and tokens.
    string private collectionDescription;

    ///@dev Disclaimer message appended to wildcard tokens for buyer safety.
    string private wildcardDescription;

    ///@dev Disclaimer message appended to tokens that have been redeemed.
    string private redeemedDescription;

    ///@dev Management of redemption booleans bitpacked to lower storage needs.
    ///@notice `tokens` as it is a bitpacked mapping returned.
    mapping(uint256 => uint256) public tokensToRedeemed;

    /*//////////////////////////////////////////////////////////////
                      COLLECTION STATE MANAGEMENT
    //////////////////////////////////////////////////////////////*/

    ///@dev Controls whether or not wildcards can be loaded.
    bool public wildcardsLocked;

    ///@dev Controls whether or not master actions can be called.
    bool public masterLocked;

    ///@dev Controls all series progression within the collection.
    bool public locked;

    ///@dev Nuclear Nerd contracts that call transferHooks upon transfer.
    mapping(address => bool) public hooks;

    /*//////////////////////////////////////////////////////////////
                            ROYALTY LOGIC
    //////////////////////////////////////////////////////////////*/
    
    ///@dev IPFS hash to the contract URI json.
    string public contractURIHash;

    ///@dev On-chain royalty basis points.
    uint256 public royaltyBasis = 690;
    
    ///@dev The floating point percentage used for royalty calculation.
    uint256 private constant percentageTotal = 10000;

    ///@dev Team address that receives royalties from secondary sales.
    address public royaltyReceiver;

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    ///@dev EIP-2309 standard for more efficient ownership indexing events.
    event ConsecutiveTransfer(
          uint256 indexed fromTokenId
        , uint256 toTokenId
        , address indexed fromAddress
        , address indexed toAddress
    );

    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error CollectionStateInvalid();
    error CollectionMasterLocked();
    error CollectionWildcardsLocked();

    error HookCallerMismatch();

    error TokenMinted();
    error TokenDoesNotExist();
    error TokenOwnerMismatch();
    error TokenNotWildcard();
    error TokenBundleInvalid();
    error TokenRedeemed();

    error SeriesNotLoaded();
    error SeriesAlreadyLoaded();
    error SeriesAlreadyLocked();
    error SeriesNotLocked();
    error SeriesDirectionProhibited();
    error SeriesBundleInvalid();

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

    constructor(
          string memory _name
        , string memory _symbol
        , string memory _seriesZeroDescription
        , string memory _seriesZeroHash
        , string memory _collectionDescription
        , string memory _wildcardDescription
        , string memory _redeemedDescription        
        , address _nerds
        , address _royaltyReceiver
        , string memory _contractURIHash
    ) ERC721(
          _name
        , _symbol
        , _nerds
    ) {
        ///@dev Initialize series 0 that everyone starts with.
        seriesToSeries[0] = Series(
              _seriesZeroDescription
            , _seriesZeroHash
            , 42069
        );

        collectionDescription = _collectionDescription;
        wildcardDescription = _wildcardDescription;
        redeemedDescription = _redeemedDescription;

        royaltyReceiver = _royaltyReceiver;
        contractURIHash = _contractURIHash;
    }

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

    ///@dev Prevents master locked actions.
    modifier onlyMasterUnlocked() {
        if(masterLocked) revert CollectionMasterLocked();
        _;
    }

    ///@dev Prevents unlocked actions.
    modifier onlyUnlocked() {
        if(locked) revert SeriesAlreadyLocked();
        _;
    }

    ///@dev Prevents locked actions.
    modifier onlyLocked() {
        if(!locked) revert SeriesNotLocked();
        _;
    }

    ///@dev Prevents actions not on a non-loaded series.
    modifier onlyLoaded(uint8 _series) {
        if(bytes(seriesToSeries[_series].ipfsHash).length == 0)
            revert SeriesNotLoaded();
        _;
    }

    ///@dev Prevents actions on tokenIds greater than max supply.
    modifier onlyInRange(uint256 _tokenId) {
        if(_tokenId > MAX_SUPPLY - 1) revert TokenDoesNotExist();
        _;
    }

    /*//////////////////////////////////////////////////////////////
                        METADATA INTILIAZATION
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Allows the Nuclear Nerds team migrate the primary Nuclear
     *         Nerds collection without having to migrate comics and 
     *         having instant updates as the comics would follow the migration.
     *         As soon as utilization has completed the enabling of
     *         master lock will prevent this function from ever being used
     *         again. Contract ownership is delegated to multi-sig for 
     *         maximum security.
     * @notice THIS WOULD NOT BE IMPLEMENTED IF IT WAS NOT NEEDED. ;) 
     *         (Short time horizon on the usage and locking.)
     * @param _mirror The address of the parent token to mirror ownership of.
     * 
     * Requires:
     * - sender must be contract owner
     * - `masterLocked` must be false (default value)
     */
    function loadMirror(
        address _mirror
    )
        public
        virtual
        onlyMasterUnlocked()
        onlyOwner()
    { 
        mirror = IMirror(_mirror);
    }

    /**
     * @notice Loads the wildcards that have direct redemption at the
     *         locking-point for physical transformation.
     * @dev This function can only be ran once so that wildcards cannot
     *      be adjusted past the time of being established.
     * @param _tokenIds The ids of the tokens that are wildcards.
     * 
     * Requires:
     * - sender must be contract owner
     * - `wildcardsLocked` hash must be false (default value).
     */
    function loadWildcards(
        uint256[] calldata _tokenIds
    )
        public
        virtual
        onlyOwner()
    {
        if(wildcardsLocked) revert CollectionWildcardsLocked();
        
        wildcardsLocked = true;

        for(
            uint8 i;
            i < _tokenIds.length;
            i++
        ) {
            nerdToWildcard[_tokenIds[i]] = true;
        }
    }

    /**
     * @notice Allows token holders to emit an event with
     *         'refreshed' ownership that using the mirrored ownership
     *         of the parent token. This way, indexers will pick up the new
     *         ownership for far cheaper still without having to write 
     *         ownership.
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     * @dev This is not needed for primary-use however, this is here for
     *      future-proofing backup for any small issues that 
     *      take place upon delivery or future roll outs of new platforms. The 
     *      primary of this use would be that the comic has not been seperated, 
     *      but has found it's in a smart contract that needs the hook to 
     *      complete processing.
     *
     * Requires:
     * - `masterLocked` must be false.
     * - token must NOT be claimed
     * - sender must be owner of the token.
     */
    function refreshToken(
        uint256 _tokenId
    )
        public
        onlyMasterUnlocked()
    {
        if(_exists(_tokenId)) revert TokenMinted();
  
        address _owner = mirror.ownerOf(_tokenId);
        
        if(_msgSender() != _owner) revert TokenOwnerMismatch();

        emit Transfer(
              address(this)
            , _owner
            , _tokenId
        );
    }

    /**
     * @notice Bundle version of token refreshing. This can only be called
     *         if all tokens are still paired and the caller is the owner
     *         of all comics being called.
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     *
     * Requires:
     * - `masterLocked` must be false.
     * - all tokens must NOT be claimed.
     * - sender must be owner of all tokens.
     */
    function refreshTokenBundle(
        uint256[] calldata _tokenIds
    )
        public
        onlyMasterUnlocked()
    {
        if(!mirror.isOwnerOf(
              _msgSender()
            , _tokenIds
        )) revert TokenOwnerMismatch();

        for(
            uint256 i;
            i < _tokenIds.length;
            i++
        ) {
            if(_exists(_tokenIds[i])) revert TokenMinted();

            emit Transfer(
                  address(this)
                , _msgSender()
                , _tokenIds[i]
            );
        }
    }

    /**
     * @notice Allows the Nuclear Nerds team to emit an event with
     *         'refreshed' ownership utilizing the mirrored ownership
     *         of the parent token.
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     * @dev This is not needed for primary-use however, this is here for
     *      future-proofing backup for any small issues that 
     *      take place upon delivery or future roll outs of new platforms. The 
     *      primary of this use would be that the comic has not been seperated, 
     *      but has found it's in a smart contract that needs the hook to 
     *      complete processing.
     *
     * Requires:
     * - `masterLocked` must be false.
     * - sender must be contract owner.
     */
    function loadCollectionOwners(
          uint256 _fromTokenId
        , uint256 _toTokenId
    )
        public
        onlyMasterUnlocked()
        onlyOwner()
    {
        for(
            uint256 tokenId = _fromTokenId;
            tokenId < _toTokenId;
            tokenId++
        ) { 
            address _owner = mirror.ownerOf(tokenId);

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

            require(
                _checkOnERC721Received(
                      address(0)
                    , _owner
                    , tokenId
                    , ""
                )
                , "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    }

    /**
     * @notice Allows the Nuclear Nerds team to emit Transfer events to a 
     *         a specific target. 
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     * @dev This is not needed for primary-use however,
     *      this is here for future-proofing/backup for any small issues that 
     *      take place upon delivery or future roll outs of new platforms.
     * 
     * Requires:
     * - `masterLocked` must be false.
     * - sender must be contract owner.
     * - length of `to` must be the same length as the range of token ids.
     */
    function loadCollectionCalldata(
            uint256 _fromTokenId
          , uint256 _toTokenId
          , address[] calldata _to
    )
        public
        onlyMasterUnlocked()
        onlyOwner()
    { 
        uint256 length =  _toTokenId - _fromTokenId + 1;

        if(length != _to.length) revert CollectionStateInvalid();

        uint256 index;
        for(
            uint256 tokenId = _fromTokenId;
            tokenId <= _toTokenId;
            tokenId++
        ) { 
            emit Transfer(
                  address(0)
                , _to[index++]
                , tokenId
            );
        }
    }

    /**
     * @notice Utilizes EIP-2309 to most efficiently emit the Transfer events
     *         needed to notify the platforms that this token exists.
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     *
     * Requires:
     * - `masterLocked` must be false.
     * - sender must be contract owner
     */
    function loadCollection2309(
            uint256 _fromTokenId
          , uint256 _toTokenId
    ) 
        public
        onlyMasterUnlocked()
        onlyOwner()
    { 
        emit ConsecutiveTransfer(
              _fromTokenId
            , _toTokenId
            , address(0)
            , address(this)
        );
    }

    /**
     * @notice Utilizes EIP-2309 to refresh the ownership of tokens in a 
     *         collective batch. This is to be fired after tokens have been 
     *         minted.
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     *
     * Requires:
     * - `masterLocked` must be false.
     * - sender must be contract owner
     */
    function loadCollection2309From(
            uint256 _fromTokenId
          , uint256 _toTokenId
          , address _from
    ) 
        public
        onlyMasterUnlocked()
        onlyOwner()
    { 
        emit ConsecutiveTransfer(
              _fromTokenId
            , _toTokenId
            , _from
            , address(this)
        );
    }

    /**
     * @notice Utilizes EIP-2309 to most efficiently emit the Transfer events
     *         needed to notify the platforms that this token exists of a 
     *         specific range of token ids AND receivers.
     * @notice Does not update the real ownership state and merely notifies the
     *         platforms of an ownership record 'change' that they need 
     *         to catalog.
     *
     * Requires:
     * - `masterLocked` must be false.
     * - sender must be contract owner
     */
    function loadCollection2309To(
            uint256 _fromTokenId
          , uint256 _toTokenId
          , address _to
    ) 
        public
        onlyMasterUnlocked()
        onlyOwner()
    { 
        emit ConsecutiveTransfer(
              _fromTokenId
            , _toTokenId
            , address(0)
            , _to
        );
    }

    /**
     * @notice Allows owners of contract to initialize a new series of 
     *         the comic as Chapter 12 cannot be published on the same
     *         day as Chapter 1.
     * @dev Fundamentally, a series is 'just' an IPFS hash.
     * @param _series The index of the series being initialized.
     * @param _ipfsHash The ipfs hash of the cover image of the series.
     * @param _issuanceEnd When the issue can no longer be focused.
     * 
     * Requires:
     * - `locked` must be false.
     * - sender must be contract owner
     * `_series` hash must not be set.
     */
    function loadSeries(
          uint8 _series
        , string memory _description
        , string memory _ipfsHash
        , uint256 _issuanceEnd
    )
        override
        public
        virtual
        onlyUnlocked()
        onlyOwner()
    {
        if(bytes(seriesToSeries[_series].ipfsHash).length != 0) {
            revert SeriesAlreadyLoaded();
        }

        seriesToSeries[_series] = Series(
              _description
            , _ipfsHash
            , _issuanceEnd
        );
    }

    /*//////////////////////////////////////////////////////////////
                            LOCK MANAGEMENT
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Locks the emission of Nuclear Nerd team member called 
     *         loadCollection(x). By default this will remain open,
     *         however with time and the completed release of series
     *         the community may prefer the contract reach a truly 
     *         immutable and decentralized state.
     *
     * Requires:
     * - sender must be contract owner
     */
    function masterLock()
        public
        virtual
        onlyOwner()
    {
        masterLocked = true;
    }

    /**
     * @notice Locks the series upgrading of the collection preventing any
     *         further series from being added and preventing holders
     *         from upgrading their series any further.
     * 
     * Requires:
     * - sender must be contract owner
     */
    function lock()
        override
        public
        virtual
        onlyOwner()
    {     
        locked = true;
    }

    /*//////////////////////////////////////////////////////////////
                            HOOK MANAGEMENT
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Allows The Nuclear Nerd team to connect Transfer hooks
     *         to the comic state of a token.
     * @dev Future feature. This can also be completely disabled and 
     *      then locked to prevent any new team additions of hook contracts.
     * @param _hook The address of the contract to accept an incoming 
     *              event from.
     * 
     * Requires:
     * - `masterLocked` must be false.
     * - sender must be contract owner.
     */
    function toggleHook(
        address _hook
    )
        public
        onlyMasterUnlocked()
        onlyOwner()
    {
        hooks[_hook] = !hooks[_hook];
    }

    /**
     * @notice Handles the processing when a parent token of this
     *         is transferred. To be procesed within the handling of 
     *         of the parent token. With this, ownership
     *         of the child token will update immediately across all
     *         indexers, marketplaces and tools.
     * @dev Only emits an event for children tokens that haven't been seperated.
     * @param _from The address transferring the parent token.
     * @param _to The address transferring the child token.
     * @param _tokenId The id of the parent:child token being transferred.
     * 
     * Requires:
     * - sender must be an enabled hook contract.
     */
    function transferHook(
          address _from
        , address _to
        , uint256 _tokenId
    )
        public
        virtual
    {
        if(!hooks[_msgSender()]) revert HookCallerMismatch();

        if(!_exists(_tokenId)) {
            delete _tokenApprovals[_tokenId][_from];
            emit Approval(
                  _from
                , address(0)
                , _tokenId
            );

            emit Transfer(
                  _from
                , _to
                , _tokenId
            );
        }
    }

    /**
     * @notice Handles the processing when a parent token of this
     *         is transferred. To be procesed within the handling of 
     *         of the parent token. With this, ownership
     *         of the child token will update immediately across all
     *         indexers, marketplaces and tools.
     * @dev Only emits an event for children tokens that haven't been seperated.
     * @param _from The address transferring the parent token.
     * @param _to The address transferring the child token.
     * @param _tokenId The id of the parent:child token being transferred.
     * 
     * Requires:
     * - sender must be an enabled hook contract.
     */
    function safeTransferHook(
          address _from
        , address _to
        , uint256 _tokenId
        , bytes memory _data
    )
        public
        virtual
    {
        if(!hooks[_msgSender()]) revert HookCallerMismatch();

        if(!_exists(_tokenId)) {
            delete _tokenApprovals[_tokenId][_from];
            emit Approval(
                  _from
                , address(0)
                , _tokenId
            );

            emit Transfer(
                  _from
                , _to
                , _tokenId
            );

            require(
                  _checkOnERC721Received(
                        _from
                      , _to
                      , _tokenId
                      , _data
                  )
                , "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    }

    /*//////////////////////////////////////////////////////////////
                            COMIC METADATA
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Returns the ipfs image url.
     * @param _series The index of the series we are getting the image for.
     * @return ipfsString The url to ipfs where the image is represented. 
     * 
     * Requires:
     * - Series index provided must be loaded.
     * - Token of id must exist.
     */
    function seriesImage(
        uint8 _series
    )
        override
        public
        virtual
        view
        onlyLoaded(_series)
        returns (
            string memory ipfsString
        )
    {
        ipfsString = string(
            abi.encodePacked(
                  "ipfs://"
                , seriesToSeries[_series].ipfsHash
            )
        );
    }

    /**
     * @notice Returns the series JSON metadata that conforms to standards.
     * @dev The response from this function is not intended for on-chain usage.
     * @param _series The index of the series we are getting the image for.
     * @return metadataString The JSON string of the metadata that represents
     *                        the supplied series. 
     * 
     * Requires:
     * - Series index provided must be loaded.
     * - Token of id must exist.
     */
    function seriesMetadata(
          uint8 _series
        , uint256 _tokenId
        , bool redeemed
        , bool exists
        , bool wildcard
        , uint256 votes
    ) 
        override
        public
        virtual
        view
        onlyLoaded(_series)
        returns (
            string memory metadataString
        )
    {
        ///@dev Append active series 
        ///@note Nerds special prologue of #00 and all series below 10 are 0 padded
        metadataString = string(
            abi.encodePacked(
                  '{"trait_type":"Series","value":"#'
                , _series < 10 ? string(
                    abi.encodePacked(
                          "0"
                        , _series.toString()
                    )
                ) : _series.toString()
                , '"},'
            )
        );

        ///@dev Reflect the state of the series the comic is currently at
        ///@note Minting if issues is still open -- Limited if issues is closed and no more comics can evolve to this stage (series supply is functionally max supply locked)
        metadataString = string(
            abi.encodePacked(
                  metadataString
                , string(
                    abi.encodePacked(
                         '{"trait_type":"Edition","value":"'
                        , seriesToSeries[_series].issuanceEnd < block.timestamp ? "Limited" : "Minting"
                        , '"},'
                    )
                )
            )
        );
        
        ///@dev Append metadata to reflect the Pairing Status of the token
        ///@note When appended the ownership of the token is automatically updating until the pairing is broken through transferring or claiming.
        metadataString = string(
            abi.encodePacked(
                  metadataString
                , string(
                    abi.encodePacked(
                        '{"trait_type":"Nerd","value":"'
                        , !exists ? string(
                            abi.encodePacked(
                                  "#"
                                , _tokenId.toString()
                            )
                        ) : "Unpaired"
                        , '"},'
                    )
                )
            )
        );

        ///@dev Adds the Schrodinger trait if applicable and reflects the status of usage
        if(wildcard) { 
            metadataString = string(
                abi.encodePacked(
                      metadataString
                    , '{"trait_type":"Schrodinger'
                    , "'"
                    , 's Cat","value":"'
                    , redeemed ? "Dead" : "Alive"
                    , '"},'
                )
            );

        ///@dev Show whether or not the token has been used for the physical comic redemption -- does not show on Schrodingers
        } else { 
            metadataString = string(
                abi.encodePacked(
                      metadataString
                    , string(
                        abi.encodePacked(
                            '{"trait_type":"Status","value":"'
                            , redeemed ? "Redeemed" : "Unredeemed"
                            , '"},'
                        )
                    )
                )
            );
        }

        ///@dev Reflect the current number of Story Votes the owner of a Comic token earns through ownership.
        metadataString = string(
            abi.encodePacked(
                  metadataString
                , string(
                    abi.encodePacked(
                        '{"display_type":"number","trait_type":"Story Votes","value":"'
                        , votes.toString()
                        , '","max_value":"12"}'
                    )
                )
            )
        );
    }

    /**
     * @notice Allows the active series of the token to be retrieved.
     * @dev Pick the number out from where it lives. All this does is pull down
     *      the number that we've stored in the data packed index. With the 
     *      cumulative number in hand we nagivate into the proper bits and 
     *      make sure we return the properly cased number.
     * @param _tokenId The token to retrieve the comic book series for.
     * @return series The index of the series the retrieved comic represents.
     * 
     * Requires:
     * - token id must exist
     */
    function tokenSeries(
        uint256 _tokenId
    )
        override
        public
        virtual
        view
        onlyInRange(_tokenId)
        returns (
            uint8 series
        )
    {
        series = uint8(
            (
                tokenToSeries[_tokenId / PACKED] >> (
                    (_tokenId % PACKED) * PACKED_SHIFT
                )
            ) & 0xF
        );
    }

    /**
     * @notice Get the number of votes for a token.
     * @param _tokenId The comic tokenId to check votes for.
     * @return The number of votes the token actively contributes. 
     * 
     * Requires:
     * - token id must exist
     */
    function tokenVotes(
        uint256 _tokenId
    )
        public
        virtual
        view
        onlyInRange(_tokenId)
        returns (
            uint8
        ) 
    {
        if(nerdToWildcard[_tokenId]) return 12;
        
        return tokenSeries(_tokenId);
    }

    /**
     * @notice Determines if a Comic has been used for redemption.
     * @param _tokenId The comic tokenId being checked.
     * @return bool url to ipfs where the image is represented.
     * 
     * Requires:
     * - token id must exist
     */
    function tokenRedeemed(
        uint256 _tokenId
    )
        public 
        view 
        onlyInRange(_tokenId)
        returns(
            bool
        )
    {
        uint256 flag = (
            tokensToRedeemed[_tokenId / 256] >> _tokenId % 256
        ) & uint256(1);

        return (flag == 1 ? true : false);
    }

    /**
     * @notice Get the ipfs image url for a given token.
     * @param _tokenId The comic tokenId desired to be updated.
     * @return The url to ipfs where the image is represented.
     * 
     * Requires:
     * - token id must exist
     */
    function tokenImage(
        uint256 _tokenId
    )
        override
        public
        virtual
        view
        onlyInRange(_tokenId)
        returns (
            string memory
        )
    {
        return seriesImage(tokenSeries(_tokenId));
    }

    /**
     * @notice Returns the series JSON metadata that conforms to standards.
     * @dev The response from this function is not intended for on-chain usage.
     * @param _tokenId The comic tokenId desired to be updated.
     * @return The JSON string of the metadata that represents
     *         the supplied series.
     * 
     * Requires:
     * - token id must exist
     */
    function tokenMetadata(
        uint256 _tokenId
    ) 
        override
        public
        virtual
        view
        onlyInRange(_tokenId)
        returns (
            string memory
        )
    {
        return seriesMetadata(
              tokenSeries(_tokenId)
            , _tokenId
            , tokenRedeemed(_tokenId)
            , _exists(_tokenId)
            , nerdToWildcard[_tokenId]
            , tokenVotes(_tokenId)
        );
    }

    /**
     * @notice Generates the on-chain metadata for each non-fungible 1155.
     * @param _tokenId The id of the token to get the uri data for.
     * @return uri encoded json in the form of a string detailing the 
     *         retrieved token.
     * 
     * Requires:
     * - token id must exist
     */
    function tokenURI(
        uint256 _tokenId
    )
        override
        public
        virtual
        view
        onlyInRange(_tokenId)
        returns (
            string memory uri
        )        
    { 
        uint8 series = tokenSeries(_tokenId);

        uri = seriesToSeries[series].description;

        if(nerdToWildcard[_tokenId]) { 
            uri = string(
                abi.encodePacked(
                      uri
                    , wildcardDescription
                )
            );
        }

        if(tokenRedeemed(_tokenId)) { 
            uri = string(
                abi.encodePacked(
                      uri
                    , redeemedDescription
                )
            );
        }

        // Build the metadata string and return it as encoded data
        uri = string(
            abi.encodePacked(
                  "data:application/json;base64,"
                , Base64.encode(
                    bytes(  
                        abi.encodePacked(
                              '{"name":"Nuclear Nerds Comic #'
                            , _tokenId.toString()
                            , '","description":"'
                            , collectionDescription
                            , uri
                            , '","image":"'
                            , seriesImage(series)
                            , '?owner='
                            , Strings.toHexString(
                                    uint160(ownerOf(_tokenId))
                                , 20
                             )
                            , '","attributes":['
                            , tokenMetadata(_tokenId)
                            , ']}'
                        )
                    )
                )
            )
        );
    }

    /**
     * @notice Helper function to assist in determining whether a Nuclear Nerd
     *         has been used to claim a comic.
     * @dev This function will return false if even one of the tokenId 
     *      parameters has been previously used to claim.
     * @param _tokenIds The tokenIds of the Nuclear Nerds being checked 
     *                  for their claiming status.
     */
    function isClaimable(
        uint256[] calldata _tokenIds
    ) 
        public
        view
        returns (
            bool
        )
    {
        for(
            uint256 i; 
            i < _tokenIds.length;
            i++
        ) {
            if(_exists(_tokenIds[i])) 
                return false;
        }

        return true;
    }

    /**
     * @notice Helper function to used to determine if an array of 
     *         tokens can still be used to redeem a physical.
     * @dev This function will return false if even one of the tokenId
     *      parameters has been previously used to claim.
     * @param _tokenIds The tokenIds of the comcis being checked.
     */
    function isRedeemable(
        uint256[] calldata _tokenIds
    )
        public
        view 
        returns ( 
            bool
        )
    {
        for(
            uint256 i;
            i < _tokenIds.length;
            i++ 
        ) { 
            if(tokenRedeemed(_tokenIds[i]))
                return false;
        }

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                            COMIC CONTROL
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Allows holders of a Nuclear Nerd to claim a comic.
     * @dev This mint function acts as the single token call for claiming
     *      multiple tokens at a time.
     * @param _tokenId The tokenId of the Nuclear Nerd being used 
     *                  to claim a Comic.
     * 
     * Requires:
     * - sender must be owner of mirrored token.
     * - token of id must NOT exist.
     */
    function claimComic(
        uint256 _tokenId
    )
        public
        virtual
    {
        if (
            mirror.ownerOf(_tokenId) != _msgSender()
        ) revert TokenOwnerMismatch();

        _mint(
              _msgSender()
            , _tokenId
        );
    }    

    /**
     * @notice Allows holders of Nuclear Nerds to claim a comic for each 
     *         Nerd they own.
     * @dev This function should be used with reason in mind. A holder with 100 
     *      Nerds is far more likely to have a Nerd purchased in a
     *      long-pending transaction given low gas urgency. 
     * @param _tokenIds The tokenIds of the Nuclear Nerds being used 
     *                  to claim Comics.
     * 
     * Requires:
     * - sender must be owner of all mirrored tokens.
     * - all ids of token must NOT exist.
     */
    function claimComicBundle(
          uint256[] calldata _tokenIds
    ) 
        public
        virtual 
    {
        if(!mirror.isOwnerOf(
              _msgSender()
            , _tokenIds
        )) revert TokenOwnerMismatch();

        for(
            uint256 i; 
            i < _tokenIds.length;
            i++
        ) {
            _mint(
                  _msgSender()
                , _tokenIds[i]
            );
        }
    }
    
    /**
     * @notice Focuses a specific comic on a specific series.
     * @dev Every _series has at most 8 bits so we can bitpack 32 of them 
     *      (8 * 32 = 256) into a single storage slot of a uint256. 
     *      This saves a significant amount of money because setting a 
     *      non-zero slot consumes 20,000 gas where as it only costs 5,000 
     *      gas. So it is cheaper to store 31/32 times.
     * 
     * Requires:
     * - series being upgraded to must have been loaded.
     * - message sender must be the token owner.
     * - comic cannot be downgraded.
     * - cannot upgrade to series with closed issuance.
     */
    function _focusSeries(
          uint8 _series
        , uint256 _tokenId
    )
        internal
        onlyLoaded(_series)
    {        
        if(_msgSender() != ownerOf(_tokenId)) revert TokenOwnerMismatch();
    
        uint256 seriesIndex = _tokenId / PACKED;
        uint256 bitShift = (_tokenId % PACKED) * PACKED_SHIFT;

        if(uint8(
            (tokenToSeries[seriesIndex] >> bitShift) & 0xF
        ) > _series) revert SeriesDirectionProhibited();

        if(seriesToSeries[_series].issuanceEnd < block.timestamp) {
            revert SeriesAlreadyLocked();
        }

        tokenToSeries[seriesIndex] =
              (tokenToSeries[seriesIndex] & ~(0xF << bitShift)) 
            | (uint256(_series) << bitShift);
    }

    /**
     * @notice Allows the holder of a comic to progress
     *         the comic token to a subsequent issued series.
     * @dev Once a comic has progressed to the next issued series,
     *      it cannot be reverted back to a previous series.
     * @dev A token can progress from an early series to any series
     *      in the future provided Comics have not been locked.
     * @param _series The desired series index.
     * @param _tokenId The comic tokenId desired to be updated.
     *
     * Requires:
     * - series of index must be unlocked.
     */
    function focusSeries(
          uint8 _series
        , uint256 _tokenId
    ) 
        override
        public
        virtual
        onlyUnlocked()
    {
        _focusSeries(
              _series
            , _tokenId
        );
    }
 
    /**
     * @notice Allows the holder to focus multiple comics with multiple series
     *         in the same transaction so that they can update a series of
     *         comics all at once without having to go through pain.
     * @dev Once a comic has progressed to the next issued series,
     *      it cannot be reverted back to a previous series.
     * @dev A token can progress from an early series to any series
     * @param _series The array of desired series to be focused by tokenId.
     * @param _tokenIds The array of tokenIds to be focused.
     *
     * Requires:
     * - series of index must be unlocked.
     * - series array and token id array lengths must be the same.
     */
    function focusSeriesBundle(
          uint8[] calldata _series
        , uint256[] calldata _tokenIds
    ) 
        public
        virtual
        onlyUnlocked()
    {
        if(_series.length != _tokenIds.length) revert SeriesBundleInvalid();

        for(
            uint256 i;
            i < _series.length;
            i++
        ) {
            _focusSeries(
                  _series[i]
                , _tokenIds[i]
            );
        }
    }

    /**
    * @notice Toggles the redemption stage for a token id.
     * @dev Implements the boolean bitpacking of 256 values into a single 
     *      storage slot. This means, that while we've created a gas-consuming
     *      mechanism we've minimized cost to the highest extent. A boolean is 
     *      only 1 bit of information, but is typically 8 bits in solidity.
     *      With bitpacking, we can stuff 256 values into a single storage slot
     *      making it cheaper for the following 255 comics. This cost-savings 
     *      scales through the entire collection.
     * 
     * Requires:
     * - message sender must be the token owner
     * - cannot already be redeemed
     */
    function _redeemComic(
        uint256 _tokenId
    )
        internal
    {
        if(ownerOf(_tokenId) != _msgSender()) revert TokenOwnerMismatch();

        uint256 tokenIndex = _tokenId / 256;
        uint256 tokenShift =  _tokenId % 256;

        if(((
            tokensToRedeemed[tokenIndex] >> tokenShift
        ) & uint256(1)) == 1) revert TokenRedeemed();

        tokensToRedeemed[tokenIndex] = (
            tokensToRedeemed[tokenIndex] | uint256(1) << tokenShift
        );
    }

    /**
     * @notice Allows a holder to redee an array of tokens.
     * @dev The utilization of this function is not fully gated, though the 
     *      return for 'redeeming comics' is dependent on external criteria. 
     *      Nothing is earned or entitled by the redemption of a Comic unless 
     *      in the defined times and opportunities.
     * @dev Interface calls are extremely expensive. It is worthwhile to use 
     *      the higher level processing that is available.
     * @param _tokenIds The ids of the tokens to redeem.
     *
     * Requires:
     * - collection evolution must be locked preventing any future focusing.
     * - token ids array length must be equal to redemption capacity
     */
    function redeemComics(
          uint256[] calldata _tokenIds
    ) 
        public
        virtual
        onlyLocked()
    {
        if(
            _tokenIds.length != REDEMPTION_QUALIFIER
        ) revert TokenBundleInvalid();

        for (
            uint256 i; 
            i < _tokenIds.length; 
            i++
        ) {
            _redeemComic(_tokenIds[i]);
        }
    }

    /**
     * @notice Allows a wildcard holder to redeem their token.
     * @dev The utilization of this function is not fully gated, though the
     *      return for 'redeeming comics' is dependent on external criteria. 
     *      Nothing is earned or entitled by the redemption of a Comic unless 
     *      in the defined times and opportunities.
     * @dev Interface calls are extremely expensive. It is worthwhile to use 
     *      the higher level processing that is available.
     * @param _tokenId The id of the token to redeem.
     *
     * Requires:
     * - collection evolution must be locked preventing any future focusing.
     * - token id must be a wildcard representative of a wildcard Nuclear Nerd.
     */
    function redeemWildcardComic(
        uint256 _tokenId
    ) 
        public
        virtual
        onlyLocked()
    {   
        if(!nerdToWildcard[_tokenId]) revert TokenNotWildcard();

        _redeemComic(_tokenId);
    }

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

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

    /*//////////////////////////////////////////////////////////////
                            ERC2981 LOGIC
    //////////////////////////////////////////////////////////////*/
    
    /**
     * @notice Allows the Nuclear Nerds team to adjust contract-level metadata
     * @param _contractURIHash The ipfs hash of the contract metadata
     */
    function setContractURI(
        string memory _contractURIHash
    )
        public
        onlyOwner()
    { 
        contractURIHash = _contractURIHash;
    }

    /**
     * @notice Returns the accesible url of the contract level metadata
     */
    function contractURI() 
        public 
        view 
        returns (
            string memory
        ) 
    {
        return string(
            abi.encodePacked(
                  "ipfs://"
                , contractURIHash
            )
        );
    }

    /**
    * @notice Allows the Nuclear Nerds team to adjust where royalties
    *         are paid out if necessary.
    * @param _royaltyReceiver The address to send royalties to
    */
    function setRoyaltyReceiver(
        address _royaltyReceiver
    ) 
        public 
        onlyOwner() 
    {
        require(
              _royaltyReceiver != address(0)
            , "Royalties: new recipient is the zero address"
        );

        royaltyReceiver = _royaltyReceiver;
    }

    /**
    * @notice Allows the Nuclear Nerds team to adjust the on-chain
    *         royalty basis points.
    * @param _royaltyBasis The new basis points earned in royalties
    */
    function setRoyaltyBasis(
        uint256 _royaltyBasis
    )
        public
        onlyOwner()
    {
        royaltyBasis = _royaltyBasis;
    }

    /**
    * @notice EIP-2981 compliant view function for marketplaces
    *         to calculate the royalty percentage and what address
    *         receives them. 
    * @param _salePrice Total price of secondary sale
    * @return address of receiver and the amount of payment to send
    */
    function royaltyInfo(
          uint256
        , uint256 _salePrice
    ) 
        public 
        view 
        returns (
              address
            , uint256
        ) 
    {
        return (
              royaltyReceiver
            , (_salePrice * royaltyBasis) / percentageTotal
        );
    }
}

File 2 of 16 : ERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

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

/**
 * @notice This implementation of ERC721 is focused on mirroring the ownership 
 *         of an existing collection to provide the initial ownership record.
 *         With this, functionally the token deployed is attached to the mirror 
 *         --> until being detached. <--
 *         Once the Comic token has moved wallets independently, it functions 
 *         as a normal ERC721 with it's own ownership.
 */
contract ERC721 is 
      Context
    , ERC165
    , IERC721
    , IERC721Metadata 
{
    using Address for address;
    using Strings for uint256;

    ///@dev Token name
    string private _name;

    ///@dev Token symbol
    string private _symbol;

    uint256 internal constant MAX_SUPPLY = 8999;

    ///@dev hard coding in a max range of _owners is required.
    address[MAX_SUPPLY] internal _owners;

    ///@dev Mapping from token ID to approved address
    ///@notice This is outside of the standard implementation as it is 
    ///        token:holder due to an ownership record that mirrors
    ///        the parent. Once a token has been seperated from it's
    ///        parent, approvals are cleared upon transfer. While 
    ///        paired, approvals are tied to the owning address.
    ///        This has been accepted as this is also how operator 
    ///        approvals function by default.
    mapping(uint256 => mapping(address => address)) internal _tokenApprovals;

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

    IMirror public mirror;

    constructor(
          string memory name_
        , string memory symbol_
        , address _mirror
    ) {
        _name = name_;
        _symbol = symbol_;
        mirror = IMirror(_mirror);
    }

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

    /**
     * @notice Get the balance of address utilizing the existing ownership *         records of comic books / nerds
     * @dev See {IERC721-balanceOf}.
     * @dev This is extremely gassy and IS NOT intended for on-chain usage.
     * @param account The address to check the total balance of.
     * @return Amount of tokens that are owned by account
     */
    function balanceOf(
        address account
    ) 
        override
        public
        view 
        returns(
            uint256
        ) 
    {
        require(
              account != address(0)
            , "ERC721: balance query for the zero address"
        );

        uint256 counter;

        for (
            uint256 i; 
            i < MAX_SUPPLY; 
            i++
        ) {
            if (ERC721.ownerOf(i) == account)
                counter++;
        }

        return counter;
    }

    /**
     * @dev See {IERC721-ownerOf}.
     * @notice Overrides the default functionality of ownerOf() to utilize 
     *         phantom ownership of the tokens until they are first
     *         transferred.
     */
    function ownerOf(
        uint256 tokenId
    ) 
        public 
        view 
        virtual 
        override 
        returns (
            address
        ) 
    {
        address _owner = _owners[tokenId];
        
        if(_owner != address(0))
            return _owner;

        return mirror.ownerOf(tokenId);
    }
    
    /**
     * @notice Returns the entire ownership record of the comic books up to 
     *         the max supply.
     */
    function owners()
        external 
        view 
        returns(
            address[MAX_SUPPLY] memory
        ) 
    {
        return _owners;
    }

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

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

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

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

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

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

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

        _approve(
              to
            , tokenId
        );
    }

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

        address _owner = ERC721.ownerOf(tokenId);

        return _tokenApprovals[tokenId][_owner];
    }

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

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

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

        _transfer(
              from
            , to
            , tokenId
        );
    }

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

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

        _safeTransfer(
              from
            , to
            , tokenId
            , _data
        );
    }

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

        require(
              _checkOnERC721Received(
                  from
                , to
                , tokenId
                , _data
              )
            , "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

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

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

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

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

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

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

        _owners[tokenId] = to;

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

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

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

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

        // Clear approvals
        delete _tokenApprovals[tokenId][_owner];
        emit Approval(
              _owner
            , address(0)
            , tokenId
        );

        delete _owners[tokenId];

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

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

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

        require(
              _owner == from
            , "ERC721: transfer from incorrect owner"
        );
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(
              from
            , to
            , tokenId
        );

        // Clear approvals from the previous owner
        delete _tokenApprovals[tokenId][_owner];
        emit Approval(
              _owner
            , address(0)
            , tokenId
        );

        _owners[tokenId] = to;

        emit Transfer(
              from
            , to
            , tokenId
        );

        _afterTokenTransfer(
              from
            , to
            , tokenId
        );
    }

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

        _tokenApprovals[tokenId][_owner] = to;
        emit Approval(
              _owner
            , to
            , tokenId
        );
    }

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

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

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

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

File 3 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

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

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

File 4 of 16 : IMimeticComic.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

interface IMimeticComic {
    function loadSeries(
          uint8 _series
        , string memory _description
        , string memory _ipfsHash
        , uint256 _issuanceEnd
    )
        external;

    function lock()
        external;

    function seriesImage(
        uint8 _series
    )
        external
        view
        returns (
            string memory ipfsString
        );

    function seriesMetadata(
          uint8 _series
        , uint256 _tokenId
        , bool redeemed
        , bool exists
        , bool wildcard
        , uint256 votes
    )
        external
        view
        returns (
            string memory metadataString
        );

    function tokenSeries(
        uint256 _tokenId
    )
        external
        view
        returns (
            uint8 series
        );

    function tokenImage(
        uint256 _tokenId
    )
        external
        view
        returns (
            string memory
        );

    function tokenMetadata(
        uint256 _tokenId
    )
        external
        view
        returns (
            string memory
        );

    function focusSeries(
          uint8 _series
        , uint256 _tokenId
    )
        external;
}

File 5 of 16 : Base64.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0;

/// @title Base64
/// @author Brecht Devos - <[email protected]>
/// @notice Provides functions for encoding/decoding base64
library Base64 {
    string internal constant TABLE_ENCODE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    bytes  internal constant TABLE_DECODE = hex"0000000000000000000000000000000000000000000000000000000000000000"
                                            hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
                                            hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
                                            hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";

    function encode(bytes memory data) internal pure returns (string memory) {
        if (data.length == 0) return '';

        // load the table into memory
        string memory table = TABLE_ENCODE;

        // multiply by 4/3 rounded up
        uint256 encodedLen = 4 * ((data.length + 2) / 3);

        // add some extra buffer at the end required for the writing
        string memory result = new string(encodedLen + 32);

        assembly {
            // set the actual output length
            mstore(result, encodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 3 bytes at a time
            for {} lt(dataPtr, endPtr) {}
            {
                // read 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // write 4 characters
                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
                resultPtr := add(resultPtr, 1)
                mstore8(resultPtr, mload(add(tablePtr, and(        input,  0x3F))))
                resultPtr := add(resultPtr, 1)
            }

            // padding with '='
            switch mod(mload(data), 3)
            case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
            case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
        }

        return result;
    }

    function decode(string memory _data) internal pure returns (bytes memory) {
        bytes memory data = bytes(_data);

        if (data.length == 0) return new bytes(0);
        require(data.length % 4 == 0, "invalid base64 decoder input");

        // load the table into memory
        bytes memory table = TABLE_DECODE;

        // every 4 characters represent 3 bytes
        uint256 decodedLen = (data.length / 4) * 3;

        // add some extra buffer at the end required for the writing
        bytes memory result = new bytes(decodedLen + 32);

        assembly {
            // padding with '='
            let lastBytes := mload(add(data, mload(data)))
            if eq(and(lastBytes, 0xFF), 0x3d) {
                decodedLen := sub(decodedLen, 1)
                if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
                    decodedLen := sub(decodedLen, 1)
                }
            }

            // set the actual output length
            mstore(result, decodedLen)

            // prepare the lookup table
            let tablePtr := add(table, 1)

            // input ptr
            let dataPtr := data
            let endPtr := add(dataPtr, mload(data))

            // result ptr, jump over length
            let resultPtr := add(result, 32)

            // run over the input, 4 characters at a time
            for {} lt(dataPtr, endPtr) {}
            {
               // read 4 characters
               dataPtr := add(dataPtr, 4)
               let input := mload(dataPtr)

               // write 3 bytes
               let output := add(
                   add(
                       shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
                       shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
                   add(
                       shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
                               and(mload(add(tablePtr, and(        input , 0xFF))), 0xFF)
                    )
                )
                mstore(resultPtr, shl(232, output))
                resultPtr := add(resultPtr, 3)
            }
        }

        return result;
    }
}

File 6 of 16 : 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 7 of 16 : IMirror.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.9;

interface IMirror {
    function ownerOf(uint256 tokenId_) 
        external 
        view 
        returns (
            address
        );

    function isOwnerOf(
          address account
        , uint256[] calldata _tokenIds
    ) 
        external 
        view 
        returns (
            bool
        );
}

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

File 9 of 16 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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`, 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 Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

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

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

File 10 of 16 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

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

pragma solidity ^0.8.0;

import "../IERC721.sol";

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

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

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

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

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

pragma solidity ^0.8.0;

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

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

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

File 15 of 16 : 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 16 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

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

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_seriesZeroDescription","type":"string"},{"internalType":"string","name":"_seriesZeroHash","type":"string"},{"internalType":"string","name":"_collectionDescription","type":"string"},{"internalType":"string","name":"_wildcardDescription","type":"string"},{"internalType":"string","name":"_redeemedDescription","type":"string"},{"internalType":"address","name":"_nerds","type":"address"},{"internalType":"address","name":"_royaltyReceiver","type":"address"},{"internalType":"string","name":"_contractURIHash","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CollectionMasterLocked","type":"error"},{"inputs":[],"name":"CollectionStateInvalid","type":"error"},{"inputs":[],"name":"CollectionWildcardsLocked","type":"error"},{"inputs":[],"name":"HookCallerMismatch","type":"error"},{"inputs":[],"name":"SeriesAlreadyLoaded","type":"error"},{"inputs":[],"name":"SeriesAlreadyLocked","type":"error"},{"inputs":[],"name":"SeriesBundleInvalid","type":"error"},{"inputs":[],"name":"SeriesDirectionProhibited","type":"error"},{"inputs":[],"name":"SeriesNotLoaded","type":"error"},{"inputs":[],"name":"SeriesNotLocked","type":"error"},{"inputs":[],"name":"TokenBundleInvalid","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenMinted","type":"error"},{"inputs":[],"name":"TokenNotWildcard","type":"error"},{"inputs":[],"name":"TokenOwnerMismatch","type":"error"},{"inputs":[],"name":"TokenRedeemed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"PACKED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PACKED_SHIFT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REDEMPTION_QUALIFIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"claimComic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"claimComicBundle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURIHash","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_series","type":"uint8"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"focusSeries","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"_series","type":"uint8[]"},{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"focusSeriesBundle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hooks","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"isClaimable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"isRedeemable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"loadCollection2309","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"internalType":"uint256","name":"_toTokenId","type":"uint256"},{"internalType":"address","name":"_from","type":"address"}],"name":"loadCollection2309From","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"internalType":"uint256","name":"_toTokenId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"loadCollection2309To","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"internalType":"uint256","name":"_toTokenId","type":"uint256"},{"internalType":"address[]","name":"_to","type":"address[]"}],"name":"loadCollectionCalldata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"loadCollectionOwners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mirror","type":"address"}],"name":"loadMirror","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_series","type":"uint8"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"string","name":"_ipfsHash","type":"string"},{"internalType":"uint256","name":"_issuanceEnd","type":"uint256"}],"name":"loadSeries","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"loadWildcards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"masterLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mirror","outputs":[{"internalType":"contract IMirror","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owners","outputs":[{"internalType":"address[8999]","name":"","type":"address[8999]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"redeemComics","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"redeemWildcardComic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"refreshToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"refreshTokenBundle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"royaltyBasis","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"_salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"royaltyReceiver","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":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_series","type":"uint8"}],"name":"seriesImage","outputs":[{"internalType":"string","name":"ipfsString","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_series","type":"uint8"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bool","name":"redeemed","type":"bool"},{"internalType":"bool","name":"exists","type":"bool"},{"internalType":"bool","name":"wildcard","type":"bool"},{"internalType":"uint256","name":"votes","type":"uint256"}],"name":"seriesMetadata","outputs":[{"internalType":"string","name":"metadataString","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"seriesToSeries","outputs":[{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"ipfsHash","type":"string"},{"internalType":"uint256","name":"issuanceEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_contractURIHash","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_royaltyBasis","type":"uint256"}],"name":"setRoyaltyBasis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_royaltyReceiver","type":"address"}],"name":"setRoyaltyReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_hook","type":"address"}],"name":"toggleHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenImage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenRedeemed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenSeries","outputs":[{"internalType":"uint8","name":"series","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenVotes","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokensToRedeemed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wildcardsLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

60806040526102b2612337553480156200001857600080fd5b506040516200522e3803806200522e8339810160408190526200003b9162000396565b89898482600090805190602001906200005692919062000206565b5081516200006c90600190602085019062000206565b5061232b80546001600160a01b0319166001600160a01b039290921691909117905550620000a390506200009d3390565b620001b3565b6040805160608101825289815260208082018a905261a455928201929092526000805261232d82528051805191927fb1ede82ae2780a126e2c6d22a316da535a857b4a6c12bc28001d37d3be2989df9262000102928492019062000206565b5060208281015180516200011d926001850192019062000206565b50604091909101516002909101558551620001419061233090602089019062000206565b508451620001589061233190602088019062000206565b5083516200016f9061233290602087019062000206565b5061233880546001600160a01b0319166001600160a01b0384161790558051620001a29061233690602084019062000206565b505050505050505050505062000552565b61232c80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b828054620002149062000515565b90600052602060002090601f01602090048101928262000238576000855562000283565b82601f106200025357805160ff191683800117855562000283565b8280016001018555821562000283579182015b828111156200028357825182559160200191906001019062000266565b506200029192915062000295565b5090565b5b8082111562000291576000815560010162000296565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620002d457600080fd5b81516001600160401b0380821115620002f157620002f1620002ac565b604051601f8301601f19908116603f011681019082821181831017156200031c576200031c620002ac565b816040528381526020925086838588010111156200033957600080fd5b600091505b838210156200035d57858201830151818301840152908201906200033e565b838211156200036f5760008385830101525b9695505050505050565b80516001600160a01b03811681146200039157600080fd5b919050565b6000806000806000806000806000806101408b8d031215620003b757600080fd5b8a516001600160401b0380821115620003cf57600080fd5b620003dd8e838f01620002c2565b9b5060208d0151915080821115620003f457600080fd5b620004028e838f01620002c2565b9a5060408d01519150808211156200041957600080fd5b620004278e838f01620002c2565b995060608d01519150808211156200043e57600080fd5b6200044c8e838f01620002c2565b985060808d01519150808211156200046357600080fd5b620004718e838f01620002c2565b975060a08d01519150808211156200048857600080fd5b620004968e838f01620002c2565b965060c08d0151915080821115620004ad57600080fd5b620004bb8e838f01620002c2565b9550620004cb60e08e0162000379565b9450620004dc6101008e0162000379565b93506101208d0151915080821115620004f457600080fd5b50620005038d828e01620002c2565b9150509295989b9194979a5092959850565b600181811c908216806200052a57607f821691505b602082108114156200054c57634e487b7160e01b600052602260045260246000fd5b50919050565b614ccc80620005626000396000f3fe608060405234801561001057600080fd5b50600436106103eb5760003560e01c8063873b99561161021a578063c2c74f8a11610135578063e6bc672d116100c8578063e985e9c511610097578063f0d1700e1161007c578063f0d1700e146108f0578063f2fde38b14610903578063f83d08ba1461091657600080fd5b8063e985e9c5146108a0578063ea462b56146108dd57600080fd5b8063e6bc672d1461086a578063e71f6c2f1461087d578063e8a3d48514610890578063e8dee6581461089857600080fd5b8063c982681b11610104578063c982681b1461080c578063cf30901214610830578063cf34842514610844578063e2df2c731461085757600080fd5b8063c2c74f8a146107d4578063c4217932146107e7578063c6ec6909146107ef578063c87b56dd146107f957600080fd5b8063a22cb465116101ad578063b071cdb41161017c578063b071cdb414610788578063b0954dee1461079b578063b37f66e7146107ae578063b88d4fde146107c157600080fd5b8063a22cb4651461073a578063a2f13aba1461074d578063ae40c3e014610760578063affe39c11461077357600080fd5b806395d89b41116101e957806395d89b41146106f85780639bcf4f03146107005780639f9e97b8146107135780639fbc87131461072657600080fd5b8063873b9956146106b85780638da5cb5b146106c05780638dc251e3146106d2578063938e3d7b146106e557600080fd5b806342842e0e1161030a578063663cc3731161029d57806370a082311161026c57806370a0823114610669578063715018a61461067c57806371c185b214610684578063809b8fad146106a557600080fd5b8063663cc3731461061d5780636914db60146106305780636fff617b1461064357806370255cfd1461065657600080fd5b80635659bd62116102d95780635659bd62146105dc5780636352211e146105ef578063654edd00146106025780636626ada21461061557600080fd5b806342842e0e1461058f578063444d9172146105a257806344bdde08146105b657806353004a99146105c957600080fd5b80631d398554116103825780632a55205a116103515780632a55205a1461051a5780633c5283891461054c5780633ed213731461056e5780634083e9421461057c57600080fd5b80631d398554146104cb57806322db91b3146104de57806323b872dd146104f4578063272e7dbc1461050757600080fd5b8063081812fc116103be578063081812fc14610467578063095ea7b3146104925780630d114c9a146104a557806319a1ec83146104b857600080fd5b806301ffc9a7146103f057806302f2e47a1461041857806303f765761461042d57806306fdde0314610452575b600080fd5b6104036103fe366004613de4565b61091e565b60405190151581526020015b60405180910390f35b61042b610426366004613e01565b610996565b005b61044061043b366004613e01565b610a15565b60405160ff909116815260200161040f565b61045a610a78565b60405161040f9190613e72565b61047a610475366004613e01565b610b0a565b6040516001600160a01b03909116815260200161040f565b61042b6104a0366004613e9a565b610bb1565b61042b6104b3366004613f52565b610ce3565b6104036104c6366004614017565b610e37565b61042b6104d9366004614059565b610e8f565b6104e6604081565b60405190815260200161040f565b61042b61050236600461407b565b61105b565b61042b610515366004614017565b6110e2565b61052d610528366004614059565b6111c1565b604080516001600160a01b03909316835260208301919091520161040f565b61055f61055a3660046140d2565b6111fe565b60405161040f939291906140ed565b612334546104039060ff1681565b61045a61058a3660046140d2565b611331565b61042b61059d36600461407b565b6113b6565b61232b5461047a906001600160a01b031681565b6104406105c4366004613e01565b6113d1565b61042b6105d7366004614059565b611444565b61042b6105ea366004614123565b6114f5565b61047a6105fd366004613e01565b61158b565b61042b610610366004614140565b611638565b6104e6600481565b61042b61062b366004614193565b611796565b61045a61063e366004613e01565b6117cf565b61042b6106513660046141af565b611842565b61042b61066436600461407b565b611908565b6104e6610677366004614123565b6119e8565b61042b611abd565b6104e6610692366004613e01565b6123336020526000908152604090205481565b61042b6106b3366004613e01565b611b12565b61042b611c48565b61232c546001600160a01b031661047a565b61042b6106e0366004614123565b611ca3565b61042b6106f3366004614208565b611d8b565b61045a611de8565b61042b61070e366004614017565b611df7565b610403610721366004614017565b611f70565b6123385461047a906001600160a01b031681565b61042b61074836600461424b565b611fbe565b61042b61075b366004614017565b611fc9565b61042b61076e366004613e01565b6120c7565b61077b612116565b60405161040f9190614284565b61042b610796366004614017565b61215e565b6104036107a9366004613e01565b612200565b61042b6107bc3660046141af565b61227f565b61042b6107cf366004613f52565b612339565b61042b6107e23660046142c1565b6123c1565b61045a612491565b6104e66123375481565b61045a610807366004613e01565b612520565b61040361081a366004614123565b6123356020526000908152604090205460ff1681565b612334546104039062010000900460ff1681565b61045a610852366004613e01565b612701565b61045a610865366004614321565b61273d565b6123345461040390610100900460ff1681565b61042b61088b366004614123565b612b17565b61045a612bb4565b6104e6600d81565b6104036108ae36600461438f565b6001600160a01b03918216600090815261232a6020908152604080832093909416825291909152205460ff1690565b61042b6108eb366004613e01565b612bdd565b61042b6108fe3660046143bd565b612c90565b61042b610911366004614123565b612dcd565b61042b612e9b565b60006001600160e01b031982167f2a55205a00000000000000000000000000000000000000000000000000000000148061098157506001600160e01b031982167f2e11ffbb00000000000000000000000000000000000000000000000000000000145b80610990575061099082612ef8565b92915050565b6123345462010000900460ff166109c0576040516313f97ebb60e21b815260040160405180910390fd5b600081815261232f602052604090205460ff16610a09576040517f68163b6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a1281612f93565b50565b600081610a25600161232761444f565b811115610a455760405163677510db60e11b815260040160405180910390fd5b600083815261232f602052604090205460ff1615610a6657600c9150610a72565b610a6f836113d1565b91505b50919050565b606060008054610a8790614466565b80601f0160208091040260200160405190810160405280929190818152602001828054610ab390614466565b8015610b005780601f10610ad557610100808354040283529160200191610b00565b820191906000526020600020905b815481529060010190602001808311610ae357829003601f168201915b5050505050905090565b60006123278210610b775760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b6000610b828361158b565b6000938452612329602090815260408086206001600160a01b0393841687529091529093205490921692915050565b6000610bbc8261158b565b9050806001600160a01b0316836001600160a01b03161415610c465760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610b6e565b336001600160a01b0382161480610c625750610c6281336108ae565b610cd45760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b6e565b610cde8383613053565b505050565b336000908152612335602052604090205460ff16610d14576040516320040d8560e01b815260040160405180910390fd5b610d1d826130cd565b610e31576000828152612329602090815260408083206001600160a01b038816808552925280832080546001600160a01b031916905551849291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a481836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4610dca848484846130f7565b610e315760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610b6e565b50505050565b6000805b82811015610e8557610e64848483818110610e5857610e5861449b565b905060200201356130cd565b15610e73576000915050610990565b80610e7d816144b1565b915050610e3b565b5060019392505050565b61233454610100900460ff1615610eb95760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b03163314610f025760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b815b81811015610cde5761232b546040516331a9108f60e11b8152600481018390526000916001600160a01b031690636352211e9060240160206040518083038186803b158015610f5257600080fd5b505afa158015610f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8a91906144cc565b60405190915082906001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4610fe160008284604051806020016040528060008152506130f7565b6110485760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610b6e565b5080611053816144b1565b915050610f04565b611065338261324f565b6110d75760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b6e565b610cde838383613332565b61232b546001600160a01b0316634d44660c3384846040518463ffffffff1660e01b8152600401611115939291906144e9565b60206040518083038186803b15801561112d57600080fd5b505afa158015611141573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611165919061454e565b611182576040516371d3ec2560e11b815260040160405180910390fd5b60005b81811015610cde576111af338484848181106111a3576111a361449b565b90506020020135613505565b806111b9816144b1565b915050611185565b612338546123375460009182916001600160a01b0390911690612710906111e8908661456b565b6111f291906145a0565b915091505b9250929050565b61232d6020526000908152604090208054819061121a90614466565b80601f016020809104026020016040519081016040528092919081815260200182805461124690614466565b80156112935780601f1061126857610100808354040283529160200191611293565b820191906000526020600020905b81548152906001019060200180831161127657829003601f168201915b5050505050908060010180546112a890614466565b80601f01602080910402602001604051908101604052809291908181526020018280546112d490614466565b80156113215780601f106112f657610100808354040283529160200191611321565b820191906000526020600020905b81548152906001019060200180831161130457829003601f168201915b5050505050908060020154905083565b60ff8116600090815261232d602052604090206001018054606091839161135790614466565b151590506113785760405163071f08b360e11b815260040160405180910390fd5b60ff8316600090815261232d6020908152604091829020915161139f92600101910161464e565b604051602081830303815290604052915050919050565b610cde83838360405180602001604052806000815250612339565b6000816113e1600161232761444f565b8111156114015760405163677510db60e11b815260040160405180910390fd5b600461140e604085614680565b611418919061456b565b61232e60006114286040876145a0565b815260200190815260200160002054901c600f16915050919050565b61233454610100900460ff161561146e5760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146114b75760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b604051818152309060009084907fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d9060200160405180910390a45050565b61233454610100900460ff161561151f5760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146115685760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b61232b80546001600160a01b0319166001600160a01b0392909216919091179055565b60008060028361232781106115a2576115a261449b565b01546001600160a01b0316905080156115bb5792915050565b61232b546040516331a9108f60e11b8152600481018590526001600160a01b0390911690636352211e9060240160206040518083038186803b15801561160057600080fd5b505afa158015611614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6f91906144cc565b61233454610100900460ff16156116625760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146116ab5760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b60006116b7858561444f565b6116c2906001614694565b90508181146116fd576040517f2292985d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000855b85811161178d5780858584611715816144b1565b95508181106117265761172661449b565b905060200201602081019061173b9190614123565b6001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480611785816144b1565b915050611701565b50505050505050565b6123345462010000900460ff16156117c157604051634a93292d60e11b815260040160405180910390fd5b6117cb8282613615565b5050565b6060816117df600161232761444f565b8111156117ff5760405163677510db60e11b815260040160405180910390fd5b610a6f61180b846113d1565b8461181586612200565b61181e876130cd565b600088815261232f602052604090205460ff1661183a89610a15565b60ff1661273d565b61233454610100900460ff161561186c5760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146118b55760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b306001600160a01b0316816001600160a01b0316847fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d856040516118fb91815260200190565b60405180910390a4505050565b336000908152612335602052604090205460ff16611939576040516320040d8560e01b815260040160405180910390fd5b611942816130cd565b610cde576000818152612329602090815260408083206001600160a01b038716808552925280832080546001600160a01b031916905551839291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a480826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b60006001600160a01b038216611a665760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610b6e565b6000805b612327811015611ab657836001600160a01b0316611a878261158b565b6001600160a01b03161415611aa45781611aa0816144b1565b9250505b80611aae816144b1565b915050611a6a565b5092915050565b61232c546001600160a01b03163314611b065760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b611b106000613773565b565b61233454610100900460ff1615611b3c5760405163114f7cf360e11b815260040160405180910390fd5b611b45816130cd565b15611b63576040516331cde96f60e21b815260040160405180910390fd5b61232b546040516331a9108f60e11b8152600481018390526000916001600160a01b031690636352211e9060240160206040518083038186803b158015611ba957600080fd5b505afa158015611bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be191906144cc565b9050336001600160a01b03821614611c0c576040516371d3ec2560e11b815260040160405180910390fd5b60405182906001600160a01b0383169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90600090a45050565b61232c546001600160a01b03163314611c915760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b612334805461ff001916610100179055565b61232c546001600160a01b03163314611cec5760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6001600160a01b038116611d685760405162461bcd60e51b815260206004820152602c60248201527f526f79616c746965733a206e657720726563697069656e74206973207468652060448201527f7a65726f206164647265737300000000000000000000000000000000000000006064820152608401610b6e565b61233880546001600160a01b0319166001600160a01b0392909216919091179055565b61232c546001600160a01b03163314611dd45760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b80516117cb90612336906020840190613d14565b606060018054610a8790614466565b61233454610100900460ff1615611e215760405163114f7cf360e11b815260040160405180910390fd5b61232b546001600160a01b0316634d44660c3384846040518463ffffffff1660e01b8152600401611e54939291906144e9565b60206040518083038186803b158015611e6c57600080fd5b505afa158015611e80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea4919061454e565b611ec1576040516371d3ec2560e11b815260040160405180910390fd5b60005b81811015610cde57611ee1838383818110610e5857610e5861449b565b15611eff576040516331cde96f60e21b815260040160405180910390fd5b828282818110611f1157611f1161449b565b90506020020135611f1f3390565b6001600160a01b0316306001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480611f68816144b1565b915050611ec4565b6000805b82811015610e8557611f9d848483818110611f9157611f9161449b565b90506020020135612200565b15611fac576000915050610990565b80611fb6816144b1565b915050611f74565b6117cb3383836137c6565b61232c546001600160a01b031633146120125760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6123345460ff1615612050576040517f99d117e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612334805460ff1916600117905560005b60ff8116821115610cde57600161232f600085858560ff168181106120885761208861449b565b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555080806120bf906146ac565b915050612061565b61232c546001600160a01b031633146121105760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b61233755565b61211e613d98565b60408051620464e0810191829052906002906123279082845b81546001600160a01b03168152600190910190602001808311612137575050505050905090565b6123345462010000900460ff16612188576040516313f97ebb60e21b815260040160405180910390fd5b600d81146121c2576040517f172e743e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610cde576121ee8383838181106121e2576121e261449b565b90506020020135612f93565b806121f8816144b1565b9150506121c5565b600081612210600161232761444f565b8111156122305760405163677510db60e11b815260040160405180910390fd5b6000600161224061010086614680565b6123336000612251610100896145a0565b815260200190815260200160002054901c16905080600114612274576000612277565b60015b949350505050565b61233454610100900460ff16156122a95760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146122f25760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b806001600160a01b031660006001600160a01b0316847fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d856040516118fb91815260200190565b612343338361324f565b6123b55760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b6e565b610e3184848484613896565b6123345462010000900460ff16156123ec57604051634a93292d60e11b815260040160405180910390fd5b828114612425576040517f515871e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8381101561248a576124788585838181106124455761244561449b565b905060200201602081019061245a91906140d2565b84848481811061246c5761246c61449b565b90506020020135613615565b80612482816144b1565b915050612428565b5050505050565b612336805461249f90614466565b80601f01602080910402602001604051908101604052809291908181526020018280546124cb90614466565b80156125185780601f106124ed57610100808354040283529160200191612518565b820191906000526020600020905b8154815290600101906020018083116124fb57829003601f168201915b505050505081565b606081612530600161232761444f565b8111156125505760405163677510db60e11b815260040160405180910390fd5b600061255b846113d1565b60ff8116600090815261232d6020526040902080549192509061257d90614466565b80601f01602080910402602001604051908101604052809291908181526020018280546125a990614466565b80156125f65780601f106125cb576101008083540402835291602001916125f6565b820191906000526020600020905b8154815290600101906020018083116125d957829003601f168201915b505050600087815261232f6020526040902054929550505060ff161561263d578261233160405160200161262b9291906146cc565b60405160208183030381529060405292505b61264684612200565b1561267257826123326040516020016126609291906146cc565b60405160208183030381529060405292505b6126d961267e856138ad565b6123308561268b85611331565b6126a76126978a61158b565b6001600160a01b031660146139ab565b6126b08a6117cf565b6040516020016126c5969594939291906146f3565b604051602081830303815290604052613b77565b6040516020016126e99190614869565b60405160208183030381529060405292505050919050565b606081612711600161232761444f565b8111156127315760405163677510db60e11b815260040160405180910390fd5b610a6f61058a846113d1565b60ff8616600090815261232d602052604090206001018054606091889161276390614466565b151590506127845760405163071f08b360e11b815260040160405180910390fd5b600a8860ff16106127a05761279b8860ff166138ad565b6127cc565b6127ac8860ff166138ad565b6040516020016127bc91906148ae565b6040516020818303038152906040525b6040516020016127dc91906148d7565b60408051601f1981840301815291815260ff8a16600090815261232d602052206002015490925082904211612846576040518060400160405280600781526020017f4d696e74696e670000000000000000000000000000000000000000000000000081525061287d565b6040518060400160405280600781526020017f4c696d69746564000000000000000000000000000000000000000000000000008152505b60405160200161288d9190614933565b60408051601f19818403018152908290526128ab9291602001614991565b60405160208183030381529060405291508185156128fe576040518060400160405280600881526020017f556e706169726564000000000000000000000000000000000000000000000000815250612927565b612907886138ad565b60405160200161291791906149c0565b6040516020818303038152906040525b60405160200161293791906149dc565b60408051601f19818403018152908290526129559291602001614991565b60405160208183030381529060405291508315612a0b5781866129ad576040518060400160405280600581526020017f416c6976650000000000000000000000000000000000000000000000000000008152506129e4565b6040518060400160405280600481526020017f44656164000000000000000000000000000000000000000000000000000000008152505b6040516020016129f5929190614a2e565b6040516020818303038152906040529150612ac3565b8186612a4c576040518060400160405280600a81526020017f556e72656465656d656400000000000000000000000000000000000000000000815250612a83565b6040518060400160405280600881526020017f52656465656d65640000000000000000000000000000000000000000000000008152505b604051602001612a939190614ae2565b60408051601f1981840301815290829052612ab19291602001614991565b60405160208183030381529060405291505b81612acd846138ad565b604051602001612add9190614b34565b60408051601f1981840301815290829052612afb9291602001614991565b6040516020818303038152906040529150509695505050505050565b61233454610100900460ff1615612b415760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b03163314612b8a5760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6001600160a01b0316600090815261233560205260409020805460ff19811660ff90911615179055565b6060612336604051602001612bc9919061464e565b604051602081830303815290604052905090565b3361232b546040516331a9108f60e11b8152600481018490526001600160a01b039283169290911690636352211e9060240160206040518083038186803b158015612c2757600080fd5b505afa158015612c3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5f91906144cc565b6001600160a01b031614612c86576040516371d3ec2560e11b815260040160405180910390fd5b610a123382613505565b6123345462010000900460ff1615612cbb57604051634a93292d60e11b815260040160405180910390fd5b61232c546001600160a01b03163314612d045760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b60ff8416600090815261232d602052604090206001018054612d2590614466565b159050612d5e576040517f4cf58b4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051606081018252848152602080820185905281830184905260ff8716600090815261232d8252929092208151805192939192612da09284920190613d14565b506020828101518051612db99260018501920190613d14565b506040820151816002015590505050505050565b61232c546001600160a01b03163314612e165760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6001600160a01b038116612e925760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b6e565b610a1281613773565b61232c546001600160a01b03163314612ee45760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b612334805462ff0000191662010000179055565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480612f5b57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061099057507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610990565b33612f9d8261158b565b6001600160a01b031614612fc4576040516371d3ec2560e11b815260040160405180910390fd5b6000612fd2610100836145a0565b90506000612fe261010084614680565b60008381526123336020526040902054909150811c60019081161415613034576040517ff6dd524a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600091825261233360205260409091208054600190921b909117905550565b600061305e8261158b565b6000838152612329602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b60008060028361232781106130e4576130e461449b565b01546001600160a01b0316141592915050565b60006001600160a01b0384163b1561324457604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061313b903390899088908890600401614bc6565b602060405180830381600087803b15801561315557600080fd5b505af1925050508015613185575060408051601f3d908101601f1916820190925261318291810190614c02565b60015b61322a573d8080156131b3576040519150601f19603f3d011682016040523d82523d6000602084013e6131b8565b606091505b5080516132225760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610b6e565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612277565b506001949350505050565b600061232782106132b75760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b6e565b60006132c28361158b565b9050806001600160a01b0316846001600160a01b031614806132fd5750836001600160a01b03166132f284610b0a565b6001600160a01b0316145b8061227757506001600160a01b03808216600090815261232a602090815260408083209388168352929052205460ff16612277565b600061333d8261158b565b9050836001600160a01b0316816001600160a01b0316146133c65760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152608401610b6e565b6001600160a01b0383166134415760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610b6e565b6000828152612329602090815260408083206001600160a01b038516808552925280832080546001600160a01b031916905551849291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a48260028361232781106134b2576134b261449b565b0180546001600160a01b0319166001600160a01b03928316179055604051839185811691908716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90600090a4610e31565b6001600160a01b03821661355b5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b6e565b613564816130cd565b156135b15760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b6e565b8160028261232781106135c6576135c661449b565b0180546001600160a01b0319166001600160a01b0392831617905560405182918416906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60ff8216600090815261232d60205260409020600101805483919061363990614466565b1515905061365a5760405163071f08b360e11b815260040160405180910390fd5b6136638261158b565b6001600160a01b0316336001600160a01b031614613694576040516371d3ec2560e11b815260040160405180910390fd5b60006136a16040846145a0565b9050600060046136b2604086614680565b6136bc919061456b565b600083815261232e602052604090205490915060ff861690821c600f161115613711576040517fdc86b7bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff8516600090815261232d602052604090206002015442111561374857604051634a93292d60e11b815260040160405180910390fd5b600091825261232e60205260409091208054600f831b191660ff90951690911b939093179092555050565b61232c80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b031614156138285760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b6e565b6001600160a01b03838116600081815261232a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6138a1848484613332565b610dca848484846130f7565b6060816138d15750506040805180820190915260018152600360fc1b602082015290565b8160005b81156138fb57806138e5816144b1565b91506138f49050600a836145a0565b91506138d5565b60008167ffffffffffffffff81111561391657613916613ec6565b6040519080825280601f01601f191660200182016040528015613940576020820181803683370190505b5090505b84156122775761395560018361444f565b9150613962600a86614680565b61396d906030614694565b60f81b8183815181106139825761398261449b565b60200101906001600160f81b031916908160001a9053506139a4600a866145a0565b9450613944565b606060006139ba83600261456b565b6139c5906002614694565b67ffffffffffffffff8111156139dd576139dd613ec6565b6040519080825280601f01601f191660200182016040528015613a07576020820181803683370190505b509050600360fc1b81600081518110613a2257613a2261449b565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110613a6d57613a6d61449b565b60200101906001600160f81b031916908160001a9053506000613a9184600261456b565b613a9c906001614694565b90505b6001811115613b21577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110613add57613add61449b565b1a60f81b828281518110613af357613af361449b565b60200101906001600160f81b031916908160001a90535060049490941c93613b1a81614c1f565b9050613a9f565b508315613b705760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b6e565b9392505050565b6060815160001415613b9757505060408051602081019091526000815290565b6000604051806060016040528060408152602001614c376040913990506000600384516002613bc69190614694565b613bd091906145a0565b613bdb90600461456b565b90506000613bea826020614694565b67ffffffffffffffff811115613c0257613c02613ec6565b6040519080825280601f01601f191660200182016040528015613c2c576020820181803683370190505b509050818152600183018586518101602084015b81831015613c98576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825350600101613c40565b600389510660018114613cb25760028114613cde57613d06565b7f3d3d000000000000000000000000000000000000000000000000000000000000600119830152613d06565b7f3d000000000000000000000000000000000000000000000000000000000000006000198301525b509398975050505050505050565b828054613d2090614466565b90600052602060002090601f016020900481019282613d425760008555613d88565b82601f10613d5b57805160ff1916838001178555613d88565b82800160010185558215613d88579182015b82811115613d88578251825591602001919060010190613d6d565b50613d94929150613db9565b5090565b60405180620464e00160405280612327906020820280368337509192915050565b5b80821115613d945760008155600101613dba565b6001600160e01b031981168114610a1257600080fd5b600060208284031215613df657600080fd5b8135613b7081613dce565b600060208284031215613e1357600080fd5b5035919050565b60005b83811015613e35578181015183820152602001613e1d565b83811115610e315750506000910152565b60008151808452613e5e816020860160208601613e1a565b601f01601f19169290920160200192915050565b602081526000613b706020830184613e46565b6001600160a01b0381168114610a1257600080fd5b60008060408385031215613ead57600080fd5b8235613eb881613e85565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115613ef757613ef7613ec6565b604051601f8501601f19908116603f01168101908282118183101715613f1f57613f1f613ec6565b81604052809350858152868686011115613f3857600080fd5b858560208301376000602087830101525050509392505050565b60008060008060808587031215613f6857600080fd5b8435613f7381613e85565b93506020850135613f8381613e85565b925060408501359150606085013567ffffffffffffffff811115613fa657600080fd5b8501601f81018713613fb757600080fd5b613fc687823560208401613edc565b91505092959194509250565b60008083601f840112613fe457600080fd5b50813567ffffffffffffffff811115613ffc57600080fd5b6020830191508360208260051b85010111156111f757600080fd5b6000806020838503121561402a57600080fd5b823567ffffffffffffffff81111561404157600080fd5b61404d85828601613fd2565b90969095509350505050565b6000806040838503121561406c57600080fd5b50508035926020909101359150565b60008060006060848603121561409057600080fd5b833561409b81613e85565b925060208401356140ab81613e85565b929592945050506040919091013590565b803560ff811681146140cd57600080fd5b919050565b6000602082840312156140e457600080fd5b613b70826140bc565b6060815260006141006060830186613e46565b82810360208401526141128186613e46565b915050826040830152949350505050565b60006020828403121561413557600080fd5b8135613b7081613e85565b6000806000806060858703121561415657600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561417b57600080fd5b61418787828801613fd2565b95989497509550505050565b600080604083850312156141a657600080fd5b613eb8836140bc565b6000806000606084860312156141c457600080fd5b833592506020840135915060408401356141dd81613e85565b809150509250925092565b600082601f8301126141f957600080fd5b613b7083833560208501613edc565b60006020828403121561421a57600080fd5b813567ffffffffffffffff81111561423157600080fd5b612277848285016141e8565b8015158114610a1257600080fd5b6000806040838503121561425e57600080fd5b823561426981613e85565b915060208301356142798161423d565b809150509250929050565b620464e08101818360005b6123278110156142b85781516001600160a01b031683526020928301929091019060010161428f565b50505092915050565b600080600080604085870312156142d757600080fd5b843567ffffffffffffffff808211156142ef57600080fd5b6142fb88838901613fd2565b9096509450602087013591508082111561431457600080fd5b5061418787828801613fd2565b60008060008060008060c0878903121561433a57600080fd5b614343876140bc565b955060208701359450604087013561435a8161423d565b9350606087013561436a8161423d565b9250608087013561437a8161423d565b8092505060a087013590509295509295509295565b600080604083850312156143a257600080fd5b82356143ad81613e85565b9150602083013561427981613e85565b600080600080608085870312156143d357600080fd5b6143dc856140bc565b9350602085013567ffffffffffffffff808211156143f957600080fd5b614405888389016141e8565b9450604087013591508082111561441b57600080fd5b50614428878288016141e8565b949793965093946060013593505050565b634e487b7160e01b600052601160045260246000fd5b60008282101561446157614461614439565b500390565b600181811c9082168061447a57607f821691505b60208210811415610a7257634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006000198214156144c5576144c5614439565b5060010190565b6000602082840312156144de57600080fd5b8151613b7081613e85565b6001600160a01b03841681526040602082015281604082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561453157600080fd5b8260051b8085606085013760009201606001918252509392505050565b60006020828403121561456057600080fd5b8151613b708161423d565b600081600019048311821515161561458557614585614439565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826145af576145af61458a565b500490565b8054600090600181811c90808316806145ce57607f831692505b60208084108214156145f057634e487b7160e01b600052602260045260246000fd5b818015614604576001811461461557614642565b60ff19861689528489019650614642565b60008881526020902060005b8681101561463a5781548b820152908501908301614621565b505084890196505b50505050505092915050565b7f697066733a2f2f0000000000000000000000000000000000000000000000000081526000613b7060078301846145b4565b60008261468f5761468f61458a565b500690565b600082198211156146a7576146a7614439565b500190565b600060ff821660ff8114156146c3576146c3614439565b60010192915050565b600083516146de818460208801613e1a565b6146ea818401856145b4565b95945050505050565b7f7b226e616d65223a224e75636c656172204e6572647320436f6d69632023000081526000875161472b81601e850160208c01613e1a565b7f222c226465736372697074696f6e223a22000000000000000000000000000000601e91840191820152614762602f8201896145b4565b90508651614774818360208b01613e1a565b7f222c22696d616765223a22000000000000000000000000000000000000000000910190815285516147ad81600b840160208a01613e1a565b7f3f6f776e65723d00000000000000000000000000000000000000000000000000600b929091019182015284516147eb816012840160208901613e1a565b7f222c2261747472696275746573223a5b00000000000000000000000000000000601292909101918201528351614829816022840160208801613e1a565b61485b6022828401017f5d7d000000000000000000000000000000000000000000000000000000000000815260020190565b9a9950505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516148a181601d850160208701613e1a565b91909101601d0192915050565b600360fc1b8152600082516148ca816001850160208701613e1a565b9190910160010192915050565b7f7b2274726169745f74797065223a22536572696573222c2276616c7565223a228152602360f81b602082015260008251614919816021850160208701613e1a565b62089f4b60ea1b6021939091019283015250602401919050565b7f7b2274726169745f74797065223a2245646974696f6e222c2276616c7565223a81527f2200000000000000000000000000000000000000000000000000000000000000602082015260008251614919816021850160208701613e1a565b600083516149a3818460208801613e1a565b8351908301906149b7818360208801613e1a565b01949350505050565b602360f81b8152600082516148ca816001850160208701613e1a565b7f7b2274726169745f74797065223a224e657264222c2276616c7565223a220000815260008251614a1481601e850160208701613e1a565b62089f4b60ea1b601e939091019283015250602101919050565b60008351614a40818460208801613e1a565b7f7b2274726169745f74797065223a22536368726f64696e6765720000000000009083019081527f2700000000000000000000000000000000000000000000000000000000000000601a8201527f7320436174222c2276616c7565223a2200000000000000000000000000000000601b8201528351614ac681602b840160208801613e1a565b62089f4b60ea1b602b9290910191820152602e01949350505050565b7f7b2274726169745f74797065223a22537461747573222c2276616c7565223a22815260008251614b1a816020850160208701613e1a565b62089f4b60ea1b6020939091019283015250602301919050565b7f7b22646973706c61795f74797065223a226e756d626572222c2274726169745f81527f74797065223a2253746f727920566f746573222c2276616c7565223a22000000602082015260008251614b9281603d850160208701613e1a565b7f222c226d61785f76616c7565223a223132227d00000000000000000000000000603d939091019283015250605001919050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614bf86080830184613e46565b9695505050505050565b600060208284031215614c1457600080fd5b8151613b7081613dce565b600081614c2e57614c2e614439565b50600019019056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a264697066735822122026719a181c467f36210736d0ef8644a5ba80beede06c2ece956502e6271635f664736f6c634300080900330000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000f78c6eee3c89ff37fd9ef96bd685830993636f2000000000000000000000000efc83375b4bf4e9011a8bc716bdaada4e043e90d000000000000000000000000000000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000000134e75636c656172204e6572647320436f6d696300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4e45524453434f4d49430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002272a2a43484150544552202330303a2054686520426567696e6e696e67206f662074686520456e642a2a5c6e5c6e47726f756e64205a65726f206f66206f7572204e75636c656172204e6572642773204f726967696e2053746f72792c2043686170746572202330302c2054686520426567696e6e696e67206f662074686520456e642c2074616b65732075732066726f6d207468652073747265657473206f6620436f6c6f7261646f20537072696e677320746f206465657020696e736964652043686579656e6e65204d6f756e7461696e2c20686f6d6520746f20746865204e6f72746820416d65726963616e204165726f737061636520446566656e736520436f6d6d616e6420616e642074686520776f726c642773206d6f73742064616e6765726f757320e2809c6c61756e6368e2809d20627574746f6e2e205468616e6b7320746f204169726d616e204e6f726d20616e64206f6e6520657863657074696f6e616c6c79206a7569637920636865657365737465616b2c207375666669636520697420746f207361792c207468696e677320646f206e6f74207475726e206f75742077656c6c20666f722068756d616e6974792e5c6e5c6e5b526561642053657269657320305d28687474703a2f2f6e75636c6561726e657264732e6d7970696e6174612e636c6f75642f697066732f516d57534234564c37677269366952474378315748534741616e5a50336f67664679516e5650566868357273776d295c6e5c6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d564e4c455a736d6444464457413875674635526d37445a5a7952753537663232613364456a5a794b4d57396a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dc54686572652061726520382c393939204e75636c656172204e6572647320436f6d696320546f6b656e732c20656163682075706772616461626c6520746f20746865206c617465737420436f6d696320697373756520647572696e672074686174206973737565277320757067726164652077696e646f772e20446f696e6720736f2077696c6c206368616e67652074686520646973706c617920617274206f662074686520436f6d696320746f6b656e20746f2074686520636f76657220617274206f6620746861742069737375652e204f6e63652075706772616465642c206120436f6d696320746f6b656e2063616e6e6f7420676f206261636b776172647320746f20612070726576696f75732069737375652e2052656d656d6265723a2074686520696e697469616c206169722d64726f70206f662074686520436f6d696320746f6b656e20697320617474616368656420746f207468617420746f6b656e27732027706172656e7427204e6572642e20496620796f752073656c6c20796f7572204e65726420776974686f75742027756e70616972696e672720796f757220436f6d69632c20796f757220436f6d696320746f6b656e2077696c6c20626520736f6c64207769746820796f7572204e6572642e5c6e5c6e0000000000000000000000000000000000000000000000000000000000000000000000cb5468697320436f6d696320746f6b656e20706f737365737365732074686520536368726f64696e676572204d79737465727920547261697420616e642063616e2062652072656465656d656420666f722074686520506879736963616c20416e74686f6c6f67792061742074686520656e64206f6620536561736f6e20312e20497420616c736f2067697665732074686520686f6c64657220696d6d6564696174652061636365737320746f203132206164646974696f6e616c2053746f727920566f7465732e5c6e5c6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000885468697320436f6d696320746f6b656e20686173206265656e2072656465656d656420666f72206120506879736963616c20416e74686f6c6f677920616e642063616e6e6f742062652072657573656420696e20746861742063617061636974792e20466f72206d6f726520696e666f726d6174696f6e20766965772070726f706572746965732e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d5769577367366a70364d7076586b544b674367636f38316b5a3846544a53637a66625336424a683234697453000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103eb5760003560e01c8063873b99561161021a578063c2c74f8a11610135578063e6bc672d116100c8578063e985e9c511610097578063f0d1700e1161007c578063f0d1700e146108f0578063f2fde38b14610903578063f83d08ba1461091657600080fd5b8063e985e9c5146108a0578063ea462b56146108dd57600080fd5b8063e6bc672d1461086a578063e71f6c2f1461087d578063e8a3d48514610890578063e8dee6581461089857600080fd5b8063c982681b11610104578063c982681b1461080c578063cf30901214610830578063cf34842514610844578063e2df2c731461085757600080fd5b8063c2c74f8a146107d4578063c4217932146107e7578063c6ec6909146107ef578063c87b56dd146107f957600080fd5b8063a22cb465116101ad578063b071cdb41161017c578063b071cdb414610788578063b0954dee1461079b578063b37f66e7146107ae578063b88d4fde146107c157600080fd5b8063a22cb4651461073a578063a2f13aba1461074d578063ae40c3e014610760578063affe39c11461077357600080fd5b806395d89b41116101e957806395d89b41146106f85780639bcf4f03146107005780639f9e97b8146107135780639fbc87131461072657600080fd5b8063873b9956146106b85780638da5cb5b146106c05780638dc251e3146106d2578063938e3d7b146106e557600080fd5b806342842e0e1161030a578063663cc3731161029d57806370a082311161026c57806370a0823114610669578063715018a61461067c57806371c185b214610684578063809b8fad146106a557600080fd5b8063663cc3731461061d5780636914db60146106305780636fff617b1461064357806370255cfd1461065657600080fd5b80635659bd62116102d95780635659bd62146105dc5780636352211e146105ef578063654edd00146106025780636626ada21461061557600080fd5b806342842e0e1461058f578063444d9172146105a257806344bdde08146105b657806353004a99146105c957600080fd5b80631d398554116103825780632a55205a116103515780632a55205a1461051a5780633c5283891461054c5780633ed213731461056e5780634083e9421461057c57600080fd5b80631d398554146104cb57806322db91b3146104de57806323b872dd146104f4578063272e7dbc1461050757600080fd5b8063081812fc116103be578063081812fc14610467578063095ea7b3146104925780630d114c9a146104a557806319a1ec83146104b857600080fd5b806301ffc9a7146103f057806302f2e47a1461041857806303f765761461042d57806306fdde0314610452575b600080fd5b6104036103fe366004613de4565b61091e565b60405190151581526020015b60405180910390f35b61042b610426366004613e01565b610996565b005b61044061043b366004613e01565b610a15565b60405160ff909116815260200161040f565b61045a610a78565b60405161040f9190613e72565b61047a610475366004613e01565b610b0a565b6040516001600160a01b03909116815260200161040f565b61042b6104a0366004613e9a565b610bb1565b61042b6104b3366004613f52565b610ce3565b6104036104c6366004614017565b610e37565b61042b6104d9366004614059565b610e8f565b6104e6604081565b60405190815260200161040f565b61042b61050236600461407b565b61105b565b61042b610515366004614017565b6110e2565b61052d610528366004614059565b6111c1565b604080516001600160a01b03909316835260208301919091520161040f565b61055f61055a3660046140d2565b6111fe565b60405161040f939291906140ed565b612334546104039060ff1681565b61045a61058a3660046140d2565b611331565b61042b61059d36600461407b565b6113b6565b61232b5461047a906001600160a01b031681565b6104406105c4366004613e01565b6113d1565b61042b6105d7366004614059565b611444565b61042b6105ea366004614123565b6114f5565b61047a6105fd366004613e01565b61158b565b61042b610610366004614140565b611638565b6104e6600481565b61042b61062b366004614193565b611796565b61045a61063e366004613e01565b6117cf565b61042b6106513660046141af565b611842565b61042b61066436600461407b565b611908565b6104e6610677366004614123565b6119e8565b61042b611abd565b6104e6610692366004613e01565b6123336020526000908152604090205481565b61042b6106b3366004613e01565b611b12565b61042b611c48565b61232c546001600160a01b031661047a565b61042b6106e0366004614123565b611ca3565b61042b6106f3366004614208565b611d8b565b61045a611de8565b61042b61070e366004614017565b611df7565b610403610721366004614017565b611f70565b6123385461047a906001600160a01b031681565b61042b61074836600461424b565b611fbe565b61042b61075b366004614017565b611fc9565b61042b61076e366004613e01565b6120c7565b61077b612116565b60405161040f9190614284565b61042b610796366004614017565b61215e565b6104036107a9366004613e01565b612200565b61042b6107bc3660046141af565b61227f565b61042b6107cf366004613f52565b612339565b61042b6107e23660046142c1565b6123c1565b61045a612491565b6104e66123375481565b61045a610807366004613e01565b612520565b61040361081a366004614123565b6123356020526000908152604090205460ff1681565b612334546104039062010000900460ff1681565b61045a610852366004613e01565b612701565b61045a610865366004614321565b61273d565b6123345461040390610100900460ff1681565b61042b61088b366004614123565b612b17565b61045a612bb4565b6104e6600d81565b6104036108ae36600461438f565b6001600160a01b03918216600090815261232a6020908152604080832093909416825291909152205460ff1690565b61042b6108eb366004613e01565b612bdd565b61042b6108fe3660046143bd565b612c90565b61042b610911366004614123565b612dcd565b61042b612e9b565b60006001600160e01b031982167f2a55205a00000000000000000000000000000000000000000000000000000000148061098157506001600160e01b031982167f2e11ffbb00000000000000000000000000000000000000000000000000000000145b80610990575061099082612ef8565b92915050565b6123345462010000900460ff166109c0576040516313f97ebb60e21b815260040160405180910390fd5b600081815261232f602052604090205460ff16610a09576040517f68163b6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a1281612f93565b50565b600081610a25600161232761444f565b811115610a455760405163677510db60e11b815260040160405180910390fd5b600083815261232f602052604090205460ff1615610a6657600c9150610a72565b610a6f836113d1565b91505b50919050565b606060008054610a8790614466565b80601f0160208091040260200160405190810160405280929190818152602001828054610ab390614466565b8015610b005780601f10610ad557610100808354040283529160200191610b00565b820191906000526020600020905b815481529060010190602001808311610ae357829003601f168201915b5050505050905090565b60006123278210610b775760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b6000610b828361158b565b6000938452612329602090815260408086206001600160a01b0393841687529091529093205490921692915050565b6000610bbc8261158b565b9050806001600160a01b0316836001600160a01b03161415610c465760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152608401610b6e565b336001600160a01b0382161480610c625750610c6281336108ae565b610cd45760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c00000000000000006064820152608401610b6e565b610cde8383613053565b505050565b336000908152612335602052604090205460ff16610d14576040516320040d8560e01b815260040160405180910390fd5b610d1d826130cd565b610e31576000828152612329602090815260408083206001600160a01b038816808552925280832080546001600160a01b031916905551849291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a481836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4610dca848484846130f7565b610e315760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610b6e565b50505050565b6000805b82811015610e8557610e64848483818110610e5857610e5861449b565b905060200201356130cd565b15610e73576000915050610990565b80610e7d816144b1565b915050610e3b565b5060019392505050565b61233454610100900460ff1615610eb95760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b03163314610f025760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b815b81811015610cde5761232b546040516331a9108f60e11b8152600481018390526000916001600160a01b031690636352211e9060240160206040518083038186803b158015610f5257600080fd5b505afa158015610f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8a91906144cc565b60405190915082906001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a4610fe160008284604051806020016040528060008152506130f7565b6110485760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610b6e565b5080611053816144b1565b915050610f04565b611065338261324f565b6110d75760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b6e565b610cde838383613332565b61232b546001600160a01b0316634d44660c3384846040518463ffffffff1660e01b8152600401611115939291906144e9565b60206040518083038186803b15801561112d57600080fd5b505afa158015611141573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611165919061454e565b611182576040516371d3ec2560e11b815260040160405180910390fd5b60005b81811015610cde576111af338484848181106111a3576111a361449b565b90506020020135613505565b806111b9816144b1565b915050611185565b612338546123375460009182916001600160a01b0390911690612710906111e8908661456b565b6111f291906145a0565b915091505b9250929050565b61232d6020526000908152604090208054819061121a90614466565b80601f016020809104026020016040519081016040528092919081815260200182805461124690614466565b80156112935780601f1061126857610100808354040283529160200191611293565b820191906000526020600020905b81548152906001019060200180831161127657829003601f168201915b5050505050908060010180546112a890614466565b80601f01602080910402602001604051908101604052809291908181526020018280546112d490614466565b80156113215780601f106112f657610100808354040283529160200191611321565b820191906000526020600020905b81548152906001019060200180831161130457829003601f168201915b5050505050908060020154905083565b60ff8116600090815261232d602052604090206001018054606091839161135790614466565b151590506113785760405163071f08b360e11b815260040160405180910390fd5b60ff8316600090815261232d6020908152604091829020915161139f92600101910161464e565b604051602081830303815290604052915050919050565b610cde83838360405180602001604052806000815250612339565b6000816113e1600161232761444f565b8111156114015760405163677510db60e11b815260040160405180910390fd5b600461140e604085614680565b611418919061456b565b61232e60006114286040876145a0565b815260200190815260200160002054901c600f16915050919050565b61233454610100900460ff161561146e5760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146114b75760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b604051818152309060009084907fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d9060200160405180910390a45050565b61233454610100900460ff161561151f5760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146115685760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b61232b80546001600160a01b0319166001600160a01b0392909216919091179055565b60008060028361232781106115a2576115a261449b565b01546001600160a01b0316905080156115bb5792915050565b61232b546040516331a9108f60e11b8152600481018590526001600160a01b0390911690636352211e9060240160206040518083038186803b15801561160057600080fd5b505afa158015611614573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6f91906144cc565b61233454610100900460ff16156116625760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146116ab5760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b60006116b7858561444f565b6116c2906001614694565b90508181146116fd576040517f2292985d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000855b85811161178d5780858584611715816144b1565b95508181106117265761172661449b565b905060200201602081019061173b9190614123565b6001600160a01b031660006001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480611785816144b1565b915050611701565b50505050505050565b6123345462010000900460ff16156117c157604051634a93292d60e11b815260040160405180910390fd5b6117cb8282613615565b5050565b6060816117df600161232761444f565b8111156117ff5760405163677510db60e11b815260040160405180910390fd5b610a6f61180b846113d1565b8461181586612200565b61181e876130cd565b600088815261232f602052604090205460ff1661183a89610a15565b60ff1661273d565b61233454610100900460ff161561186c5760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146118b55760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b306001600160a01b0316816001600160a01b0316847fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d856040516118fb91815260200190565b60405180910390a4505050565b336000908152612335602052604090205460ff16611939576040516320040d8560e01b815260040160405180910390fd5b611942816130cd565b610cde576000818152612329602090815260408083206001600160a01b038716808552925280832080546001600160a01b031916905551839291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a480826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050565b60006001600160a01b038216611a665760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a6560448201527f726f2061646472657373000000000000000000000000000000000000000000006064820152608401610b6e565b6000805b612327811015611ab657836001600160a01b0316611a878261158b565b6001600160a01b03161415611aa45781611aa0816144b1565b9250505b80611aae816144b1565b915050611a6a565b5092915050565b61232c546001600160a01b03163314611b065760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b611b106000613773565b565b61233454610100900460ff1615611b3c5760405163114f7cf360e11b815260040160405180910390fd5b611b45816130cd565b15611b63576040516331cde96f60e21b815260040160405180910390fd5b61232b546040516331a9108f60e11b8152600481018390526000916001600160a01b031690636352211e9060240160206040518083038186803b158015611ba957600080fd5b505afa158015611bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be191906144cc565b9050336001600160a01b03821614611c0c576040516371d3ec2560e11b815260040160405180910390fd5b60405182906001600160a01b0383169030907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90600090a45050565b61232c546001600160a01b03163314611c915760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b612334805461ff001916610100179055565b61232c546001600160a01b03163314611cec5760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6001600160a01b038116611d685760405162461bcd60e51b815260206004820152602c60248201527f526f79616c746965733a206e657720726563697069656e74206973207468652060448201527f7a65726f206164647265737300000000000000000000000000000000000000006064820152608401610b6e565b61233880546001600160a01b0319166001600160a01b0392909216919091179055565b61232c546001600160a01b03163314611dd45760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b80516117cb90612336906020840190613d14565b606060018054610a8790614466565b61233454610100900460ff1615611e215760405163114f7cf360e11b815260040160405180910390fd5b61232b546001600160a01b0316634d44660c3384846040518463ffffffff1660e01b8152600401611e54939291906144e9565b60206040518083038186803b158015611e6c57600080fd5b505afa158015611e80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea4919061454e565b611ec1576040516371d3ec2560e11b815260040160405180910390fd5b60005b81811015610cde57611ee1838383818110610e5857610e5861449b565b15611eff576040516331cde96f60e21b815260040160405180910390fd5b828282818110611f1157611f1161449b565b90506020020135611f1f3390565b6001600160a01b0316306001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a480611f68816144b1565b915050611ec4565b6000805b82811015610e8557611f9d848483818110611f9157611f9161449b565b90506020020135612200565b15611fac576000915050610990565b80611fb6816144b1565b915050611f74565b6117cb3383836137c6565b61232c546001600160a01b031633146120125760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6123345460ff1615612050576040517f99d117e600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612334805460ff1916600117905560005b60ff8116821115610cde57600161232f600085858560ff168181106120885761208861449b565b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555080806120bf906146ac565b915050612061565b61232c546001600160a01b031633146121105760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b61233755565b61211e613d98565b60408051620464e0810191829052906002906123279082845b81546001600160a01b03168152600190910190602001808311612137575050505050905090565b6123345462010000900460ff16612188576040516313f97ebb60e21b815260040160405180910390fd5b600d81146121c2576040517f172e743e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610cde576121ee8383838181106121e2576121e261449b565b90506020020135612f93565b806121f8816144b1565b9150506121c5565b600081612210600161232761444f565b8111156122305760405163677510db60e11b815260040160405180910390fd5b6000600161224061010086614680565b6123336000612251610100896145a0565b815260200190815260200160002054901c16905080600114612274576000612277565b60015b949350505050565b61233454610100900460ff16156122a95760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b031633146122f25760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b806001600160a01b031660006001600160a01b0316847fdeaa91b6123d068f5821d0fb0678463d1a8a6079fe8af5de3ce5e896dcf9133d856040516118fb91815260200190565b612343338361324f565b6123b55760405162461bcd60e51b815260206004820152603160248201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f60448201527f776e6572206e6f7220617070726f7665640000000000000000000000000000006064820152608401610b6e565b610e3184848484613896565b6123345462010000900460ff16156123ec57604051634a93292d60e11b815260040160405180910390fd5b828114612425576040517f515871e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8381101561248a576124788585838181106124455761244561449b565b905060200201602081019061245a91906140d2565b84848481811061246c5761246c61449b565b90506020020135613615565b80612482816144b1565b915050612428565b5050505050565b612336805461249f90614466565b80601f01602080910402602001604051908101604052809291908181526020018280546124cb90614466565b80156125185780601f106124ed57610100808354040283529160200191612518565b820191906000526020600020905b8154815290600101906020018083116124fb57829003601f168201915b505050505081565b606081612530600161232761444f565b8111156125505760405163677510db60e11b815260040160405180910390fd5b600061255b846113d1565b60ff8116600090815261232d6020526040902080549192509061257d90614466565b80601f01602080910402602001604051908101604052809291908181526020018280546125a990614466565b80156125f65780601f106125cb576101008083540402835291602001916125f6565b820191906000526020600020905b8154815290600101906020018083116125d957829003601f168201915b505050600087815261232f6020526040902054929550505060ff161561263d578261233160405160200161262b9291906146cc565b60405160208183030381529060405292505b61264684612200565b1561267257826123326040516020016126609291906146cc565b60405160208183030381529060405292505b6126d961267e856138ad565b6123308561268b85611331565b6126a76126978a61158b565b6001600160a01b031660146139ab565b6126b08a6117cf565b6040516020016126c5969594939291906146f3565b604051602081830303815290604052613b77565b6040516020016126e99190614869565b60405160208183030381529060405292505050919050565b606081612711600161232761444f565b8111156127315760405163677510db60e11b815260040160405180910390fd5b610a6f61058a846113d1565b60ff8616600090815261232d602052604090206001018054606091889161276390614466565b151590506127845760405163071f08b360e11b815260040160405180910390fd5b600a8860ff16106127a05761279b8860ff166138ad565b6127cc565b6127ac8860ff166138ad565b6040516020016127bc91906148ae565b6040516020818303038152906040525b6040516020016127dc91906148d7565b60408051601f1981840301815291815260ff8a16600090815261232d602052206002015490925082904211612846576040518060400160405280600781526020017f4d696e74696e670000000000000000000000000000000000000000000000000081525061287d565b6040518060400160405280600781526020017f4c696d69746564000000000000000000000000000000000000000000000000008152505b60405160200161288d9190614933565b60408051601f19818403018152908290526128ab9291602001614991565b60405160208183030381529060405291508185156128fe576040518060400160405280600881526020017f556e706169726564000000000000000000000000000000000000000000000000815250612927565b612907886138ad565b60405160200161291791906149c0565b6040516020818303038152906040525b60405160200161293791906149dc565b60408051601f19818403018152908290526129559291602001614991565b60405160208183030381529060405291508315612a0b5781866129ad576040518060400160405280600581526020017f416c6976650000000000000000000000000000000000000000000000000000008152506129e4565b6040518060400160405280600481526020017f44656164000000000000000000000000000000000000000000000000000000008152505b6040516020016129f5929190614a2e565b6040516020818303038152906040529150612ac3565b8186612a4c576040518060400160405280600a81526020017f556e72656465656d656400000000000000000000000000000000000000000000815250612a83565b6040518060400160405280600881526020017f52656465656d65640000000000000000000000000000000000000000000000008152505b604051602001612a939190614ae2565b60408051601f1981840301815290829052612ab19291602001614991565b60405160208183030381529060405291505b81612acd846138ad565b604051602001612add9190614b34565b60408051601f1981840301815290829052612afb9291602001614991565b6040516020818303038152906040529150509695505050505050565b61233454610100900460ff1615612b415760405163114f7cf360e11b815260040160405180910390fd5b61232c546001600160a01b03163314612b8a5760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6001600160a01b0316600090815261233560205260409020805460ff19811660ff90911615179055565b6060612336604051602001612bc9919061464e565b604051602081830303815290604052905090565b3361232b546040516331a9108f60e11b8152600481018490526001600160a01b039283169290911690636352211e9060240160206040518083038186803b158015612c2757600080fd5b505afa158015612c3b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c5f91906144cc565b6001600160a01b031614612c86576040516371d3ec2560e11b815260040160405180910390fd5b610a123382613505565b6123345462010000900460ff1615612cbb57604051634a93292d60e11b815260040160405180910390fd5b61232c546001600160a01b03163314612d045760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b60ff8416600090815261232d602052604090206001018054612d2590614466565b159050612d5e576040517f4cf58b4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051606081018252848152602080820185905281830184905260ff8716600090815261232d8252929092208151805192939192612da09284920190613d14565b506020828101518051612db99260018501920190613d14565b506040820151816002015590505050505050565b61232c546001600160a01b03163314612e165760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b6001600160a01b038116612e925760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b6e565b610a1281613773565b61232c546001600160a01b03163314612ee45760405162461bcd60e51b81526020600482018190526024820152600080516020614c778339815191526044820152606401610b6e565b612334805462ff0000191662010000179055565b60006001600160e01b031982167f80ac58cd000000000000000000000000000000000000000000000000000000001480612f5b57506001600160e01b031982167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061099057507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610990565b33612f9d8261158b565b6001600160a01b031614612fc4576040516371d3ec2560e11b815260040160405180910390fd5b6000612fd2610100836145a0565b90506000612fe261010084614680565b60008381526123336020526040902054909150811c60019081161415613034576040517ff6dd524a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600091825261233360205260409091208054600190921b909117905550565b600061305e8261158b565b6000838152612329602090815260408083206001600160a01b038581168086529190935281842080546001600160a01b031916938916938417905590519394508593919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259190a4505050565b60008060028361232781106130e4576130e461449b565b01546001600160a01b0316141592915050565b60006001600160a01b0384163b1561324457604051630a85bd0160e11b81526001600160a01b0385169063150b7a029061313b903390899088908890600401614bc6565b602060405180830381600087803b15801561315557600080fd5b505af1925050508015613185575060408051601f3d908101601f1916820190925261318291810190614c02565b60015b61322a573d8080156131b3576040519150601f19603f3d011682016040523d82523d6000602084013e6131b8565b606091505b5080516132225760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608401610b6e565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050612277565b506001949350505050565b600061232782106132b75760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b6064820152608401610b6e565b60006132c28361158b565b9050806001600160a01b0316846001600160a01b031614806132fd5750836001600160a01b03166132f284610b0a565b6001600160a01b0316145b8061227757506001600160a01b03808216600090815261232a602090815260408083209388168352929052205460ff16612277565b600061333d8261158b565b9050836001600160a01b0316816001600160a01b0316146133c65760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152608401610b6e565b6001600160a01b0383166134415760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610b6e565b6000828152612329602090815260408083206001600160a01b038516808552925280832080546001600160a01b031916905551849291907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925908390a48260028361232781106134b2576134b261449b565b0180546001600160a01b0319166001600160a01b03928316179055604051839185811691908716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90600090a4610e31565b6001600160a01b03821661355b5760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610b6e565b613564816130cd565b156135b15760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610b6e565b8160028261232781106135c6576135c661449b565b0180546001600160a01b0319166001600160a01b0392831617905560405182918416906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b60ff8216600090815261232d60205260409020600101805483919061363990614466565b1515905061365a5760405163071f08b360e11b815260040160405180910390fd5b6136638261158b565b6001600160a01b0316336001600160a01b031614613694576040516371d3ec2560e11b815260040160405180910390fd5b60006136a16040846145a0565b9050600060046136b2604086614680565b6136bc919061456b565b600083815261232e602052604090205490915060ff861690821c600f161115613711576040517fdc86b7bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff8516600090815261232d602052604090206002015442111561374857604051634a93292d60e11b815260040160405180910390fd5b600091825261232e60205260409091208054600f831b191660ff90951690911b939093179092555050565b61232c80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b816001600160a01b0316836001600160a01b031614156138285760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610b6e565b6001600160a01b03838116600081815261232a6020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6138a1848484613332565b610dca848484846130f7565b6060816138d15750506040805180820190915260018152600360fc1b602082015290565b8160005b81156138fb57806138e5816144b1565b91506138f49050600a836145a0565b91506138d5565b60008167ffffffffffffffff81111561391657613916613ec6565b6040519080825280601f01601f191660200182016040528015613940576020820181803683370190505b5090505b84156122775761395560018361444f565b9150613962600a86614680565b61396d906030614694565b60f81b8183815181106139825761398261449b565b60200101906001600160f81b031916908160001a9053506139a4600a866145a0565b9450613944565b606060006139ba83600261456b565b6139c5906002614694565b67ffffffffffffffff8111156139dd576139dd613ec6565b6040519080825280601f01601f191660200182016040528015613a07576020820181803683370190505b509050600360fc1b81600081518110613a2257613a2261449b565b60200101906001600160f81b031916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110613a6d57613a6d61449b565b60200101906001600160f81b031916908160001a9053506000613a9184600261456b565b613a9c906001614694565b90505b6001811115613b21577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110613add57613add61449b565b1a60f81b828281518110613af357613af361449b565b60200101906001600160f81b031916908160001a90535060049490941c93613b1a81614c1f565b9050613a9f565b508315613b705760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b6e565b9392505050565b6060815160001415613b9757505060408051602081019091526000815290565b6000604051806060016040528060408152602001614c376040913990506000600384516002613bc69190614694565b613bd091906145a0565b613bdb90600461456b565b90506000613bea826020614694565b67ffffffffffffffff811115613c0257613c02613ec6565b6040519080825280601f01601f191660200182016040528015613c2c576020820181803683370190505b509050818152600183018586518101602084015b81831015613c98576003830192508251603f8160121c168501518253600182019150603f81600c1c168501518253600182019150603f8160061c168501518253600182019150603f8116850151825350600101613c40565b600389510660018114613cb25760028114613cde57613d06565b7f3d3d000000000000000000000000000000000000000000000000000000000000600119830152613d06565b7f3d000000000000000000000000000000000000000000000000000000000000006000198301525b509398975050505050505050565b828054613d2090614466565b90600052602060002090601f016020900481019282613d425760008555613d88565b82601f10613d5b57805160ff1916838001178555613d88565b82800160010185558215613d88579182015b82811115613d88578251825591602001919060010190613d6d565b50613d94929150613db9565b5090565b60405180620464e00160405280612327906020820280368337509192915050565b5b80821115613d945760008155600101613dba565b6001600160e01b031981168114610a1257600080fd5b600060208284031215613df657600080fd5b8135613b7081613dce565b600060208284031215613e1357600080fd5b5035919050565b60005b83811015613e35578181015183820152602001613e1d565b83811115610e315750506000910152565b60008151808452613e5e816020860160208601613e1a565b601f01601f19169290920160200192915050565b602081526000613b706020830184613e46565b6001600160a01b0381168114610a1257600080fd5b60008060408385031215613ead57600080fd5b8235613eb881613e85565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b600067ffffffffffffffff80841115613ef757613ef7613ec6565b604051601f8501601f19908116603f01168101908282118183101715613f1f57613f1f613ec6565b81604052809350858152868686011115613f3857600080fd5b858560208301376000602087830101525050509392505050565b60008060008060808587031215613f6857600080fd5b8435613f7381613e85565b93506020850135613f8381613e85565b925060408501359150606085013567ffffffffffffffff811115613fa657600080fd5b8501601f81018713613fb757600080fd5b613fc687823560208401613edc565b91505092959194509250565b60008083601f840112613fe457600080fd5b50813567ffffffffffffffff811115613ffc57600080fd5b6020830191508360208260051b85010111156111f757600080fd5b6000806020838503121561402a57600080fd5b823567ffffffffffffffff81111561404157600080fd5b61404d85828601613fd2565b90969095509350505050565b6000806040838503121561406c57600080fd5b50508035926020909101359150565b60008060006060848603121561409057600080fd5b833561409b81613e85565b925060208401356140ab81613e85565b929592945050506040919091013590565b803560ff811681146140cd57600080fd5b919050565b6000602082840312156140e457600080fd5b613b70826140bc565b6060815260006141006060830186613e46565b82810360208401526141128186613e46565b915050826040830152949350505050565b60006020828403121561413557600080fd5b8135613b7081613e85565b6000806000806060858703121561415657600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561417b57600080fd5b61418787828801613fd2565b95989497509550505050565b600080604083850312156141a657600080fd5b613eb8836140bc565b6000806000606084860312156141c457600080fd5b833592506020840135915060408401356141dd81613e85565b809150509250925092565b600082601f8301126141f957600080fd5b613b7083833560208501613edc565b60006020828403121561421a57600080fd5b813567ffffffffffffffff81111561423157600080fd5b612277848285016141e8565b8015158114610a1257600080fd5b6000806040838503121561425e57600080fd5b823561426981613e85565b915060208301356142798161423d565b809150509250929050565b620464e08101818360005b6123278110156142b85781516001600160a01b031683526020928301929091019060010161428f565b50505092915050565b600080600080604085870312156142d757600080fd5b843567ffffffffffffffff808211156142ef57600080fd5b6142fb88838901613fd2565b9096509450602087013591508082111561431457600080fd5b5061418787828801613fd2565b60008060008060008060c0878903121561433a57600080fd5b614343876140bc565b955060208701359450604087013561435a8161423d565b9350606087013561436a8161423d565b9250608087013561437a8161423d565b8092505060a087013590509295509295509295565b600080604083850312156143a257600080fd5b82356143ad81613e85565b9150602083013561427981613e85565b600080600080608085870312156143d357600080fd5b6143dc856140bc565b9350602085013567ffffffffffffffff808211156143f957600080fd5b614405888389016141e8565b9450604087013591508082111561441b57600080fd5b50614428878288016141e8565b949793965093946060013593505050565b634e487b7160e01b600052601160045260246000fd5b60008282101561446157614461614439565b500390565b600181811c9082168061447a57607f821691505b60208210811415610a7257634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60006000198214156144c5576144c5614439565b5060010190565b6000602082840312156144de57600080fd5b8151613b7081613e85565b6001600160a01b03841681526040602082015281604082015260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561453157600080fd5b8260051b8085606085013760009201606001918252509392505050565b60006020828403121561456057600080fd5b8151613b708161423d565b600081600019048311821515161561458557614585614439565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826145af576145af61458a565b500490565b8054600090600181811c90808316806145ce57607f831692505b60208084108214156145f057634e487b7160e01b600052602260045260246000fd5b818015614604576001811461461557614642565b60ff19861689528489019650614642565b60008881526020902060005b8681101561463a5781548b820152908501908301614621565b505084890196505b50505050505092915050565b7f697066733a2f2f0000000000000000000000000000000000000000000000000081526000613b7060078301846145b4565b60008261468f5761468f61458a565b500690565b600082198211156146a7576146a7614439565b500190565b600060ff821660ff8114156146c3576146c3614439565b60010192915050565b600083516146de818460208801613e1a565b6146ea818401856145b4565b95945050505050565b7f7b226e616d65223a224e75636c656172204e6572647320436f6d69632023000081526000875161472b81601e850160208c01613e1a565b7f222c226465736372697074696f6e223a22000000000000000000000000000000601e91840191820152614762602f8201896145b4565b90508651614774818360208b01613e1a565b7f222c22696d616765223a22000000000000000000000000000000000000000000910190815285516147ad81600b840160208a01613e1a565b7f3f6f776e65723d00000000000000000000000000000000000000000000000000600b929091019182015284516147eb816012840160208901613e1a565b7f222c2261747472696275746573223a5b00000000000000000000000000000000601292909101918201528351614829816022840160208801613e1a565b61485b6022828401017f5d7d000000000000000000000000000000000000000000000000000000000000815260020190565b9a9950505050505050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c0000008152600082516148a181601d850160208701613e1a565b91909101601d0192915050565b600360fc1b8152600082516148ca816001850160208701613e1a565b9190910160010192915050565b7f7b2274726169745f74797065223a22536572696573222c2276616c7565223a228152602360f81b602082015260008251614919816021850160208701613e1a565b62089f4b60ea1b6021939091019283015250602401919050565b7f7b2274726169745f74797065223a2245646974696f6e222c2276616c7565223a81527f2200000000000000000000000000000000000000000000000000000000000000602082015260008251614919816021850160208701613e1a565b600083516149a3818460208801613e1a565b8351908301906149b7818360208801613e1a565b01949350505050565b602360f81b8152600082516148ca816001850160208701613e1a565b7f7b2274726169745f74797065223a224e657264222c2276616c7565223a220000815260008251614a1481601e850160208701613e1a565b62089f4b60ea1b601e939091019283015250602101919050565b60008351614a40818460208801613e1a565b7f7b2274726169745f74797065223a22536368726f64696e6765720000000000009083019081527f2700000000000000000000000000000000000000000000000000000000000000601a8201527f7320436174222c2276616c7565223a2200000000000000000000000000000000601b8201528351614ac681602b840160208801613e1a565b62089f4b60ea1b602b9290910191820152602e01949350505050565b7f7b2274726169745f74797065223a22537461747573222c2276616c7565223a22815260008251614b1a816020850160208701613e1a565b62089f4b60ea1b6020939091019283015250602301919050565b7f7b22646973706c61795f74797065223a226e756d626572222c2274726169745f81527f74797065223a2253746f727920566f746573222c2276616c7565223a22000000602082015260008251614b9281603d850160208701613e1a565b7f222c226d61785f76616c7565223a223132227d00000000000000000000000000603d939091019283015250605001919050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152614bf86080830184613e46565b9695505050505050565b600060208284031215614c1457600080fd5b8151613b7081613dce565b600081614c2e57614c2e614439565b50600019019056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a264697066735822122026719a181c467f36210736d0ef8644a5ba80beede06c2ece956502e6271635f664736f6c63430008090033

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

0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000068000000000000000000000000000000000000000000000000000000000000007800000000000000000000000000f78c6eee3c89ff37fd9ef96bd685830993636f2000000000000000000000000efc83375b4bf4e9011a8bc716bdaada4e043e90d000000000000000000000000000000000000000000000000000000000000084000000000000000000000000000000000000000000000000000000000000000134e75636c656172204e6572647320436f6d696300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4e45524453434f4d49430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002272a2a43484150544552202330303a2054686520426567696e6e696e67206f662074686520456e642a2a5c6e5c6e47726f756e64205a65726f206f66206f7572204e75636c656172204e6572642773204f726967696e2053746f72792c2043686170746572202330302c2054686520426567696e6e696e67206f662074686520456e642c2074616b65732075732066726f6d207468652073747265657473206f6620436f6c6f7261646f20537072696e677320746f206465657020696e736964652043686579656e6e65204d6f756e7461696e2c20686f6d6520746f20746865204e6f72746820416d65726963616e204165726f737061636520446566656e736520436f6d6d616e6420616e642074686520776f726c642773206d6f73742064616e6765726f757320e2809c6c61756e6368e2809d20627574746f6e2e205468616e6b7320746f204169726d616e204e6f726d20616e64206f6e6520657863657074696f6e616c6c79206a7569637920636865657365737465616b2c207375666669636520697420746f207361792c207468696e677320646f206e6f74207475726e206f75742077656c6c20666f722068756d616e6974792e5c6e5c6e5b526561642053657269657320305d28687474703a2f2f6e75636c6561726e657264732e6d7970696e6174612e636c6f75642f697066732f516d57534234564c37677269366952474378315748534741616e5a50336f67664679516e5650566868357273776d295c6e5c6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d564e4c455a736d6444464457413875674635526d37445a5a7952753537663232613364456a5a794b4d57396a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dc54686572652061726520382c393939204e75636c656172204e6572647320436f6d696320546f6b656e732c20656163682075706772616461626c6520746f20746865206c617465737420436f6d696320697373756520647572696e672074686174206973737565277320757067726164652077696e646f772e20446f696e6720736f2077696c6c206368616e67652074686520646973706c617920617274206f662074686520436f6d696320746f6b656e20746f2074686520636f76657220617274206f6620746861742069737375652e204f6e63652075706772616465642c206120436f6d696320746f6b656e2063616e6e6f7420676f206261636b776172647320746f20612070726576696f75732069737375652e2052656d656d6265723a2074686520696e697469616c206169722d64726f70206f662074686520436f6d696320746f6b656e20697320617474616368656420746f207468617420746f6b656e27732027706172656e7427204e6572642e20496620796f752073656c6c20796f7572204e65726420776974686f75742027756e70616972696e672720796f757220436f6d69632c20796f757220436f6d696320746f6b656e2077696c6c20626520736f6c64207769746820796f7572204e6572642e5c6e5c6e0000000000000000000000000000000000000000000000000000000000000000000000cb5468697320436f6d696320746f6b656e20706f737365737365732074686520536368726f64696e676572204d79737465727920547261697420616e642063616e2062652072656465656d656420666f722074686520506879736963616c20416e74686f6c6f67792061742074686520656e64206f6620536561736f6e20312e20497420616c736f2067697665732074686520686f6c64657220696d6d6564696174652061636365737320746f203132206164646974696f6e616c2053746f727920566f7465732e5c6e5c6e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000885468697320436f6d696320746f6b656e20686173206265656e2072656465656d656420666f72206120506879736963616c20416e74686f6c6f677920616e642063616e6e6f742062652072657573656420696e20746861742063617061636974792e20466f72206d6f726520696e666f726d6174696f6e20766965772070726f706572746965732e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e516d5769577367366a70364d7076586b544b674367636f38316b5a3846544a53637a66625336424a683234697453000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): Nuclear Nerds Comic
Arg [1] : _symbol (string): NERDSCOMIC
Arg [2] : _seriesZeroDescription (string): **CHAPTER #00: The Beginning of the End**\n\nGround Zero of our Nuclear Nerd's Origin Story, Chapter #00, The Beginning of the End, takes us from the streets of Colorado Springs to deep inside Cheyenne Mountain, home to the North American Aerospace Defense Command and the world's most dangerous “launch” button. Thanks to Airman Norm and one exceptionally juicy cheesesteak, suffice it to say, things do not turn out well for humanity.\n\n[Read Series 0](http://nuclearnerds.mypinata.cloud/ipfs/QmWSB4VL7gri6iRGCx1WHSGAanZP3ogfFyQnVPVhh5rswm)\n\n
Arg [3] : _seriesZeroHash (string): QmVNLEZsmdDFDWA8ugF5Rm7DZZyRu57f22a3dEjZyKMW9j
Arg [4] : _collectionDescription (string): There are 8,999 Nuclear Nerds Comic Tokens, each upgradable to the latest Comic issue during that issue's upgrade window. Doing so will change the display art of the Comic token to the cover art of that issue. Once upgraded, a Comic token cannot go backwards to a previous issue. Remember: the initial air-drop of the Comic token is attached to that token's 'parent' Nerd. If you sell your Nerd without 'unpairing' your Comic, your Comic token will be sold with your Nerd.\n\n
Arg [5] : _wildcardDescription (string): This Comic token possesses the Schrodinger Mystery Trait and can be redeemed for the Physical Anthology at the end of Season 1. It also gives the holder immediate access to 12 additional Story Votes.\n\n
Arg [6] : _redeemedDescription (string): This Comic token has been redeemed for a Physical Anthology and cannot be reused in that capacity. For more information view properties.
Arg [7] : _nerds (address): 0x0F78C6eEE3C89Ff37fD9ef96bD685830993636F2
Arg [8] : _royaltyReceiver (address): 0xefC83375b4Bf4e9011a8bc716bdAAdA4e043e90d
Arg [9] : _contractURIHash (string): QmWiWsg6jp6MpvXkTKgCgco81kZ8FTJSczfbS6BJh24itS

-----Encoded View---------------
69 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [2] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000420
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000480
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000680
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000780
Arg [7] : 0000000000000000000000000f78c6eee3c89ff37fd9ef96bd685830993636f2
Arg [8] : 000000000000000000000000efc83375b4bf4e9011a8bc716bdaada4e043e90d
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000840
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000013
Arg [11] : 4e75636c656172204e6572647320436f6d696300000000000000000000000000
Arg [12] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [13] : 4e45524453434f4d494300000000000000000000000000000000000000000000
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000227
Arg [15] : 2a2a43484150544552202330303a2054686520426567696e6e696e67206f6620
Arg [16] : 74686520456e642a2a5c6e5c6e47726f756e64205a65726f206f66206f757220
Arg [17] : 4e75636c656172204e6572642773204f726967696e2053746f72792c20436861
Arg [18] : 70746572202330302c2054686520426567696e6e696e67206f66207468652045
Arg [19] : 6e642c2074616b65732075732066726f6d207468652073747265657473206f66
Arg [20] : 20436f6c6f7261646f20537072696e677320746f206465657020696e73696465
Arg [21] : 2043686579656e6e65204d6f756e7461696e2c20686f6d6520746f2074686520
Arg [22] : 4e6f72746820416d65726963616e204165726f737061636520446566656e7365
Arg [23] : 20436f6d6d616e6420616e642074686520776f726c642773206d6f7374206461
Arg [24] : 6e6765726f757320e2809c6c61756e6368e2809d20627574746f6e2e20546861
Arg [25] : 6e6b7320746f204169726d616e204e6f726d20616e64206f6e65206578636570
Arg [26] : 74696f6e616c6c79206a7569637920636865657365737465616b2c2073756666
Arg [27] : 69636520697420746f207361792c207468696e677320646f206e6f7420747572
Arg [28] : 6e206f75742077656c6c20666f722068756d616e6974792e5c6e5c6e5b526561
Arg [29] : 642053657269657320305d28687474703a2f2f6e75636c6561726e657264732e
Arg [30] : 6d7970696e6174612e636c6f75642f697066732f516d57534234564c37677269
Arg [31] : 366952474378315748534741616e5a50336f67664679516e5650566868357273
Arg [32] : 776d295c6e5c6e00000000000000000000000000000000000000000000000000
Arg [33] : 000000000000000000000000000000000000000000000000000000000000002e
Arg [34] : 516d564e4c455a736d6444464457413875674635526d37445a5a795275353766
Arg [35] : 3232613364456a5a794b4d57396a000000000000000000000000000000000000
Arg [36] : 00000000000000000000000000000000000000000000000000000000000001dc
Arg [37] : 54686572652061726520382c393939204e75636c656172204e6572647320436f
Arg [38] : 6d696320546f6b656e732c20656163682075706772616461626c6520746f2074
Arg [39] : 6865206c617465737420436f6d696320697373756520647572696e6720746861
Arg [40] : 74206973737565277320757067726164652077696e646f772e20446f696e6720
Arg [41] : 736f2077696c6c206368616e67652074686520646973706c617920617274206f
Arg [42] : 662074686520436f6d696320746f6b656e20746f2074686520636f7665722061
Arg [43] : 7274206f6620746861742069737375652e204f6e63652075706772616465642c
Arg [44] : 206120436f6d696320746f6b656e2063616e6e6f7420676f206261636b776172
Arg [45] : 647320746f20612070726576696f75732069737375652e2052656d656d626572
Arg [46] : 3a2074686520696e697469616c206169722d64726f70206f662074686520436f
Arg [47] : 6d696320746f6b656e20697320617474616368656420746f207468617420746f
Arg [48] : 6b656e27732027706172656e7427204e6572642e20496620796f752073656c6c
Arg [49] : 20796f7572204e65726420776974686f75742027756e70616972696e67272079
Arg [50] : 6f757220436f6d69632c20796f757220436f6d696320746f6b656e2077696c6c
Arg [51] : 20626520736f6c64207769746820796f7572204e6572642e5c6e5c6e00000000
Arg [52] : 00000000000000000000000000000000000000000000000000000000000000cb
Arg [53] : 5468697320436f6d696320746f6b656e20706f73736573736573207468652053
Arg [54] : 6368726f64696e676572204d79737465727920547261697420616e642063616e
Arg [55] : 2062652072656465656d656420666f722074686520506879736963616c20416e
Arg [56] : 74686f6c6f67792061742074686520656e64206f6620536561736f6e20312e20
Arg [57] : 497420616c736f2067697665732074686520686f6c64657220696d6d65646961
Arg [58] : 74652061636365737320746f203132206164646974696f6e616c2053746f7279
Arg [59] : 20566f7465732e5c6e5c6e000000000000000000000000000000000000000000
Arg [60] : 0000000000000000000000000000000000000000000000000000000000000088
Arg [61] : 5468697320436f6d696320746f6b656e20686173206265656e2072656465656d
Arg [62] : 656420666f72206120506879736963616c20416e74686f6c6f677920616e6420
Arg [63] : 63616e6e6f742062652072657573656420696e20746861742063617061636974
Arg [64] : 792e20466f72206d6f726520696e666f726d6174696f6e20766965772070726f
Arg [65] : 706572746965732e000000000000000000000000000000000000000000000000
Arg [66] : 000000000000000000000000000000000000000000000000000000000000002e
Arg [67] : 516d5769577367366a70364d7076586b544b674367636f38316b5a3846544a53
Arg [68] : 637a66625336424a683234697453000000000000000000000000000000000000


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.