Contract 0x19B436638d31bF38Ba33924e6e25f8ce2a764a52 1

 
 
Txn Hash
Method
Block
From
To
Value
0x40f5b25f7c4bcd32101f29544924a121ba3b54c193fe5e919cca6970bf653d31Set Approval For...165515742023-02-03 23:34:4759 mins ago0x7700c4a6ef133eae29f35a06003fd208707d04c0 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00112359 24.36813562
0xc448969f5f3b8a1fab76cc6e7d1be6470f5609b72187706da9f660d5bf6ad9c3Set Approval For...165430602023-02-02 19:00:111 day 5 hrs ago0x6f87b2abd34d3bf861389cc1e775656d664cb1b6 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00104343 43.12230488
0x36e33d31a1fa87c208416d5c1c52d701a307e33ea6dd9fe4010e88452ff0db5fSet Approval For...165430372023-02-02 18:55:351 day 5 hrs ago0x172473fd3233e77c06579cc9173850edd57a139c IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00180697 39.189272
0x5aa9b695cf2ad84914938fd9a589c43e5dcbe9aa93e9119401dbd3a233736a0cSet Approval For...165430022023-02-02 18:48:231 day 5 hrs ago0x6f87b2abd34d3bf861389cc1e775656d664cb1b6 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00216877 47.03589579
0x9ec2980055ae880db062115ddb636215ea204845ff3c5b1d2b0a914b72f9d032Set Approval For...165376632023-02-02 0:52:111 day 23 hrs ago0x56a6ff5eca020a8ffc67fe7682887ccae12ac2d3 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.0019788 42.89350866
0xb89aa2c91ed985353fa2e3d439dddaf426723bce410c658fb24fdcbcd8f00610Set Approval For...165151172023-01-29 21:19:235 days 3 hrs agoENS Name mindfool.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00092026 19.95845479
0xdf32276c66c20dc6ac3ceafe0b0ded3d262e1bfc10a79f5c083da4872d1b059aSet Approval For...165128002023-01-29 13:33:115 days 11 hrs ago0x697feec3ad6eadd6c2444507d81b56d787cbc637 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00074139 16.07927607
0x507c87106c69938003dce802fd7f21106375ef17960d5ce2c72825d758d91903Set Approval For...165090312023-01-29 0:55:115 days 23 hrs agoENS Name bromano.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00153973 33.37600586
0x4c5725d77fb8988bd5a57f0d307eac819fc2c0d06dbdad0c259f9b5a96680128Set Approval For...165017422023-01-28 0:31:117 days 2 mins ago0x8de9f7e78fb5beea2ad6e3a333ba4f0669d9c594 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00048349 19.98156563
0x75485a0f0666d0b1ea10db40ab711491fb14726e64da899734361607a6ca31aeSet Approval For...165017422023-01-28 0:31:117 days 2 mins ago0x8de9f7e78fb5beea2ad6e3a333ba4f0669d9c594 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00048517 19.98156563
0x5926aa9e077436592da55f8d6d19b009101c7542f78008b74abc1e8ab5438625Set Approval For...165017422023-01-28 0:31:117 days 2 mins ago0x8de9f7e78fb5beea2ad6e3a333ba4f0669d9c594 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00048517 19.98156563
0x65f6aff9bdde6184584141ab2da5d7ae370497bfa8c6a43696c668871fc0d41eSet Approval For...164968112023-01-27 7:58:597 days 16 hrs agoENS Name redlxix.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00036766 15.1420842
0x254cf27f0154817637cfd6da23a6d96f0bf72c16bedf480f4f6e5c93090c838eSet Approval For...164968102023-01-27 7:58:477 days 16 hrs agoENS Name redlxix.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00036649 15.14626132
0xeaf97ca208b78d06bb230660080c2a6b1e0ec1d8ee04b9eaa5678ef780daba8cSet Approval For...164964562023-01-27 6:46:237 days 17 hrs ago0xa3d998b61e214f5a1963ef52a19706a3a2a136db IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00077325 16.77007618
0x76d631675ce541eadbe5c33b31bc5bd99506df3af4c01a8702699569e1c71a38Set Approval For...164924472023-01-26 17:20:598 days 7 hrs agoENS Name hakai.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.0012399 26.89074586
0x37dc42ce2d90a9675fa57fb123b502f3d01140226545ee146aca43dafc999c59Set Approval For...164887502023-01-26 4:57:478 days 19 hrs ago0x8c26cc23c671be30c6f701417fbc153b6998ff68 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00073007 15.83363203
0x882093f7dded85d6c3987dd1c02039c15c1d6d2a2c259bc4686f4406079b3ac0Set Approval For...164869062023-01-25 22:46:359 days 1 hr ago0x6024323da4fc4de706c6df9630a6d2ab063fc0cd IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00121273 26.25360575
0x9327cbb4e02efb5c238f68b6388e66f8cd4ae770a0ff87552168d6d8b971b405Set Approval For...164823802023-01-25 7:35:359 days 16 hrs agoENS Name dogestonks.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00066618 14.44798533
0x0cf9892a6b93e01b78c96d7f9800ca8b892b50052790bb9735714409786299b6Set Approval For...164805652023-01-25 1:30:479 days 23 hrs ago0x67cf27f419d0e4541dfd8456bc62234d590dbe9d IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.0011835 25.66751912
0x039aef5c60798889d78e4b6d65e6b235cec41738fcf9db972a00b1cf7bd022cbSet Approval For...164789682023-01-24 20:10:4710 days 4 hrs agoENS Name travsvault.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00128801 27.93422678
0xbc76226120aae2770644e052688be40967b82ba822bd3ee51685fd854f3a6f7bSet Approval For...164781732023-01-24 17:30:2310 days 7 hrs agoENS Name benjammin.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00129043 27.98661472
0x8e0c5b4aef13c4386dd5fabbd21d5c4669dc0efbcee8ee4f69f79204c5e44c44Set Approval For...164781722023-01-24 17:30:1110 days 7 hrs agoENS Name benjammin.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00121661 26.37187381
0x1afd21cad51f46194c3d2129855f43a4fddf154a798299a200c3ca5a39d5617cSet Approval For...164749492023-01-24 6:42:2310 days 17 hrs ago0x6ba122da33ae38e0e9cf15b7a3cb126abf47bae2 IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00074919 16.23985148
0x7c3906ebbda1916a91654c31b913ebb1c260cc5174ff56a8a3b8ad19efe44aebSet Approval For...164746242023-01-24 5:36:5910 days 18 hrs agoENS Name 0xezrai.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00035944 14.85493688
0x653595ae54e8e170845251046596adf8a74ab77963e32e43fa993cd1e3025c80Set Approval For...164705822023-01-23 16:04:3511 days 8 hrs agoENS Name adege.eth IN  0x19b436638d31bf38ba33924e6e25f8ce2a764a520 Ether0.00047503 19.6319898
[ Download CSV Export 
Latest 1 internal transaction
Parent Txn Hash Block From To Value
0xf84480e50281b16bc62d2ad5948208f179b66d09020e94cad6fe2e006208edf0156353302022-09-29 0:10:23128 days 23 mins ago 0x19b436638d31bf38ba33924e6e25f8ce2a764a520x4a5ab7a444f92254123bdaedbefec6a2218b22c0281.84 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NFT721

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 10000 runs

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

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

import '../EthereumContracts/contracts/interfaces/IERC165.sol';
import '../EthereumContracts/contracts/interfaces/IERC721.sol';
import '../EthereumContracts/contracts/interfaces/IERC721Metadata.sol';
import '../EthereumContracts/contracts/interfaces/IERC721Enumerable.sol';
import '../EthereumContracts/contracts/interfaces/IERC721Receiver.sol';
import '../EthereumContracts/contracts/interfaces/IERC2981.sol';
import '../EthereumContracts/contracts/utils/IOwnable.sol';
import '../EthereumContracts/contracts/utils/IPausable.sol';
import '../EthereumContracts/contracts/utils/ITradable.sol';
import '../EthereumContracts/contracts/utils/IWhitelistable_ECDSA.sol';
import '../EthereumContracts/contracts/utils/ERC2981Base.sol';

contract NFT721 is IERC721, IERC721Metadata, IERC721Enumerable, ERC2981Base, IOwnable, IPausable, ITradable, IWhitelistable_ECDSA, IERC165 {
  // **************************************
  // *****           ERRORS           *****
  // **************************************
    /**
    * @dev Thrown when two related arrays have different lengths
    */
    error ARRAY_LENGTH_MISMATCH();
    /**
    * @dev Thrown when contract fails to send ether to recipient.
    * 
    * @param to     : the recipient of the ether
    * @param amount : the amount of ether being sent
    */
    error ETHER_TRANSFER_FAIL( address to, uint256 amount );
    /**
    * @dev Thrown when `operator` has not been approved to manage `tokenId` on behalf of `tokenOwner`.
    * 
    * @param tokenOwner : address owning the token
    * @param operator   : address trying to manage the token
    * @param tokenId    : identifier of the NFT being referenced
    */
    error IERC721_CALLER_NOT_APPROVED( address tokenOwner, address operator, uint256 tokenId );
    /**
    * @dev Thrown when `operator` tries to approve themselves for managing a token they own.
    * 
    * @param operator : address that is trying to approve themselves
    */
    error IERC721_INVALID_APPROVAL( address operator );
    /**
    * @dev Thrown when a token is being transferred to the zero address.
    */
    error IERC721_INVALID_TRANSFER();
    /**
    * @dev Thrown when a token is being transferred from an address that doesn't own it.
    * 
    * @param tokenOwner : address owning the token
    * @param from       : address that the NFT is being transferred from
    * @param tokenId    : identifier of the NFT being referenced
    */
    error IERC721_INVALID_TRANSFER_FROM( address tokenOwner, address from, uint256 tokenId );
    /**
    * @dev Thrown when the requested token doesn't exist.
    * 
    * @param tokenId : identifier of the NFT being referenced
    */
    error IERC721_NONEXISTANT_TOKEN( uint256 tokenId );
    /**
    * @dev Thrown when a token is being safely transferred to a contract unable to handle it.
    * 
    * @param receiver : address unable to receive the token
    */
    error IERC721_NON_ERC721_RECEIVER( address receiver );
    /**
    * @dev Thrown when trying to get the token at an index that doesn't exist.
    * 
    * @param index : the inexistant index
    */
    error IERC721Enumerable_INDEX_OUT_OF_BOUNDS( uint256 index );
    /**
    * @dev Thrown when trying to get the token owned by `tokenOwner` at an index that doesn't exist.
    * 
    * @param tokenOwner : address owning the token
    * @param index      : the inexistant index
    */
    error IERC721Enumerable_OWNER_INDEX_OUT_OF_BOUNDS( address tokenOwner, uint256 index );
    /**
    * @dev Thrown when an incorrect amount of eth is being sent for a payable operation.
    * 
    * @param amountReceived : the amount the contract received
    * @param amountExpected : the actual amount the contract expected to receive
    */
    error INCORRECT_PRICE( uint256 amountReceived, uint256 amountExpected );
    /**
    * @dev Thrown when trying to mint 0 token.
    */
    error NFT_INVALID_QTY();
    /**
    * @dev Thrown when trying to mint more tokens than the max allowed per transaction.
    * 
    * @param qtyRequested : the amount of tokens requested
    * @param maxBatch     : the maximum amount that can be minted per transaction
    */
    error NFT_MAX_BATCH( uint256 qtyRequested, uint256 maxBatch );
    /**
    * @dev Thrown when trying to mint more tokens from the reserve than the amount left.
    * 
    * @param qtyRequested : the amount of tokens requested
    * @param reserveLeft  : the amount of tokens left in the reserve
    */
    error NFT_MAX_RESERVE( uint256 qtyRequested, uint256 reserveLeft );
    /**
    * @dev Thrown when trying to mint more tokens than the amount left to be minted (except reserve).
    * 
    * @param qtyRequested    : the amount of tokens requested
    * @param remainingSupply : the amount of tokens left in the reserve
    */
    error NFT_MAX_SUPPLY( uint256 qtyRequested, uint256 remainingSupply );
    /**
    * @dev Thrown when trying to withdraw from the contract with no balance.
    */
    error NO_ETHER_BALANCE();
  // **************************************

  /**
  * @dev A structure representing the deployment configuration of the contract.
  * It contains several pieces of information:
  * - reserve          : The amount of tokens that are reserved for airdrops
  * - maxBatch         : The maximum amount of tokens that can be minted in one transaction (for public sale)
  * - maxSupply        : The maximum amount of tokens that can be minted
  * - publicSalePrice  : The price of the tokens during public sale
  * - privateSalePrice : The price of the tokens during private sale
  * - treasury         : The address that will receive the proceeds of the mint
  * - name             : The name of the tokens, for token trackers (i.e. 'Cool Cats')
  * - symbol           : The symbol of the tokens, for token trackers (i.e. 'COOL')
  */
  struct Config {
    uint256 maxBatch;
    uint256 maxSupply;
    uint256 publicSalePrice;
    uint256 privateSalePrice;
    string  name;
    string  symbol;
  }

  // Constants
  uint8   public constant PUBLIC_SALE   = 1;
  uint8   public constant PRIVATE_SALE  = 2;
  uint8   public constant WAITLIST_SALE = 3;
  uint8   public constant CLAIM         = 4;

  uint256 private _nextId = 1;
  uint256 private _reserve;
  string  private _baseURI;
  Config  private _config;
  address private _treasury;

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

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

  // List of owner addresses
  mapping( uint256 => address ) private _owners;

  constructor(
    uint256 maxSupply_,
    uint256 maxBatch_,
    uint256 reserve_,
    uint256 salePrice_,
    uint256 royaltyRate_,
    address treasury_,
    string memory name_,
    string memory symbol_
  ) {
    _config = Config(
      maxBatch_,
      maxSupply_,
      salePrice_,
      salePrice_,
      name_,
      symbol_
    );
    _reserve = reserve_;
    _treasury = treasury_;
    _setRoyaltyInfo( treasury_, royaltyRate_ );
    _initIOwnable( msg.sender );
  }

  // **************************************
  // *****          MODIFIER          *****
  // **************************************
    /**
    * @dev Ensures the token exist. 
    * A token exists if it has been minted and is not owned by the null address.
    * 
    * @param tokenId_ : identifier of the NFT being referenced
    */
    modifier exists( uint256 tokenId_ ) {
      if ( ! _exists( tokenId_ ) ) {
        revert IERC721_NONEXISTANT_TOKEN( tokenId_ );
      }
      _;
    }

    /**
    * @dev Ensures that `qty_` is higher than 0
    * 
    * @param qty_ : the amount to validate 
    */
    modifier validateAmount( uint256 qty_ ) {
      if ( qty_ == 0 ) {
        revert NFT_INVALID_QTY();
      }
      _;
    }

    /**
    * @dev Ensures that contract state is `{PRIVATE_SALE}` or `{WAITLIST_SALE}`.
    */
    modifier isPrivateOrWaitlist() {
      uint8 _currentState_ = getPauseState();
      if ( _currentState_ != PRIVATE_SALE && _currentState_ != WAITLIST_SALE ) {
        revert IPausable_INCORRECT_STATE( PRIVATE_SALE );
      }
      _;
    }
  // **************************************

  // **************************************
  // *****          INTERNAL          *****
  // **************************************
    /**
    * @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 owning the token being transferred
    * @param to_      : address the token is being transferred to
    * @param tokenId_ : identifier of the NFT being referenced
    * @param data_    : 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 ) {
      // This method relies on extcodesize, which returns 0 for contracts in
      // construction, since the code is only stored at the end of the
      // constructor execution.
      // 
      // IMPORTANT
      // It is unsafe to assume that an address not flagged by this method
      // is an externally-owned account (EOA) and not a contract.
      //
      // Among others, the following types of addresses will not be flagged:
      //
      //  - 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
      uint256 _size_;
      assembly {
        _size_ := extcodesize( to_ )
      }

      // If address is a contract, check that it is aware of how to handle ERC721 tokens
      if ( _size_ > 0 ) {
        try IERC721Receiver( to_ ).onERC721Received( msg.sender, from_, tokenId_, data_ ) returns ( bytes4 retval ) {
          return retval == IERC721Receiver.onERC721Received.selector;
        }
        catch ( bytes memory reason ) {
          if ( reason.length == 0 ) {
            revert IERC721_NON_ERC721_RECEIVER( to_ );
          }
          else {
            assembly {
              revert( add( 32, reason ), mload( reason ) )
            }
          }
        }
      }
      else {
        return true;
      }
    }

    /**
    * @dev Internal function returning whether a token exists. 
    * A token exists if it has been minted and is not owned by the null address.
    * 
    * Note: this function must be overriden if tokens are burnable.
    * 
    * @param tokenId_ : identifier of the NFT being referenced
    * 
    * @return bool : whether the token exists
    */
    function _exists( uint256 tokenId_ ) internal view returns ( bool ) {
      if ( tokenId_ == 0 ) {
        return false;
      }
      return tokenId_ < _nextId;
    }

    /**
    * @dev Internal function returning whether `operator_` is allowed 
    * to manage tokens on behalf of `tokenOwner_`.
    * 
    * @param tokenOwner_ : address that owns tokens
    * @param operator_   : address that tries to manage tokens
    * 
    * @return bool : whether `operator_` is allowed to manage the tokens
    */
    function _isApprovedForAll( address tokenOwner_, address operator_ ) internal view returns ( bool ) {
      return _isRegisteredProxy( tokenOwner_, operator_ ) ||
             _operatorApprovals[ tokenOwner_ ][ operator_ ];
    }

    /**
    * @dev Internal function returning whether `operator_` is allowed to handle `tokenId_`
    * 
    * Note: To avoid multiple checks for the same data, it is assumed 
    * that existence of `tokenId_` has been verified prior via {_exists}
    * If it hasn't been verified, this function might panic
    * 
    * @param operator_ : address that tries to handle the token
    * @param tokenId_  : identifier of the NFT being referenced
    * 
    * @return bool : whether `operator_` is allowed to manage the token
    */
    function _isApprovedOrOwner( address tokenOwner_, address operator_, uint256 tokenId_ ) internal view returns ( bool ) {
      bool _isApproved_ = operator_ == tokenOwner_ ||
                          operator_ == getApproved( tokenId_ ) ||
                          isApprovedForAll( tokenOwner_, operator_ );
      return _isApproved_;
    }

    /**
    * @dev Mints `qty_` tokens and transfers them to `to_`.
    * 
    * This internal function can be used to perform token minting.
    * 
    * @param to_  : address receiving the tokens
    * @param qty_ : the amount of tokens to be minted
    * 
    * Emits one or more {Transfer} event.
    */
    function _mint( address to_, uint256 qty_ ) internal {
      uint256 _firstToken_ = _nextId;
      uint256 _nextStart_ = _firstToken_ + qty_;
      uint256 _lastToken_ = _nextStart_ - 1;

      _owners[ _firstToken_ ] = to_;
      if ( _lastToken_ > _firstToken_ ) {
        _owners[ _lastToken_ ] = to_;
      }
      _nextId = _nextStart_;

      for ( uint256 i = _firstToken_; i < _nextStart_; ++i ) {
        emit Transfer( address( 0 ), to_, i );
      }
    }

    /**
    * @dev Internal function returning the owner of the `tokenId_` token.
    * 
    * @param tokenId_ : identifier of the NFT being referenced
    * 
    * @return address the address of the token owner
    */
    function _ownerOf( uint256 tokenId_ ) internal view returns ( address ) {
      uint256 _index_ = tokenId_;
      address _tokenOwner_ = _owners[ _index_ ];
      while ( _tokenOwner_ == address( 0 ) ) {
        _index_ --;
        _tokenOwner_ = _owners[ _index_ ];
      }

      return _tokenOwner_;
    }

    /**
    * @dev Internal function returning the total supply.
    * 
    * Note: this function must be overriden if tokens are burnable.
    */
    function _totalSupply() internal view returns ( uint256 ) {
      return supplyMinted();
    }

    /**
    * @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 Transfers `tokenId_` from `from_` to `to_`.
    *
    * This internal function can be used to implement alternative mechanisms to perform 
    * token transfer, such as signature-based, or token burning.
    * 
    * @param from_    : the current owner of the NFT
    * @param to_      : the new owner
    * @param tokenId_ : identifier of the NFT being referenced
    * 
    * Emits a {Transfer} event.
    */
    function _transfer( address from_, address to_, uint256 tokenId_ ) internal {
      _approvals[ tokenId_ ] = address( 0 );
      uint256 _previousId_ = tokenId_ > 1 ? tokenId_ - 1 : 1;
      uint256 _nextId_     = tokenId_ + 1;
      bool _previousShouldUpdate_ = _previousId_ < tokenId_ &&
                                    _exists( _previousId_ ) &&
                                    _owners[ _previousId_ ] == address( 0 );
      bool _nextShouldUpdate_ = _exists( _nextId_ ) &&
                                _owners[ _nextId_ ] == address( 0 );

      if ( _previousShouldUpdate_ ) {
        _owners[ _previousId_ ] = from_;
      }

      if ( _nextShouldUpdate_ ) {
        _owners[ _nextId_ ] = from_;
      }

      _owners[ tokenId_ ] = to_;

      emit Transfer( from_, to_, tokenId_ );
    }
  // **************************************

  // **************************************
  // *****           PUBLIC           *****
  // **************************************
    /**
    * @notice Mints `qty_` tokens and transfers them to the caller.
    * 
    * @param qty_           : the amount of tokens to be minted
    * @param alloted_       : the maximum alloted for that user
    * @param proof_         : the signature to verify whitelist allocation
    * 
    * Requirements:
    * 
    * - Sale state must be {PRIVATE_SALE}.
    * - Caller must send enough ether to pay for `qty_` tokens at private sale price.
    */
    function mintPrivate( uint256 qty_, uint256 alloted_, Proof memory proof_ ) public payable validateAmount( qty_ ) isPrivateOrWaitlist isWhitelisted( msg.sender, PRIVATE_SALE, alloted_, proof_, qty_ ) {
      uint256 _remainingSupply_ = _config.maxSupply - _reserve - supplyMinted();
      if ( qty_ > _remainingSupply_ ) {
        revert NFT_MAX_SUPPLY( qty_, _remainingSupply_ );
      }

      uint256 _expected_ = qty_ * _config.privateSalePrice;
      if ( _expected_ != msg.value ) {
        revert INCORRECT_PRICE( msg.value, _expected_ );
      }

      _consumeWhitelist( msg.sender, PRIVATE_SALE, qty_ );
      _mint( msg.sender, qty_ );
    }

    /**
    * @notice Mints `qty_` tokens and transfers them to the caller.
    * 
    * @param qty_           : the amount of tokens to be minted
    * @param alloted_       : the maximum alloted for that user
    * @param proof_         : the signature to verify whitelist allocation
    * 
    * Requirements:
    * 
    * - Sale state must be {WAITLIST_SALE}.
    * - Caller must send enough ether to pay for `qty_` tokens at private sale price.
    */
    function mintWaitlist( uint256 qty_, uint256 alloted_, Proof memory proof_ ) public payable validateAmount( qty_ ) isState( WAITLIST_SALE ) isWhitelisted( msg.sender, WAITLIST_SALE, alloted_, proof_, qty_ ) {
      uint256 _remainingSupply_ = _config.maxSupply - _reserve - supplyMinted();
      if ( qty_ > _remainingSupply_ ) {
        revert NFT_MAX_SUPPLY( qty_, _remainingSupply_ );
      }

      uint256 _expected_ = qty_ * _config.privateSalePrice;
      if ( _expected_ != msg.value ) {
        revert INCORRECT_PRICE( msg.value, _expected_ );
      }

      _consumeWhitelist( msg.sender, WAITLIST_SALE, qty_ );
      _mint( msg.sender, qty_ );
    }

    /**
    * @notice Mints `qty_` tokens and transfers them to the caller.
    * 
    * @param qty_           : the amount of tokens to be minted
    * @param alloted_       : the maximum alloted for that user
    * @param proof_         : the signature to verify whitelist allocation
    * 
    * - Sale state must not be {PAUSED}.
    * - Caller must send enough ether to pay for `qty_` tokens at private sale price.
    */
    function claimDualSouls( uint256 qty_, uint256 alloted_, Proof memory proof_ ) public payable validateAmount( qty_ ) isPrivateOrWaitlist isWhitelisted( msg.sender, CLAIM, alloted_, proof_, qty_ ) {
      uint256 _remainingSupply_ = _config.maxSupply - _reserve - supplyMinted();
      if ( qty_ > _remainingSupply_ ) {
        revert NFT_MAX_SUPPLY( qty_, _remainingSupply_ );
      }

      uint256 _expected_ = qty_ * _config.privateSalePrice;
      if ( _expected_ != msg.value ) {
        revert INCORRECT_PRICE( msg.value, _expected_ );
      }

      _consumeWhitelist( msg.sender, CLAIM, qty_ );
      _mint( msg.sender, qty_ );
    }

    /**
    * @notice Mints `qty_` tokens and transfers them to the caller.
    * 
    * @param qty_ : the amount of tokens to be minted
    * 
    * Requirements:
    * 
    * - Sale state must be {PUBLIC_SALE}.
    * - There must be enough tokens left to mint outside of the reserve.
    * - Caller must send enough ether to pay for `qty_` tokens at public sale price.
    */
    function mintPublic( uint256 qty_ ) public payable validateAmount( qty_ ) isState( PUBLIC_SALE ) {
      if ( qty_ > _config.maxBatch ) {
        revert NFT_MAX_BATCH( qty_, _config.maxBatch );
      }

      uint256 _remainingSupply_ = _config.maxSupply - _reserve - supplyMinted();
      if ( qty_ > _remainingSupply_ ) {
        revert NFT_MAX_SUPPLY( qty_, _remainingSupply_ );
      }

      uint256 _expected_ = qty_ * _config.publicSalePrice;
      if ( _expected_ != msg.value ) {
        revert INCORRECT_PRICE( msg.value, _expected_ );
      }

      _mint( msg.sender, qty_ );
    }

    // +---------+
    // | IERC721 |
    // +---------+
      /**
      * @notice Gives permission to `to_` to transfer the token number `tokenId_` on behalf of its owner.
      * 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.
      * 
      * @param to_      : The new approved NFT controller
      * @param tokenId_ : The NFT to approve
      * 
      * Requirements:
      * 
      * - The token number `tokenId_` must exist.
      * - The caller must own the token or be an approved operator.
      * - Must emit an {Approval} event.
      */
      function approve( address to_, uint256 tokenId_ ) public override exists( tokenId_ ) {
        address _operator_ = msg.sender;
        address _tokenOwner_ = _ownerOf( tokenId_ );
        if ( to_ == _tokenOwner_ ) {
          revert IERC721_INVALID_APPROVAL( to_ );
        }

        bool _isApproved_ = _isApprovedOrOwner( _tokenOwner_, _operator_, tokenId_ );
        if ( ! _isApproved_ ) {
          revert IERC721_CALLER_NOT_APPROVED( _tokenOwner_, _operator_, tokenId_ );
        }

        _approvals[ tokenId_ ] = to_;
        emit Approval( _tokenOwner_, to_, tokenId_ );
      }

      /**
      * @notice Transfers the token number `tokenId_` from `from_` to `to_`.
      * 
      * @param from_    : The current owner of the NFT
      * @param to_      : The new owner
      * @param tokenId_ : identifier of the NFT being referenced
      * 
      * Requirements:
      * 
      * - The token number `tokenId_` must exist.
      * - `from_` must be the token owner.
      * - The caller must own the token or be an approved operator.
      * - `to_` must not be the zero address.
      * - If `to_` is a contract, it must implement {IERC721Receiver-onERC721Received} with a return value of `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
      * - Must emit a {Transfer} event.
      */
      function safeTransferFrom( address from_, address to_, uint256 tokenId_ ) public override {
        safeTransferFrom( from_, to_, tokenId_, "" );
      }

      /**
      * @notice Transfers the token number `tokenId_` from `from_` to `to_`.
      * 
      * @param from_    : The current owner of the NFT
      * @param to_      : The new owner
      * @param tokenId_ : identifier of the NFT being referenced
      * @param data_    : Additional data with no specified format, sent in call to `to_`
      * 
      * Requirements:
      * 
      * - The token number `tokenId_` must exist.
      * - `from_` must be the token owner.
      * - The caller must own the token or be an approved operator.
      * - `to_` must not be the zero address.
      * - If `to_` is a contract, it must implement {IERC721Receiver-onERC721Received} with a return value of `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
      * - Must emit a {Transfer} event.
      */
      function safeTransferFrom( address from_, address to_, uint256 tokenId_, bytes memory data_ ) public override {
        transferFrom( from_, to_, tokenId_ );
        if ( ! _checkOnERC721Received( from_, to_, tokenId_, data_ ) ) {
          revert IERC721_NON_ERC721_RECEIVER( to_ );
        }
      }

      /**
      * @notice Allows or disallows `operator_` to manage the caller's tokens on their behalf.
      * 
      * @param operator_ : Address to add to the set of authorized operators
      * @param approved_ : True if the operator is approved, false to revoke approval
      * 
      * Requirements:
      * 
      * - Must emit an {ApprovalForAll} event.
      */
      function setApprovalForAll( address operator_, bool approved_ ) public override {
        address _account_ = msg.sender;
        if ( operator_ == _account_ ) {
          revert IERC721_INVALID_APPROVAL( operator_ );
        }

        _operatorApprovals[ _account_ ][ operator_ ] = approved_;
        emit ApprovalForAll( _account_, operator_, approved_ );
      }

      /**
      * @notice Transfers the token number `tokenId_` from `from_` to `to_`.
      * 
      * @param from_    : the current owner of the NFT
      * @param to_      : the new owner
      * @param tokenId_ : identifier of the NFT being referenced
      * 
      * Requirements:
      * 
      * - The token number `tokenId_` must exist.
      * - `from_` must be the token owner.
      * - The caller must own the token or be an approved operator.
      * - `to_` must not be the zero address.
      * - Must emit a {Transfer} event.
      */
      function transferFrom( address from_, address to_, uint256 tokenId_ ) public override exists( tokenId_ ) {
        if ( to_ == address( 0 ) ) {
          revert IERC721_INVALID_TRANSFER();
        }

        address _operator_ = msg.sender;
        address _tokenOwner_ = _ownerOf( tokenId_ );
        if ( from_ != _tokenOwner_ ) {
          revert IERC721_INVALID_TRANSFER_FROM( _tokenOwner_, from_, tokenId_ );
        }

        bool _isApproved_ = _isApprovedOrOwner( _tokenOwner_, _operator_, tokenId_ );
        if ( ! _isApproved_ ) {
          revert IERC721_CALLER_NOT_APPROVED( _tokenOwner_, _operator_, tokenId_ );
        }

        _transfer( _tokenOwner_, to_, tokenId_ );
      }
    // +---------+
  // **************************************

  // **************************************
  // *****       CONTRACT_OWNER       *****
  // **************************************
    /**
    * @dev Adds a proxy registry to the list of accepted proxy registries.
    * 
    * @param proxyRegistryAddress_ : the address of the proxy registry to be added
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    */
    function addProxyRegistry( address proxyRegistryAddress_ ) external onlyOwner {
      _addProxyRegistry( proxyRegistryAddress_ );
    }

    /**
    * @notice Mints `amounts_` tokens and transfers them to `accounts_`.
    * 
    * @param accounts_ : the list of accounts that will receive airdropped tokens
    * @param amounts_  : the amount of tokens each account will receive
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    * - `accounts_` and `amounts_` must have the same length.
    * - There must be enough tokens left in the reserve.
    */
    function airdrop( address[] memory accounts_, uint256[] memory amounts_ ) public onlyOwner {
      uint256 _amountsLen_ = amounts_.length;
      if ( accounts_.length != _amountsLen_ ) {
        revert ARRAY_LENGTH_MISMATCH();
      }

      uint256 _totalQty_;
      for ( uint256 i = _amountsLen_; i > 0; i -- ) {
        _totalQty_ += amounts_[ i - 1 ];
      }
      if ( _totalQty_ > _reserve ) {
        revert NFT_MAX_RESERVE( _totalQty_, _reserve );
      }
      unchecked {
        _reserve -= _totalQty_;
      }

      uint256 _count_ = _amountsLen_;
      while ( _count_ > 0 ) {
        unchecked {
          _count_ --;
        }
        _mint( accounts_[ _count_ ], amounts_[ _count_ ] );
      }
    }

    /**
    * @dev Removes a proxy registry from the list of accepted proxy registries.
    * 
    * @param proxyRegistryAddress_ : the address of the proxy registry to be removed
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    */
    function removeProxyRegistry( address proxyRegistryAddress_ ) external onlyOwner {
      _removeProxyRegistry( proxyRegistryAddress_ );
    }

    /**
    * @notice Updates the baseURI for the tokens.
    * 
    * @param baseURI_ : the new baseURI for the tokens
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    */
    function setBaseURI( string memory baseURI_ ) public onlyOwner {
      _baseURI = baseURI_;
    }

    /**
    * @notice Updates the contract state.
    * 
    * @param newState_ : the new sale state
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    * - `newState_` must be a valid state.
    */
    function setPauseState( uint8 newState_ ) external onlyOwner {
      if ( newState_ > CLAIM ) {
        revert IPausable_INVALID_STATE( newState_ );
      }
      _setPauseState( newState_ );
    }

    /**
    * @notice Updates the prices.
    * 
    * Note: We shouldn't need to use this function, but just in case.
    * 
    * @param publicSalePrice_  : the new public sale price
    * @param privateSalePrice_ : the new private sale price
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    */
    function setPrice( uint256 publicSalePrice_, uint256 privateSalePrice_ ) external onlyOwner {
      _config.publicSalePrice = publicSalePrice_;
      _config.privateSalePrice = privateSalePrice_;
    }

    /**
    * @notice Updates the royalty recipient and rate.
    * 
    * @param royaltyRecipient_ : the new recipient of the royalties
    * @param royaltyRate_      : the new royalty rate
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    * - `royaltyRate_` cannot be higher than 10,000.
    */
    function setRoyaltyInfo( address royaltyRecipient_, uint256 royaltyRate_ ) external onlyOwner {
      _setRoyaltyInfo( royaltyRecipient_, royaltyRate_ );
    }

    /**
    * @notice Updates the contract treasury.
    * 
    * @param newTreasury_ : the new trasury
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    */
    function setTreasury( address newTreasury_ ) external onlyOwner {
      _treasury = newTreasury_;
    }

    /**
    * @notice Updates the whitelist signer.
    * 
    * @param adminSigner_ : the new whitelist signer
    *  
    * Requirements:
    * 
    * - Caller must be the contract owner.
    */
    function setWhitelist( address adminSigner_ ) external onlyOwner {
      _setWhitelist( adminSigner_ );
    }

    /**
    * @notice Withdraws all the money stored in the contract and sends it to the treasury.
    * 
    * Requirements:
    * 
    * - Caller must be the contract owner.
    * - Contract must have a positive balance.
    */
    function withdraw() public onlyOwner {
      uint256 _balance_ = address( this ).balance;
      if ( _balance_ == 0 ) {
        revert NO_ETHER_BALANCE();
      }

      address _recipient_ = payable( _treasury );
      ( bool _success_, ) = _recipient_.call{ value: _balance_ }( "" );
      if ( ! _success_ ) {
        revert ETHER_TRANSFER_FAIL( _recipient_, _balance_ );
      }
    }
  // **************************************

  // **************************************
  // *****            VIEW            *****
  // **************************************
    /**
    * @notice Returns the total number of tokens minted
    * 
    * @return uint256 the number of tokens that have been minted so far
    */
    function supplyMinted() public view returns ( uint256 ) {
      return _nextId - 1;
    }

	/**
	* @notice Called with the sale price to determine how much royalty is owed and to whom.
	* 
	* @param tokenId_   : identifier of the NFT being referenced
	* @param salePrice_ : the sale price of the token sold
	* 
	* @return address : the address receiving the royalties
	* @return uint256 : the royalty payment amount
	*/
	function royaltyInfo( uint256 tokenId_, uint256 salePrice_ ) public view virtual override exists( tokenId_ ) returns ( address, uint256 ) {
		return super.royaltyInfo( tokenId_, salePrice_ );
	}

    // +---------+
    // | IERC721 |
    // +---------+
      /**
      * @notice Returns the number of tokens in `tokenOwner_`'s account.
      * 
      * @param tokenOwner_ : address that owns tokens
      * 
      * @return uint256 : the nomber of tokens owned by `tokenOwner_`
      */
      function balanceOf( address tokenOwner_ ) public view override returns ( uint256 ) {
        if ( tokenOwner_ == address( 0 ) ) {
          return 0;
        }

        uint256 _count_ = 0;
        address _currentTokenOwner_;
        for ( uint256 i = 1; i < _nextId; ++ i ) {
          if ( _exists( i ) ) {
            if ( _owners[ i ] != address( 0 ) ) {
              _currentTokenOwner_ = _owners[ i ];
            }
            if ( tokenOwner_ == _currentTokenOwner_ ) {
              _count_++;
            }
          }
        }
        return _count_;
      }

      /**
      * @notice Returns the address that has been specifically allowed to manage `tokenId_` on behalf of its owner.
      * 
      * @param tokenId_ : the NFT that has been approved
      * 
      * @return address : the address allowed to manage `tokenId_`
      * 
      * Requirements:
      * 
      * - `tokenId_` must exist.
      * 
      * Note: See {Approve}
      */
      function getApproved( uint256 tokenId_ ) public view override exists( tokenId_ ) returns ( address ) {
        return _approvals[ tokenId_ ];
      }

      /**
      * @notice Returns whether `operator_` is allowed to manage tokens on behalf of `tokenOwner_`.
      * 
      * @param tokenOwner_ : address that owns tokens
      * @param operator_   : address that tries to manage tokens
      * 
      * @return bool : whether `operator_` is allowed to handle `tokenOwner`'s tokens
      * 
      * Note: See {setApprovalForAll}
      */
      function isApprovedForAll( address tokenOwner_, address operator_ ) public view override returns ( bool ) {
        return _operatorApprovals[ tokenOwner_ ][ operator_ ];
      }

      /**
      * @notice Returns the owner of the token number `tokenId_`.
      * 
      * @param tokenId_ : the NFT to verify ownership of
      * 
      * @return address : the owner of token number `tokenId_`
      * 
      * Requirements:
      * 
      * - `tokenId_` must exist.
      */
      function ownerOf( uint256 tokenId_ ) public view override exists( tokenId_ ) returns ( address ) {
        return _ownerOf( tokenId_ );
      }
    // +---------+

    // +-----------------+
    // | IERC721Metadata |
    // +-----------------+
      /**
      * @notice A descriptive name for a collection of NFTs in this contract.
      * 
      * @return string : The name of the collection
      */
      function name() public view override returns ( string memory ) {
        return _config.name;
      }

      /**
      * @notice An abbreviated name for NFTs in this contract.
      * 
      * @return string : The abbreviated name of the collection
      */
      function symbol() public view override returns ( string memory ) {
        return _config.symbol;
      }

      /**
      * @notice A distinct Uniform Resource Identifier (URI) for a given asset.
      * 
      * @param tokenId_ : the NFT that has been approved
      * 
      * @return string : the URI of the token
      * 
      * Requirements:
      * 
      * - `tokenId_` must exist.
      */
      function tokenURI( uint256 tokenId_ ) public view override exists( tokenId_ ) returns ( string memory ) {
        return bytes( _baseURI ).length > 0 ? string( abi.encodePacked( _baseURI, _toString( tokenId_ ) ) ) : _toString( tokenId_ );
      }
    // +---------+

    // +-------------------+
    // | IERC721Enumerable |
    // +-------------------+
      /**
      * @notice Enumerate valid NFTs.
      * 
      * @param index_ : a counter less than `totalSupply()`
      * 
      * @return uint256 : the token identifier of the `index_`th NFT
      * 
      * Requirements:
      * 
      * - `index_` must be lower than `totalSupply()`.
      */
      function tokenByIndex( uint256 index_ ) public view override returns ( uint256 ) {
        if ( index_ >= supplyMinted() ) {
          revert IERC721Enumerable_INDEX_OUT_OF_BOUNDS( index_ );
        }
        return index_;
      }

      /**
      * @notice Enumerate NFTs assigned to an owner.
      * 
      * @param tokenOwner_ : the address for which we want to know the tokens owned
      * @param index_      : a counter less than `balanceOf(tokenOwner_)`
      * 
      * @return tokenId : the token identifier of the `index_`th NFT
      * 
      * Requirements:
      * 
      * - `index_` must be lower than `balanceOf(tokenOwner_)`.
      */
      function tokenOfOwnerByIndex( address tokenOwner_, uint256 index_ ) public view override returns ( uint256 tokenId ) {
        if ( index_ >= balanceOf( tokenOwner_ ) ) {
          revert IERC721Enumerable_OWNER_INDEX_OUT_OF_BOUNDS( tokenOwner_, index_ );
        }

        uint256 _count_ = 0;
        for ( uint256 i = 1; i < _nextId; ++i ) {
          if ( _exists( i ) && tokenOwner_ == _ownerOf( i ) ) {
            if ( index_ == _count_ ) {
              return i;
            }
            unchecked {
              _count_++;
            }
          }
        }
      }

      /**
      * @notice Count NFTs tracked by this contract.
      * 
      * @return the total number of existing NFTs tracked by the contract
      */
      function totalSupply() public view override returns ( uint256 ) {
        return _totalSupply();
      }
    // +---------+

    // +---------+
    // | IERC165 |
    // +---------+
      /**
      * @notice Query if a contract implements an interface.
      * @dev see https://eips.ethereum.org/EIPS/eip-165
      * 
      * @param interfaceId_ : the interface identifier, as specified in ERC-165
      * 
      * @return bool : true if the contract implements the specified interface, false otherwise
      * 
      * Requirements:
      * 
      * - This function must use less than 30,000 gas.
      */
      function supportsInterface( bytes4 interfaceId_ ) public pure override returns ( bool ) {
        return 
          interfaceId_ == type( IERC721 ).interfaceId ||
          interfaceId_ == type( IERC721Enumerable ).interfaceId ||
          interfaceId_ == type( IERC721Metadata ).interfaceId ||
          interfaceId_ == type( IERC173 ).interfaceId ||
          interfaceId_ == type( IERC165 ).interfaceId ||
          interfaceId_ == type( IERC2981 ).interfaceId;
      }
    // +---------+
  // **************************************
}

File 2 of 13 : ERC2981Base.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

import "../interfaces/IERC2981.sol";

abstract contract ERC2981Base is IERC2981 {
	// Errors
	/**
	* @dev Thrown when the desired royalty rate is higher than 10,000
	* 
	* @param royaltyRate : the desired royalty rate
	* @param royaltyBase : the maximum royalty rate
	*/
	error IERC2981_INVALID_ROYALTIES( uint256 royaltyRate, uint256 royaltyBase );

	// Royalty rate is stored out of 10,000 instead of a percentage to allow for
	// up to two digits below the unit such as 2.5% or 1.25%.
	uint private constant ROYALTY_BASE = 10000;

	// Represents the percentage of royalties on each sale on secondary markets.
	// Set to 0 to have no royalties.
	uint256 private _royaltyRate;

	// Address of the recipient of the royalties.
	address private _royaltyRecipient;

	/**
	* @notice Called with the sale price to determine how much royalty is owed and to whom.
	* 
	* Note: This function should be overriden to revert on a query for non existent token.
	* 
	*  param tokenId_   : identifier of the NFT being referenced
	* @param salePrice_ : the sale price of the token sold
	* 
	* @return address : the address receiving the royalties
	* @return uint256 : the royalty payment amount
	*/
	function royaltyInfo( uint256 /* tokenId_ */, uint256 salePrice_ ) public view virtual override returns ( address, uint256 ) {
		if ( salePrice_ == 0 || _royaltyRate == 0 ) {
			return ( _royaltyRecipient, 0 );
		}
		uint256 _royaltyAmount_ = _royaltyRate * salePrice_ / ROYALTY_BASE;
		return ( _royaltyRecipient, _royaltyAmount_ );
	}

	/**
	* @dev Sets the royalty rate to `royaltyRate_` and the royalty recipient to `royaltyRecipient_`.
	* 
	* @param royaltyRecipient_ : the address that will receive royalty payments
	* @param royaltyRate_      : the percentage of the sale price that will be taken off as royalties, expressed in Basis Points (100 BP = 1%)
	* 
	* Requirements: 
	* 
	* - `royaltyRate_` cannot be higher than `10,000`;
	*/
	function _setRoyaltyInfo( address royaltyRecipient_, uint256 royaltyRate_ ) internal virtual {
		if ( royaltyRate_ > ROYALTY_BASE ) {
			revert IERC2981_INVALID_ROYALTIES( royaltyRate_, ROYALTY_BASE );
		}
		_royaltyRate      = royaltyRate_;
		_royaltyRecipient = royaltyRecipient_;
	}
}

File 3 of 13 : IWhitelistable_ECDSA.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
* Edit  : Squeebo
*/

pragma solidity 0.8.17;

abstract contract IWhitelistable_ECDSA {
	// Errors
  /**
  * @dev Thrown when trying to query the whitelist while it's not set
  */
	error IWhitelistable_NOT_SET();
  /**
  * @dev Thrown when `account` has consumed their alloted access and tries to query more
  * 
  * @param account : address trying to access the whitelist
  */
	error IWhitelistable_CONSUMED( address account );
  /**
  * @dev Thrown when `account` does not have enough alloted access to fulfil their query
  * 
  * @param account : address trying to access the whitelist
  */
	error IWhitelistable_FORBIDDEN( address account );

	/**
  * @dev A structure representing a signature proof to be decoded by the contract
  */
	struct Proof {
		bytes32 r;
		bytes32 s;
		uint8   v;
	}

	address private _adminSigner;
	mapping( uint8 => mapping ( address => uint256 ) ) private _consumed;

	/**
	* @dev Ensures that `account_` has `qty_` alloted access on the `whitelistId_` whitelist.
	* 
	* @param account_     : the address to validate access
	* @param whitelistId_ : the identifier of the whitelist being queried
	* @param alloted_     : the max amount of whitelist spots allocated
	* @param proof_       : the signature proof to validate whitelist allocation
	* @param qty_         : the amount of whitelist access requested
	*/
	modifier isWhitelisted( address account_, uint8 whitelistId_, uint256 alloted_, Proof memory proof_, uint256 qty_ ) {
		uint256 _allowed_ = checkWhitelistAllowance( account_, whitelistId_, alloted_, proof_ );

		if ( _allowed_ < qty_ ) {
			revert IWhitelistable_FORBIDDEN( account_ );
		}

		_;
	}

	/**
	* @dev Sets the pass to protect the whitelist.
	* 
	* @param adminSigner_ : the address validating the whitelist signatures
	*/
	function _setWhitelist( address adminSigner_ ) internal virtual {
		_adminSigner = adminSigner_;
	}

	/**
	* @dev Returns the amount that `account_` is allowed to access from the whitelist.
	* 
	* @param account_     : the address to validate access
	* @param whitelistId_ : the identifier of the whitelist being queried
	* @param alloted_     : the max amount of whitelist spots allocated
	* @param proof_       : the signature proof to validate whitelist allocation
	* 
	* @return uint256 : the total amount of whitelist allocation remaining for `account_`
	* 
	* Requirements:
	* 
	* - `_adminSigner` must be set.
	*/
	function checkWhitelistAllowance( address account_, uint8 whitelistId_, uint256 alloted_, Proof memory proof_ ) public view returns ( uint256 ) {
		if ( _adminSigner == address( 0 ) ) {
			revert IWhitelistable_NOT_SET();
		}

		if ( _consumed[ whitelistId_ ][ account_ ] >= alloted_ ) {
			revert IWhitelistable_CONSUMED( account_ );
		}

		if ( ! _validateProof( account_, whitelistId_, alloted_, proof_ ) ) {
			revert IWhitelistable_FORBIDDEN( account_ );
		}

		return alloted_ - _consumed[ whitelistId_ ][ account_ ];
	}

	/**
	* @dev Internal function to decode a signature and compare it with the `_adminSigner`.
	* 
	* @param account_     : the address to validate access
	* @param whitelistId_ : the identifier of the whitelist being queried
	* @param alloted_     : the max amount of whitelist spots allocated
	* @param proof_       : the signature proof to validate whitelist allocation
	* 
	* @return bool : whether the signature is valid or not
	*/ 
	function _validateProof( address account_, uint8 whitelistId_, uint256 alloted_, Proof memory proof_ ) private view returns ( bool ) {
		bytes32 _digest_ = keccak256( abi.encode( whitelistId_, alloted_, account_ ) );
		address _signer_ = ecrecover( _digest_, proof_.v, proof_.r, proof_.s );
		return _signer_ == _adminSigner;
	}

	/**
	* @dev Consumes `amount_` whitelist access passes from `account_`.
	* 
	* @param account_     : the address to consume access from
	* @param whitelistId_ : the identifier of the whitelist being queried
	* @param qty_         : the amount of whitelist access consumed
	* 
	* Note: Before calling this function, eligibility should be checked through {IWhitelistable-checkWhitelistAllowance}.
	*/
	function _consumeWhitelist( address account_, uint8 whitelistId_, uint256 qty_ ) internal {
		unchecked {
			_consumed[ whitelistId_ ][ account_ ] += qty_;
		}
	}
}

File 4 of 13 : ITradable.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

contract OwnableDelegateProxy {}

contract ProxyRegistry {
	mapping( address => OwnableDelegateProxy ) public proxies;
}

abstract contract ITradable {
	// list of accepted proxy registries
	address[] public proxyRegistries;

	/**
	* @dev Internal function that adds a proxy registry to the list of accepted proxy registries.
	* 
	* @param proxyRegistryAddress_ : the address of the new proxy registry
	*/
	function _addProxyRegistry( address proxyRegistryAddress_ ) internal {
		uint256 _index_ = proxyRegistries.length;
		while ( _index_ > 0 ) {
			unchecked {
				_index_ --;
			}
			if ( proxyRegistries[ _index_ ] == proxyRegistryAddress_ ) {
				return;
			}
		}
		proxyRegistries.push( proxyRegistryAddress_ );
	}

	/**
	* @dev Internal function that removes a proxy registry from the list of accepted proxy registries.
	* 
	* @param proxyRegistryAddress_ : the address of the proxy registry to remove
	*/
	function _removeProxyRegistry( address proxyRegistryAddress_ ) internal {
		uint256 _len_ = proxyRegistries.length;
		uint256 _index_ = _len_;
		while ( _index_ > 0 ) {
			unchecked {
				_index_ --;
			}
			if ( proxyRegistries[ _index_ ] == proxyRegistryAddress_ ) {
				if ( _index_ + 1 != _len_ ) {
					proxyRegistries[ _index_ ] = proxyRegistries[ _len_ - 1 ];
				}
				proxyRegistries.pop();
			}
			return;
		}
	}

	/**
	* @dev Internal function that checks if `operator_` is a registered proxy for `tokenOwner_`.
	* 
	* Note: Use this function to allow whitelisting of registered proxy.
	* 
	* @param tokenOwner_ : the address the proxy operates on the behalf of
	* @param operator_   : the proxy address that operates on behalf of the token owner
	* 
	* @return bool : whether `operator_` is allowed to operate on behalf of `tokenOwner_` or not
	*/
	function _isRegisteredProxy( address tokenOwner_, address operator_ ) internal view returns ( bool ) {
		uint256 _index_ = proxyRegistries.length;
		while ( _index_ > 0 ) {
			unchecked {
				_index_ --;
			}
			ProxyRegistry _proxyRegistry_ = ProxyRegistry( proxyRegistries[ _index_ ] );
			if ( address( _proxyRegistry_.proxies( tokenOwner_ ) ) == operator_ ) {
				return true;
			}
		}
		return false;
	}
}

File 5 of 13 : IPausable.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

abstract contract IPausable {
	// Enum to represent the sale state, defaults to ``PAUSED``.
	uint8 public constant PAUSED = 0;

	// Errors
	/**
	* @dev Thrown when a function is called with the wrong contract state.
	* 
	* @param currentState : the current state of the contract
	*/
	error IPausable_INCORRECT_STATE( uint8 currentState );
	/**
	* @dev Thrown when trying to set the contract state to an invalid value.
	* 
	* @param invalidState : the invalid contract state
	*/
	error IPausable_INVALID_STATE( uint8 invalidState );

	// The current state of the contract
	uint8 private _contractState;

	/**
	* @dev Emitted when the sale state changes
	*/
	event ContractStateChanged( uint8 indexed previousState, uint8 indexed newState );

	/**
	* @dev Ensures that contract state is `expectedState_`.
	* 
	* @param expectedState_ : the desirable contract state
	*/
	modifier isState( uint8 expectedState_ ) {
		if ( _contractState != expectedState_ ) {
			revert IPausable_INCORRECT_STATE( _contractState );
		}
		_;
	}

	/**
	* @dev Ensures that contract state is not `unexpectedState_`.
	* 
	* @param unexpectedState_ : the undesirable contract state
	*/
	modifier isNotState( uint8 unexpectedState_ ) {
		if ( _contractState == unexpectedState_ ) {
			revert IPausable_INCORRECT_STATE( _contractState );
		}
		_;
	}

	/**
	* @dev Internal function setting the contract state to `newState_`.
	* 
	* Note: Contract state defaults to ``PAUSED``.
	* 			To maintain extendability, this value kept as uint8 instead of enum.
	* 			As a result, it is possible to set the state to an incorrect value.
	* 			To avoid issues, `newState_` should be validated before calling this function
	*/
	function _setPauseState( uint8 newState_ ) internal virtual {
		uint8 _previousState_ = _contractState;
		_contractState = newState_;
		emit ContractStateChanged( _previousState_, newState_ );
	}

	/**
	* @dev Returns the current contract state.
	* 
	* @return uint8 : the current contract state
	*/
	function getPauseState() public virtual view returns ( uint8 ) {
		return _contractState;
	}
}

File 6 of 13 : IOwnable.sol
// SPDX-License-Identifier: MIT

/**
* Author: Lambdalf the White
*/

pragma solidity 0.8.17;

import "../interfaces/IERC173.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 IOwnable is IERC173 {
	// Errors
  /**
  * @dev Thrown when `operator` is not the contract owner.
  * 
  * @param operator : address trying to use a function reserved to contract owner without authorization
  */
  error IERC173_NOT_OWNER( address operator );

	// The owner of the contract
	address private _owner;

	/**
	* @dev Throws if called by any account other than the owner.
	*/
	modifier onlyOwner() {
		address _sender_ = msg.sender;
		if ( owner() != _sender_ ) {
			revert IERC173_NOT_OWNER( _sender_ );
		}
		_;
	}

	/**
	* @dev Initializes the contract setting `owner_` as the initial owner.
	* 
	* Note: This function needs to be called in the contract constructor to initialize the contract owner, 
	* if it is not, then parts of the contract might be non functional
	* 
	* @param owner_ : address that owns the contract
	*/
	function _initIOwnable( address owner_ ) internal {
		_owner = owner_;
	}

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

	/**
	* @dev Transfers ownership of the contract to `newOwner`.
	* 
	* @param newOwner_ : address of the new contract owner
	* 
	* Requirements:
	* 
  * - Caller must be the contract owner.
	*/
	function transferOwnership( address newOwner_ ) public virtual onlyOwner {
		address _oldOwner_ = _owner;
		_owner = newOwner_;
		emit OwnershipTransferred( _oldOwner_, newOwner_ );
	}
}

File 7 of 13 : IERC2981.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

///
/// @dev Interface for the NFT Royalty Standard
///
interface IERC2981 /* is IERC165 */ {
  /// ERC165 bytes to add to interface array - set in parent contract
  /// implementing this standard
  ///
  /// bytes4(keccak256("royaltyInfo(uint256,uint256)")) == 0x2a55205a
  /// bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
  /// _registerInterface(_INTERFACE_ID_ERC2981);

  /// @notice Called with the sale price to determine how much royalty
  //          is owed and to whom.
  /// @param tokenId_ - the NFT asset queried for royalty information
  /// @param salePrice_ - the sale price of the NFT asset specified by tokenId_
  /// @return receiver - address of who should be sent the royalty payment
  /// @return royaltyAmount - the royalty payment amount for salePrice_
  function royaltyInfo( uint256 tokenId_, uint256 salePrice_ ) external view returns ( address receiver, uint256 royaltyAmount );
}

File 8 of 13 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface IERC721Receiver {
    /// @notice Handle the receipt of an NFT
    /// @dev The ERC721 smart contract calls this function on the recipient
    ///  after a `transfer`. This function MAY throw to revert and reject the
    ///  transfer. Return of other than the magic value MUST result in the
    ///  transaction being reverted.
    ///  Note: the contract address is always the message sender.
    /// @param operator_ The address which called `safeTransferFrom` function
    /// @param from_ The address which previously owned the token
    /// @param tokenId_ The NFT identifier which is being transferred
    /// @param data_ Additional data with no specified format
    /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    ///  unless throwing
    function onERC721Received( address operator_, address from_, uint256 tokenId_, bytes calldata data_ ) external returns( bytes4 );
}

File 9 of 13 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x780e9d63.
interface IERC721Enumerable /* is IERC721 */ {
    /// @notice Count NFTs tracked by this contract
    /// @return A count of valid NFTs tracked by this contract, where each one of
    ///  them has an assigned and queryable owner not equal to the zero address
    function totalSupply() external view returns ( uint256 );

    /// @notice Enumerate valid NFTs
    /// @dev Throws if `index_` >= `totalSupply()`.
    /// @param index_ A counter less than `totalSupply()`
    /// @return The token identifier for the `index_`th NFT,
    ///  (sort order not specified)
    function tokenByIndex( uint256 index_ ) external view returns ( uint256 );

    /// @notice Enumerate NFTs assigned to an owner
    /// @dev Throws if `index_` >= `balanceOf(owner_)` or if
    ///  `owner_` is the zero address, representing invalid NFTs.
    /// @param owner_ An address where we are interested in NFTs owned by them
    /// @param index_ A counter less than `balanceOf(owner_)`
    /// @return The token identifier for the `index_`th NFT assigned to `owner_`,
    ///   (sort order not specified)
    function tokenOfOwnerByIndex( address owner_, uint256 index_ ) external view returns ( uint256 );
}

File 10 of 13 : IERC721Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x5b5e139f.
interface IERC721Metadata /* is IERC721 */ {
    /// @notice A descriptive name for a collection of NFTs in this contract
    function name() external view returns ( string memory _name );

    /// @notice An abbreviated name for NFTs in this contract
    function symbol() external view returns ( string memory _symbol );

    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the "ERC721
    ///  Metadata JSON Schema".
    function tokenURI( uint256 _tokenId ) external view returns ( string memory );
}

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

pragma solidity 0.8.17;

/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
///  Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface IERC721 /* is IERC165 */ {
  /// @dev This emits when ownership of any NFT changes by any mechanism.
  ///  This event emits when NFTs are created (`from` == 0) and destroyed
  ///  (`to` == 0). Exception: during contract creation, any number of NFTs
  ///  may be created and assigned without emitting Transfer. At the time of
  ///  any transfer, the approved address for that NFT (if any) is reset to none.
  event Transfer( address indexed from_, address indexed to_, uint256 indexed tokenId_ );

  /// @dev This emits when the approved address for an NFT is changed or
  ///  reaffirmed. The zero address indicates there is no approved address.
  ///  When a Transfer event emits, this also indicates that the approved
  ///  address for that NFT (if any) is reset to none.
  event Approval( address indexed owner_, address indexed approved_, uint256 indexed tokenId_ );

  /// @dev This emits when an operator is enabled or disabled for an owner.
  ///  The operator can manage all NFTs of the owner.
  event ApprovalForAll( address indexed owner_, address indexed operator_, bool approved_ );

  /// @notice Count all NFTs assigned to an owner
  /// @dev NFTs assigned to the zero address are considered invalid, and this
  ///  function throws for queries about the zero address.
  /// @param owner_ An address for whom to query the balance
  /// @return The number of NFTs owned by `owner_`, possibly zero
  function balanceOf( address owner_ ) external view returns ( uint256 );

  /// @notice Find the owner of an NFT
  /// @dev NFTs assigned to zero address are considered invalid, and queries
  ///  about them do throw.
  /// @param tokenId_ The identifier for an NFT
  /// @return The address of the owner of the NFT
  function ownerOf( uint256 tokenId_ ) external view returns ( address );

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @dev Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `from_` is
  ///  not the current owner. Throws if `to_` is the zero address. Throws if
  ///  `tokenId_` is not a valid NFT. When transfer is complete, this function
  ///  checks if `to_` is a smart contract (code size > 0). If so, it calls
  ///  `onERC721Received` on `to_` and throws if the return value is not
  ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
  /// @param from_ The current owner of the NFT
  /// @param to_ The new owner
  /// @param tokenId_ The NFT to transfer
  /// @param data_ Additional data with no specified format, sent in call to `to_`
  function safeTransferFrom( address from_, address to_, uint256 tokenId_, bytes calldata data_ ) external;

  /// @notice Transfers the ownership of an NFT from one address to another address
  /// @dev This works identically to the other function with an extra data parameter,
  ///  except this function just sets data to "".
  /// @param from_ The current owner of the NFT
  /// @param to_ The new owner
  /// @param tokenId_ The NFT to transfer
  function safeTransferFrom( address from_, address to_, uint256 tokenId_ ) external;

  /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
  ///  TO CONFIRM THAT `to_` IS CAPABLE OF RECEIVING NFTS OR ELSE
  ///  THEY MAY BE PERMANENTLY LOST
  /// @dev Throws unless `msg.sender` is the current owner, an authorized
  ///  operator, or the approved address for this NFT. Throws if `from_` is
  ///  not the current owner. Throws if `to_` is the zero address. Throws if
  ///  `tokenId_` is not a valid NFT.
  /// @param from_ The current owner of the NFT
  /// @param to_ The new owner
  /// @param tokenId_ The NFT to transfer
  function transferFrom( address from_, address to_, uint256 tokenId_ ) external;

  /// @notice Change or reaffirm the approved address for an NFT
  /// @dev The zero address indicates there is no approved address.
  ///  Throws unless `msg.sender` is the current NFT owner, or an authorized
  ///  operator of the current owner.
  /// @param approved_ The new approved NFT controller
  /// @param tokenId_ The NFT to approve
  function approve( address approved_, uint256 tokenId_ ) external;

  /// @notice Enable or disable approval for a third party ("operator") to manage
  ///  all of `msg.sender`'s assets
  /// @dev Emits the ApprovalForAll event. The contract MUST allow
  ///  multiple operators per owner.
  /// @param operator_ Address to add to the set of authorized operators
  /// @param approved_ True if the operator is approved, false to revoke approval
  function setApprovalForAll( address operator_, bool approved_ ) external;

  /// @notice Get the approved address for a single NFT
  /// @dev Throws if `tokenId_` is not a valid NFT.
  /// @param tokenId_ The NFT to find the approved address for
  /// @return The approved address for this NFT, or the zero address if there is none
  function getApproved( uint256 tokenId_ ) external view returns ( address );

  /// @notice Query if an address is an authorized operator for another address
  /// @param owner_ The address that owns the NFTs
  /// @param operator_ The address that acts on behalf of the owner
  /// @return True if `operator_` is an approved operator for `owner_`, false otherwise
  function isApprovedForAll( address owner_, address operator_ ) external view returns ( bool );
}

File 12 of 13 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

File 13 of 13 : IERC173.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/**
* @dev Required interface of an ERC173 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-173[EIP].
*/
interface IERC173 /* is IERC165 */ {
    /// @dev This emits when ownership of a contract changes.    
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @notice Get the address of the owner    
    /// @return The address of the owner.
    function owner() view external returns(address);
	
    /// @notice Set the address of the new owner of the contract
    /// @dev Set _newOwner to address(0) to renounce any ownership.
    /// @param _newOwner The address of the new owner of the contract    
    function transferOwnership(address _newOwner) external;	
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"maxSupply_","type":"uint256"},{"internalType":"uint256","name":"maxBatch_","type":"uint256"},{"internalType":"uint256","name":"reserve_","type":"uint256"},{"internalType":"uint256","name":"salePrice_","type":"uint256"},{"internalType":"uint256","name":"royaltyRate_","type":"uint256"},{"internalType":"address","name":"treasury_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ARRAY_LENGTH_MISMATCH","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHER_TRANSFER_FAIL","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"IERC173_NOT_OWNER","type":"error"},{"inputs":[{"internalType":"uint256","name":"royaltyRate","type":"uint256"},{"internalType":"uint256","name":"royaltyBase","type":"uint256"}],"name":"IERC2981_INVALID_ROYALTIES","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"IERC721Enumerable_INDEX_OUT_OF_BOUNDS","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"IERC721Enumerable_OWNER_INDEX_OUT_OF_BOUNDS","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IERC721_CALLER_NOT_APPROVED","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"IERC721_INVALID_APPROVAL","type":"error"},{"inputs":[],"name":"IERC721_INVALID_TRANSFER","type":"error"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IERC721_INVALID_TRANSFER_FROM","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"IERC721_NONEXISTANT_TOKEN","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"IERC721_NON_ERC721_RECEIVER","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountReceived","type":"uint256"},{"internalType":"uint256","name":"amountExpected","type":"uint256"}],"name":"INCORRECT_PRICE","type":"error"},{"inputs":[{"internalType":"uint8","name":"currentState","type":"uint8"}],"name":"IPausable_INCORRECT_STATE","type":"error"},{"inputs":[{"internalType":"uint8","name":"invalidState","type":"uint8"}],"name":"IPausable_INVALID_STATE","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"IWhitelistable_CONSUMED","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"IWhitelistable_FORBIDDEN","type":"error"},{"inputs":[],"name":"IWhitelistable_NOT_SET","type":"error"},{"inputs":[],"name":"NFT_INVALID_QTY","type":"error"},{"inputs":[{"internalType":"uint256","name":"qtyRequested","type":"uint256"},{"internalType":"uint256","name":"maxBatch","type":"uint256"}],"name":"NFT_MAX_BATCH","type":"error"},{"inputs":[{"internalType":"uint256","name":"qtyRequested","type":"uint256"},{"internalType":"uint256","name":"reserveLeft","type":"uint256"}],"name":"NFT_MAX_RESERVE","type":"error"},{"inputs":[{"internalType":"uint256","name":"qtyRequested","type":"uint256"},{"internalType":"uint256","name":"remainingSupply","type":"uint256"}],"name":"NFT_MAX_SUPPLY","type":"error"},{"inputs":[],"name":"NO_ETHER_BALANCE","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":"uint8","name":"previousState","type":"uint8"},{"indexed":true,"internalType":"uint8","name":"newState","type":"uint8"}],"name":"ContractStateChanged","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":"CLAIM","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSED","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRIVATE_SALE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUBLIC_SALE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WAITLIST_SALE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxyRegistryAddress_","type":"address"}],"name":"addProxyRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts_","type":"address[]"},{"internalType":"uint256[]","name":"amounts_","type":"uint256[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","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":"tokenOwner_","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account_","type":"address"},{"internalType":"uint8","name":"whitelistId_","type":"uint8"},{"internalType":"uint256","name":"alloted_","type":"uint256"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct IWhitelistable_ECDSA.Proof","name":"proof_","type":"tuple"}],"name":"checkWhitelistAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"qty_","type":"uint256"},{"internalType":"uint256","name":"alloted_","type":"uint256"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct IWhitelistable_ECDSA.Proof","name":"proof_","type":"tuple"}],"name":"claimDualSouls","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPauseState","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner_","type":"address"},{"internalType":"address","name":"operator_","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"qty_","type":"uint256"},{"internalType":"uint256","name":"alloted_","type":"uint256"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct IWhitelistable_ECDSA.Proof","name":"proof_","type":"tuple"}],"name":"mintPrivate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"qty_","type":"uint256"}],"name":"mintPublic","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"qty_","type":"uint256"},{"internalType":"uint256","name":"alloted_","type":"uint256"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct IWhitelistable_ECDSA.Proof","name":"proof_","type":"tuple"}],"name":"mintWaitlist","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"proxyRegistries","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proxyRegistryAddress_","type":"address"}],"name":"removeProxyRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"salePrice_","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator_","type":"address"},{"internalType":"bool","name":"approved_","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newState_","type":"uint8"}],"name":"setPauseState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"publicSalePrice_","type":"uint256"},{"internalType":"uint256","name":"privateSalePrice_","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"royaltyRecipient_","type":"address"},{"internalType":"uint256","name":"royaltyRate_","type":"uint256"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury_","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"adminSigner_","type":"address"}],"name":"setWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner_","type":"address"},{"internalType":"uint256","name":"index_","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner_","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260016006553480156200001657600080fd5b5060405162003c1e38038062003c1e83398101604081905262000039916200020d565b6040805160c081018252888152602081018a9052908101869052606081018690526080810183905260a081018290526009888155600a8a9055600b879055600c879055600d6200008a85826200035a565b5060a08201516005820190620000a190826200035a565b5050506007869055600f80546001600160a01b0319166001600160a01b038516179055620000d08385620000f0565b600280546001600160a01b03191633179055505050505050505062000426565b6127108111156200012357604051632761fe9d60e11b815260048101829052612710602482015260440160405180910390fd5b600055600180546001600160a01b0319166001600160a01b0392909216919091179055565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200017057600080fd5b81516001600160401b03808211156200018d576200018d62000148565b604051601f8301601f19908116603f01168101908282118183101715620001b857620001b862000148565b81604052838152602092508683858801011115620001d557600080fd5b600091505b83821015620001f95785820183015181830184015290820190620001da565b600093810190920192909252949350505050565b600080600080600080600080610100898b0312156200022b57600080fd5b885160208a015160408b015160608c015160808d015160a08e0151949c50929a50909850965094506001600160a01b03811681146200026957600080fd5b60c08a01519093506001600160401b03808211156200028757600080fd5b620002958c838d016200015e565b935060e08b0151915080821115620002ac57600080fd5b50620002bb8b828c016200015e565b9150509295985092959890939650565b600181811c90821680620002e057607f821691505b6020821081036200030157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200035557600081815260208120601f850160051c81016020861015620003305750805b601f850160051c820191505b8181101562000351578281556001016200033c565b5050505b505050565b81516001600160401b0381111562000376576200037662000148565b6200038e81620003878454620002cb565b8462000307565b602080601f831160018114620003c65760008415620003ad5750858301515b600019600386901b1c1916600185901b17855562000351565b600085815260208120601f198616915b82811015620003f757888601518255948401946001909101908401620003d6565b5085821015620004165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6137e880620004366000396000f3fe6080604052600436106102d15760003560e01c8063854cff2f11610179578063c87b56dd116100d6578063ef72f2761161008a578063f2fde38b11610064578063f2fde38b146107d3578063f7d97577146107f3578063ff21456b1461081357600080fd5b8063ef72f27614610780578063efd0cbf9146107a0578063f0f44260146107b357600080fd5b8063d37ce09f116100bb578063d37ce09f14610704578063e2e784d514610717578063e985e9c51461073757600080fd5b8063c87b56dd146106c4578063d0348b97146106e457600080fd5b80639a44f1fb1161012d578063a9aad58c11610112578063a9aad58c1461067a578063b88d4fde1461068f578063c50ef4d8146106af57600080fd5b80639a44f1fb1461062a578063a22cb4651461065a57600080fd5b80638da5cb5b1161015e5780638da5cb5b146105e257806395d89b411461060057806398c83a161461061557600080fd5b8063854cff2f146105af57806386c27ffc146105cf57600080fd5b806342842e0e116102325780636352211e116101e657806370a08231116101c057806370a082311461056557806373d74876146105855780637e9845f51461059a57600080fd5b80636352211e1461050557806367243482146105255780636dfa99fd1461054557600080fd5b806355f804b31161021757806355f804b31461049e5780635f89584e146104be57806363096509146104e557600080fd5b806342842e0e1461045e5780634f6ccce71461047e57600080fd5b80631a3f839d116102895780632a55205a1161026e5780632a55205a146103ea5780632f745c59146104295780633ccfd60b1461044957600080fd5b80631a3f839d146103aa57806323b872dd146103ca57600080fd5b8063081812fc116102ba578063081812fc1461032d578063095ea7b31461036557806318160ddd1461038757600080fd5b806301ffc9a7146102d657806306fdde031461030b575b600080fd5b3480156102e257600080fd5b506102f66102f1366004612df1565b610826565b60405190151581526020015b60405180910390f35b34801561031757600080fd5b506103206109ef565b6040516103029190612e5e565b34801561033957600080fd5b5061034d610348366004612e71565b610a84565b6040516001600160a01b039091168152602001610302565b34801561037157600080fd5b50610385610380366004612ea6565b610aef565b005b34801561039357600080fd5b5061039c610c6d565b604051908152602001610302565b3480156103b657600080fd5b5061039c6103c5366004612fa4565b610c7c565b3480156103d657600080fd5b506103856103e5366004612ff2565b610db4565b3480156103f657600080fd5b5061040a61040536600461302e565b610f1e565b604080516001600160a01b039093168352602083019190915201610302565b34801561043557600080fd5b5061039c610444366004612ea6565b610f7a565b34801561045557600080fd5b50610385611040565b34801561046a57600080fd5b50610385610479366004612ff2565b611184565b34801561048a57600080fd5b5061039c610499366004612e71565b6111a4565b3480156104aa57600080fd5b506103856104b93660046130a8565b6111ed565b3480156104ca57600080fd5b506104d3600181565b60405160ff9091168152602001610302565b3480156104f157600080fd5b506103856105003660046130f1565b611258565b34801561051157600080fd5b5061034d610520366004612e71565b611307565b34801561053157600080fd5b5061038561054036600461319b565b61135c565b34801561055157600080fd5b5061038561056036600461325b565b6114f2565b34801561057157600080fd5b5061039c61058036600461325b565b61155a565b34801561059157600080fd5b506104d3600481565b3480156105a657600080fd5b5061039c611608565b3480156105bb57600080fd5b506103856105ca36600461325b565b611619565b6103856105dd366004613276565b6116af565b3480156105ee57600080fd5b506002546001600160a01b031661034d565b34801561060c57600080fd5b506103206118be565b34801561062157600080fd5b506104d3600281565b34801561063657600080fd5b5060025474010000000000000000000000000000000000000000900460ff166104d3565b34801561066657600080fd5b506103856106753660046132ac565b6118d0565b34801561068657600080fd5b506104d3600081565b34801561069b57600080fd5b506103856106aa3660046132e8565b6119aa565b3480156106bb57600080fd5b506104d3600381565b3480156106d057600080fd5b506103206106df366004612e71565b611a02565b3480156106f057600080fd5b5061034d6106ff366004612e71565b611a9e565b610385610712366004613276565b611ac8565b34801561072357600080fd5b50610385610732366004612ea6565b611cce565b34801561074357600080fd5b506102f6610752366004613364565b6001600160a01b03918216600090815260116020908152604080832093909416825291909152205460ff1690565b34801561078c57600080fd5b5061038561079b36600461325b565b611d37565b6103856107ae366004612e71565b611d9f565b3480156107bf57600080fd5b506103856107ce36600461325b565b611f6c565b3480156107df57600080fd5b506103856107ee36600461325b565b612006565b3480156107ff57600080fd5b5061038561080e36600461302e565b6120d0565b610385610821366004613276565b61213b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd0000000000000000000000000000000000000000000000000000000014806108b957507fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d6300000000000000000000000000000000000000000000000000000000145b8061090557507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061095157507fffffffff0000000000000000000000000000000000000000000000000000000082167f7f5828d000000000000000000000000000000000000000000000000000000000145b8061099d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806109e957507fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a00000000000000000000000000000000000000000000000000000000145b92915050565b606060096004018054610a0190613397565b80601f0160208091040260200160405190810160405280929190818152602001828054610a2d90613397565b8015610a7a5780601f10610a4f57610100808354040283529160200191610a7a565b820191906000526020600020905b815481529060010190602001808311610a5d57829003601f168201915b5050505050905090565b600081610a9081612335565b610ace576040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6000838152601060205260409020546001600160a01b031691505b50919050565b80610af981612335565b610b32576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b336000610b3e8461234f565b9050806001600160a01b0316856001600160a01b031603610b96576040517ff2b21e1c0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610ac5565b6000610ba38284876123a6565b905080610bf6576040517f19f48dff0000000000000000000000000000000000000000000000000000000081526001600160a01b0380841660048301528416602482015260448101869052606401610ac5565b60008581526010602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a811691821790925591518893918616917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050505050565b6000610c7761241b565b905090565b6004546000906001600160a01b0316610cc1576040517fc71bad4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff841660009081526005602090815260408083206001600160a01b03891684529091529020548311610d2b576040517f706e18b90000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610ac5565b610d3785858585612425565b610d78576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610ac5565b60ff841660009081526005602090815260408083206001600160a01b0389168452909152902054610da99084613413565b90505b949350505050565b80610dbe81612335565b610df7576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b6001600160a01b038316610e37576040517f14242cb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000610e438461234f565b9050806001600160a01b0316866001600160a01b031614610eaa576040517fe02b28e70000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528716602482015260448101859052606401610ac5565b6000610eb78284876123a6565b905080610f0a576040517f19f48dff0000000000000000000000000000000000000000000000000000000081526001600160a01b0380841660048301528416602482015260448101869052606401610ac5565b610f158287876124fa565b50505050505050565b60008083610f2b81612335565b610f64576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b610f6e85856126c3565b92509250509250929050565b6000610f858361155a565b8210610fcf576040517f374f8b4f0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101839052604401610ac5565b600060015b60065481101561103857610fe781612335565b801561100c5750610ff78161234f565b6001600160a01b0316856001600160a01b0316145b15611028578184036110215791506109e99050565b6001909101905b61103181613426565b9050610fd4565b505092915050565b33806110546002546001600160a01b031690565b6001600160a01b03161461109f576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b4760008190036110db576040517f1f84313900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f546040516001600160a01b0390911690600090829084908381818185875af1925050503d806000811461112c576040519150601f19603f3d011682016040523d82523d6000602084013e611131565b606091505b505090508061117e576040517f84020a7b0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101849052604401610ac5565b50505050565b61119f838383604051806020016040528060008152506119aa565b505050565b60006111ae611608565b82106111e9576040517f125c19b000000000000000000000000000000000000000000000000000000000815260048101839052602401610ac5565b5090565b33806112016002546001600160a01b031690565b6001600160a01b03161461124c576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600861119f83826134a4565b338061126c6002546001600160a01b031690565b6001600160a01b0316146112b7576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600460ff831611156112fa576040517f9b7c47a200000000000000000000000000000000000000000000000000000000815260ff83166004820152602401610ac5565b61130382612723565b5050565b60008161131381612335565b61134c576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b6113558361234f565b9392505050565b33806113706002546001600160a01b031690565b6001600160a01b0316146113bb576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b8151835181146113f7576040517f88adebd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815b8015611444578461140d600183613413565b8151811061141d5761141d6135a0565b60200260200101518261143091906135cf565b91508061143c816135e2565b9150506113fb565b5060075481111561148f576007546040517f016c69db000000000000000000000000000000000000000000000000000000008152610ac5918391600401918252602082015260400190565b600780548290039055815b80156114ea578080600190039150506114e58682815181106114be576114be6135a0565b60200260200101518683815181106114d8576114d86135a0565b60200260200101516127a1565b61149a565b505050505050565b33806115066002546001600160a01b031690565b6001600160a01b031614611551576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b6113038261289f565b60006001600160a01b03821661157257506000919050565b60008060015b6006548110156115ff5761158b81612335565b156115ef576000818152601260205260409020546001600160a01b0316156115c8576000818152601260205260409020546001600160a01b031691505b816001600160a01b0316856001600160a01b0316036115ef57826115eb81613426565b9350505b6115f881613426565b9050611578565b50909392505050565b60006001600654610c779190613413565b338061162d6002546001600160a01b031690565b6001600160a01b031614611678576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555050565b82806000036116ea576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805474010000000000000000000000000000000000000000900460ff1690811480159061171d575060ff8116600314155b15611757576040517f81d1489b00000000000000000000000000000000000000000000000000000000815260026004820152602401610ac5565b336004858588600061176b86868686610c7c565b9050818110156117b2576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b60006117bc611608565b600754600a546117cc9190613413565b6117d69190613413565b9050808c111561181c576040517f9abbab07000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610ac5565b600c5460009061182c908e613617565b9050348114611870576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b3360009081527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d56020526040902080548e0190555b6118af338e6127a1565b50505050505050505050505050565b606060096005018054610a0190613397565b336001600160a01b03831681900361191f576040517ff2b21e1c0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ac5565b6001600160a01b0381811660008181526011602090815260408083209488168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6119b5848484610db4565b6119c1848484846129e0565b61117e576040517f015be56a0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ac5565b606081611a0e81612335565b611a47576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b600060088054611a5690613397565b905011611a6b57611a6683612b49565b611355565b6008611a7684612b49565b604051602001611a8792919061362e565b604051602081830303815290604052915050919050565b60038181548110611aae57600080fd5b6000918252602090912001546001600160a01b0316905081565b8280600003611b03576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460039074010000000000000000000000000000000000000000900460ff168114611b7c576002546040517f81d1489b0000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910460ff166004820152602401610ac5565b3360038585886000611b9086868686610c7c565b905081811015611bd7576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b6000611be1611608565b600754600a54611bf19190613413565b611bfb9190613413565b9050808c1115611c41576040517f9abbab07000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610ac5565b600c54600090611c51908e613617565b9050348114611c95576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b3360009081527fa9bc9a3a348c357ba16b37005d7e6b3236198c0e939f4af8c5f19b8deeb8ebc06020526040902080548e0190556118a5565b3380611ce26002546001600160a01b031690565b6001600160a01b031614611d2d576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b61119f8383612c7e565b3380611d4b6002546001600160a01b031690565b6001600160a01b031614611d96576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b61130382612d02565b8080600003611dda576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460019074010000000000000000000000000000000000000000900460ff168114611e53576002546040517f81d1489b0000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910460ff166004820152602401610ac5565b600954831115611e9d576009546040517f5aaca4e4000000000000000000000000000000000000000000000000000000008152610ac5918591600401918252602082015260400190565b6000611ea7611608565b600754600a54611eb79190613413565b611ec19190613413565b905080841115611f07576040517f9abbab070000000000000000000000000000000000000000000000000000000081526004810185905260248101829052604401610ac5565b600b54600090611f179086613617565b9050348114611f5b576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b611f6533866127a1565b5050505050565b3380611f806002546001600160a01b031690565b6001600160a01b031614611fcb576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b50600f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b338061201a6002546001600160a01b031690565b6001600160a01b031614612065576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600280546001600160a01b038481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b33806120e46002546001600160a01b031690565b6001600160a01b03161461212f576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b50600b91909155600c55565b8280600003612176576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805474010000000000000000000000000000000000000000900460ff169081148015906121a9575060ff8116600314155b156121e3576040517f81d1489b00000000000000000000000000000000000000000000000000000000815260026004820152602401610ac5565b33600285858860006121f786868686610c7c565b90508181101561223e576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b6000612248611608565b600754600a546122589190613413565b6122629190613413565b9050808c11156122a8576040517f9abbab07000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610ac5565b600c546000906122b8908e613617565b90503481146122fc576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b3360009081527f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a6020526040902080548e0190556118a5565b60008160000361234757506000919050565b506006541190565b60008181526012602052604081205482906001600160a01b03165b6001600160a01b0381166113555781612382816135e2565b6000818152601260205260409020549093506001600160a01b0316915061236a9050565b600080846001600160a01b0316846001600160a01b031614806123e257506123cd83610a84565b6001600160a01b0316846001600160a01b0316145b8061241257506001600160a01b0380861660009081526011602090815260408083209388168352929052205460ff165b95945050505050565b6000610c77611608565b6040805160ff851660208201529081018390526001600160a01b038516606082015260009081906080016040516020818303038152906040528051906020012090506000600182856040015186600001518760200151604051600081526020016040526040516124b1949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156124d3573d6000803e3d6000fd5b5050604051601f1901516004546001600160a01b0390811691161498975050505050505050565b600081815260106020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001821161253d576001612548565b612548600183613413565b905060006125578360016135cf565b90506000838310801561256e575061256e83612335565b801561258f57506000838152601260205260409020546001600160a01b0316155b9050600061259c83612335565b80156125bd57506000838152601260205260409020546001600160a01b0316155b9050811561260557600084815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389161790555b801561264b57600083815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389161790555b60008581526012602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a811691821790925591518893918b16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050505050565b6000808215806126d35750600054155b156126ed5750506001546001600160a01b0316600061271c565b6000612710846000546127009190613617565b61270a9190613702565b6001546001600160a01b031693509150505b9250929050565b6002805460ff838116740100000000000000000000000000000000000000008181027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff85161790945560405193909204169182907f7285522ec93a20dcefa1a1d057094a227073a5463b91c0c19a23c6ef5c9c1fe490600090a35050565b60065460006127b083836135cf565b905060006127bf600183613413565b600084815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03881617905590508281111561284857600081815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0387161790555b6006829055825b828110156114ea5760405181906001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a461289881613426565b905061284f565b60035480801561119f57808060019003915050826001600160a01b0316600382815481106128cf576128cf6135a0565b6000918252602090912001546001600160a01b03160361119f57816128f58260016135cf565b14612972576003612907600184613413565b81548110612917576129176135a0565b600091825260209091200154600380546001600160a01b039092169183908110612943576129436135a0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600380548061298357612983613716565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505050565b6000833b8015612b3f576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0386169063150b7a0290612a359033908a9089908990600401613745565b6020604051808303816000875af1925050508015612a70575060408051601f3d908101601f19168201909252612a6d91810190613781565b60015b612af2573d808015612a9e576040519150601f19603f3d011682016040523d82523d6000602084013e612aa3565b606091505b508051600003612aea576040517f015be56a0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149150610dac9050565b6001915050610dac565b606081600003612b8c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115612bb65780612ba081613426565b9150612baf9050600a83613702565b9150612b90565b60008167ffffffffffffffff811115612bd157612bd1612ee1565b6040519080825280601f01601f191660200182016040528015612bfb576020820181803683370190505b5090505b8415610dac57612c10600183613413565b9150612c1d600a8661379e565b612c289060306135cf565b60f81b818381518110612c3d57612c3d6135a0565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612c77600a86613702565b9450612bff565b612710811115612cc5576040517f4ec3fd3a000000000000000000000000000000000000000000000000000000008152600481018290526127106024820152604401610ac5565b600055600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6003545b8015612d5557808060019003915050816001600160a01b031660038281548110612d3257612d326135a0565b6000918252602090912001546001600160a01b031603612d50575050565b612d06565b50600380546001810182556000919091527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114612dee57600080fd5b50565b600060208284031215612e0357600080fd5b813561135581612dc0565b60005b83811015612e29578181015183820152602001612e11565b50506000910152565b60008151808452612e4a816020860160208601612e0e565b601f01601f19169290920160200192915050565b6020815260006113556020830184612e32565b600060208284031215612e8357600080fd5b5035919050565b80356001600160a01b0381168114612ea157600080fd5b919050565b60008060408385031215612eb957600080fd5b612ec283612e8a565b946020939093013593505050565b803560ff81168114612ea157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612f3957612f39612ee1565b604052919050565b600060608284031215612f5357600080fd5b6040516060810181811067ffffffffffffffff82111715612f7657612f76612ee1565b80604052508091508235815260208301356020820152612f9860408401612ed0565b60408201525092915050565b60008060008060c08587031215612fba57600080fd5b612fc385612e8a565b9350612fd160208601612ed0565b925060408501359150612fe78660608701612f41565b905092959194509250565b60008060006060848603121561300757600080fd5b61301084612e8a565b925061301e60208501612e8a565b9150604084013590509250925092565b6000806040838503121561304157600080fd5b50508035926020909101359150565b600067ffffffffffffffff83111561306a5761306a612ee1565b61307d6020601f19601f86011601612f10565b905082815283838301111561309157600080fd5b828260208301376000602084830101529392505050565b6000602082840312156130ba57600080fd5b813567ffffffffffffffff8111156130d157600080fd5b8201601f810184136130e257600080fd5b610dac84823560208401613050565b60006020828403121561310357600080fd5b61135582612ed0565b600067ffffffffffffffff82111561312657613126612ee1565b5060051b60200190565b600082601f83011261314157600080fd5b813560206131566131518361310c565b612f10565b82815260059290921b8401810191818101908684111561317557600080fd5b8286015b848110156131905780358352918301918301613179565b509695505050505050565b600080604083850312156131ae57600080fd5b823567ffffffffffffffff808211156131c657600080fd5b818501915085601f8301126131da57600080fd5b813560206131ea6131518361310c565b82815260059290921b8401810191818101908984111561320957600080fd5b948201945b8386101561322e5761321f86612e8a565b8252948201949082019061320e565b9650508601359250508082111561324457600080fd5b5061325185828601613130565b9150509250929050565b60006020828403121561326d57600080fd5b61135582612e8a565b600080600060a0848603121561328b57600080fd5b83359250602084013591506132a38560408601612f41565b90509250925092565b600080604083850312156132bf57600080fd5b6132c883612e8a565b9150602083013580151581146132dd57600080fd5b809150509250929050565b600080600080608085870312156132fe57600080fd5b61330785612e8a565b935061331560208601612e8a565b925060408501359150606085013567ffffffffffffffff81111561333857600080fd5b8501601f8101871361334957600080fd5b61335887823560208401613050565b91505092959194509250565b6000806040838503121561337757600080fd5b61338083612e8a565b915061338e60208401612e8a565b90509250929050565b600181811c908216806133ab57607f821691505b602082108103610ae9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109e9576109e96133e4565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613457576134576133e4565b5060010190565b601f82111561119f57600081815260208120601f850160051c810160208610156134855750805b601f850160051c820191505b818110156114ea57828155600101613491565b815167ffffffffffffffff8111156134be576134be612ee1565b6134d2816134cc8454613397565b8461345e565b602080601f83116001811461352557600084156134ef5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114ea565b600085815260208120601f198616915b8281101561355457888601518255948401946001909101908401613535565b508582101561359057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808201808211156109e9576109e96133e4565b6000816135f1576135f16133e4565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b80820281158282048414176109e9576109e96133e4565b600080845461363c81613397565b600182811680156136545760018114613687576136b6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506136b6565b8860005260208060002060005b858110156136ad5781548a820152908401908201613694565b50505082870194505b5050505083516136ca818360208801612e0e565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613711576137116136d3565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60006001600160a01b038087168352808616602084015250836040830152608060608301526137776080830184612e32565b9695505050505050565b60006020828403121561379357600080fd5b815161135581612dc0565b6000826137ad576137ad6136d3565b50069056fea264697066735822122021de66c5fe474d20aac363c752bb1d02980438178ac105c1eb6fb63f5363ae5864736f6c63430008110033000000000000000000000000000000000000000000000000000000000000177000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000011c37937e08000000000000000000000000000000000000000000000000000000000000000003700000000000000000000000004a5ab7a444f92254123bdaedbefec6a2218b22c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000c537069726974204761746573000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025347000000000000000000000000000000000000000000000000000000000000

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

000000000000000000000000000000000000000000000000000000000000177000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000011c37937e08000000000000000000000000000000000000000000000000000000000000000003700000000000000000000000004a5ab7a444f92254123bdaedbefec6a2218b22c000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000c537069726974204761746573000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025347000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : maxSupply_ (uint256): 6000
Arg [1] : maxBatch_ (uint256): 5
Arg [2] : reserve_ (uint256): 100
Arg [3] : salePrice_ (uint256): 80000000000000000
Arg [4] : royaltyRate_ (uint256): 880
Arg [5] : treasury_ (address): 0x4A5AB7A444F92254123BDAedbefec6a2218B22c0
Arg [6] : name_ (string): Spirit Gates
Arg [7] : symbol_ (string): SG

-----Encoded View---------------
12 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000001770
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [3] : 000000000000000000000000000000000000000000000000011c37937e080000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000370
Arg [5] : 0000000000000000000000004a5ab7a444f92254123bdaedbefec6a2218b22c0
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [8] : 000000000000000000000000000000000000000000000000000000000000000c
Arg [9] : 5370697269742047617465730000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [11] : 5347000000000000000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.