ETH Price: $1,964.81 (-2.37%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

TokenTracker

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...243611202026-02-01 9:28:4728 days ago1769938127IN
0x19B43663...e2a764a52
0 ETH0.000001720.07103874
Set Approval For...243611172026-02-01 9:28:1128 days ago1769938091IN
0x19B43663...e2a764a52
0 ETH0.000001830.07567554
Set Approval For...242129412026-01-11 17:23:2349 days ago1768152203IN
0x19B43663...e2a764a52
0 ETH0.00000150.06197765
Set Approval For...241962022026-01-09 9:23:1151 days ago1767950591IN
0x19B43663...e2a764a52
0 ETH0.000001380.057013
Set Approval For...241962002026-01-09 9:22:4751 days ago1767950567IN
0x19B43663...e2a764a52
0 ETH0.000001370.05672224
Set Approval For...241314342025-12-31 8:32:1160 days ago1767169931IN
0x19B43663...e2a764a52
0 ETH0.00000140.05820247
Set Approval For...240994762025-12-26 21:25:2365 days ago1766784323IN
0x19B43663...e2a764a52
0 ETH0.000000990.04107381
Set Approval For...240847232025-12-24 19:59:1167 days ago1766606351IN
0x19B43663...e2a764a52
0 ETH0.000049282.02971107
Set Approval For...240820202025-12-24 10:56:1167 days ago1766573771IN
0x19B43663...e2a764a52
0 ETH0.000012960.53592559
Set Approval For...240682742025-12-22 12:53:1169 days ago1766407991IN
0x19B43663...e2a764a52
0 ETH0.000001210.04998715
Set Approval For...240382142025-12-18 8:11:3573 days ago1766045495IN
0x19B43663...e2a764a52
0 ETH0.000001220.02658442
Set Approval For...240027222025-12-13 9:14:3578 days ago1765617275IN
0x19B43663...e2a764a52
0 ETH0.000001720.03747095
Set Approval For...239975622025-12-12 15:54:3579 days ago1765554875IN
0x19B43663...e2a764a52
0 ETH0.000036261.49862954
Set Approval For...238962482025-11-28 9:21:3593 days ago1764321695IN
0x19B43663...e2a764a52
0 ETH0.00000190.0414132
Set Approval For...238918722025-11-27 18:37:2394 days ago1764268643IN
0x19B43663...e2a764a52
0 ETH0.000002360.05117853
Set Approval For...238711392025-11-24 20:40:1197 days ago1764016811IN
0x19B43663...e2a764a52
0 ETH0.000053832.22489819
Safe Transfer Fr...238274852025-11-18 17:27:59103 days ago1763486879IN
0x19B43663...e2a764a52
0 ETH0.000031710.74822482
Safe Transfer Fr...238078642025-11-15 23:28:11106 days ago1763249291IN
0x19B43663...e2a764a52
0 ETH0.000003180.07514489
Safe Transfer Fr...238078102025-11-15 23:17:23106 days ago1763248643IN
0x19B43663...e2a764a52
0 ETH0.000006640.15687337
Set Approval For...237984662025-11-14 15:56:35107 days ago1763135795IN
0x19B43663...e2a764a52
0 ETH0.000080553.3177658
Safe Transfer Fr...237607682025-11-09 9:19:35112 days ago1762679975IN
0x19B43663...e2a764a52
0 ETH0.00000310.07318852
Safe Transfer Fr...237604492025-11-09 8:15:35112 days ago1762676135IN
0x19B43663...e2a764a52
0 ETH0.000006640.15669091
Safe Transfer Fr...237457542025-11-07 6:58:23114 days ago1762498703IN
0x19B43663...e2a764a52
0 ETH0.000013210.3118496
Safe Transfer Fr...237378352025-11-06 4:23:59115 days ago1762403039IN
0x19B43663...e2a764a52
0 ETH0.000014430.34062849
Safe Transfer Fr...237378082025-11-06 4:18:35115 days ago1762402715IN
0x19B43663...e2a764a52
0 ETH0.00001560.36819302
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer156353302022-09-29 0:10:231250 days ago1664410223
0x19B43663...e2a764a52
281.84 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
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;
      }
    // +---------+
  // **************************************
}

// 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_;
	}
}

// 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_;
		}
	}
}

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

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

// 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_ );
	}
}

// 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 );
}

// 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 );
}

// 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 );
}

// 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 );
}

// 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 );
}

// 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);
}

// 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

API
[{"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

Deployed Bytecode

0x6080604052600436106102d15760003560e01c8063854cff2f11610179578063c87b56dd116100d6578063ef72f2761161008a578063f2fde38b11610064578063f2fde38b146107d3578063f7d97577146107f3578063ff21456b1461081357600080fd5b8063ef72f27614610780578063efd0cbf9146107a0578063f0f44260146107b357600080fd5b8063d37ce09f116100bb578063d37ce09f14610704578063e2e784d514610717578063e985e9c51461073757600080fd5b8063c87b56dd146106c4578063d0348b97146106e457600080fd5b80639a44f1fb1161012d578063a9aad58c11610112578063a9aad58c1461067a578063b88d4fde1461068f578063c50ef4d8146106af57600080fd5b80639a44f1fb1461062a578063a22cb4651461065a57600080fd5b80638da5cb5b1161015e5780638da5cb5b146105e257806395d89b411461060057806398c83a161461061557600080fd5b8063854cff2f146105af57806386c27ffc146105cf57600080fd5b806342842e0e116102325780636352211e116101e657806370a08231116101c057806370a082311461056557806373d74876146105855780637e9845f51461059a57600080fd5b80636352211e1461050557806367243482146105255780636dfa99fd1461054557600080fd5b806355f804b31161021757806355f804b31461049e5780635f89584e146104be57806363096509146104e557600080fd5b806342842e0e1461045e5780634f6ccce71461047e57600080fd5b80631a3f839d116102895780632a55205a1161026e5780632a55205a146103ea5780632f745c59146104295780633ccfd60b1461044957600080fd5b80631a3f839d146103aa57806323b872dd146103ca57600080fd5b8063081812fc116102ba578063081812fc1461032d578063095ea7b31461036557806318160ddd1461038757600080fd5b806301ffc9a7146102d657806306fdde031461030b575b600080fd5b3480156102e257600080fd5b506102f66102f1366004612df1565b610826565b60405190151581526020015b60405180910390f35b34801561031757600080fd5b506103206109ef565b6040516103029190612e5e565b34801561033957600080fd5b5061034d610348366004612e71565b610a84565b6040516001600160a01b039091168152602001610302565b34801561037157600080fd5b50610385610380366004612ea6565b610aef565b005b34801561039357600080fd5b5061039c610c6d565b604051908152602001610302565b3480156103b657600080fd5b5061039c6103c5366004612fa4565b610c7c565b3480156103d657600080fd5b506103856103e5366004612ff2565b610db4565b3480156103f657600080fd5b5061040a61040536600461302e565b610f1e565b604080516001600160a01b039093168352602083019190915201610302565b34801561043557600080fd5b5061039c610444366004612ea6565b610f7a565b34801561045557600080fd5b50610385611040565b34801561046a57600080fd5b50610385610479366004612ff2565b611184565b34801561048a57600080fd5b5061039c610499366004612e71565b6111a4565b3480156104aa57600080fd5b506103856104b93660046130a8565b6111ed565b3480156104ca57600080fd5b506104d3600181565b60405160ff9091168152602001610302565b3480156104f157600080fd5b506103856105003660046130f1565b611258565b34801561051157600080fd5b5061034d610520366004612e71565b611307565b34801561053157600080fd5b5061038561054036600461319b565b61135c565b34801561055157600080fd5b5061038561056036600461325b565b6114f2565b34801561057157600080fd5b5061039c61058036600461325b565b61155a565b34801561059157600080fd5b506104d3600481565b3480156105a657600080fd5b5061039c611608565b3480156105bb57600080fd5b506103856105ca36600461325b565b611619565b6103856105dd366004613276565b6116af565b3480156105ee57600080fd5b506002546001600160a01b031661034d565b34801561060c57600080fd5b506103206118be565b34801561062157600080fd5b506104d3600281565b34801561063657600080fd5b5060025474010000000000000000000000000000000000000000900460ff166104d3565b34801561066657600080fd5b506103856106753660046132ac565b6118d0565b34801561068657600080fd5b506104d3600081565b34801561069b57600080fd5b506103856106aa3660046132e8565b6119aa565b3480156106bb57600080fd5b506104d3600381565b3480156106d057600080fd5b506103206106df366004612e71565b611a02565b3480156106f057600080fd5b5061034d6106ff366004612e71565b611a9e565b610385610712366004613276565b611ac8565b34801561072357600080fd5b50610385610732366004612ea6565b611cce565b34801561074357600080fd5b506102f6610752366004613364565b6001600160a01b03918216600090815260116020908152604080832093909416825291909152205460ff1690565b34801561078c57600080fd5b5061038561079b36600461325b565b611d37565b6103856107ae366004612e71565b611d9f565b3480156107bf57600080fd5b506103856107ce36600461325b565b611f6c565b3480156107df57600080fd5b506103856107ee36600461325b565b612006565b3480156107ff57600080fd5b5061038561080e36600461302e565b6120d0565b610385610821366004613276565b61213b565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd0000000000000000000000000000000000000000000000000000000014806108b957507fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d6300000000000000000000000000000000000000000000000000000000145b8061090557507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b8061095157507fffffffff0000000000000000000000000000000000000000000000000000000082167f7f5828d000000000000000000000000000000000000000000000000000000000145b8061099d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b806109e957507fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a00000000000000000000000000000000000000000000000000000000145b92915050565b606060096004018054610a0190613397565b80601f0160208091040260200160405190810160405280929190818152602001828054610a2d90613397565b8015610a7a5780601f10610a4f57610100808354040283529160200191610a7a565b820191906000526020600020905b815481529060010190602001808311610a5d57829003601f168201915b5050505050905090565b600081610a9081612335565b610ace576040517f1cf4d9a4000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b6000838152601060205260409020546001600160a01b031691505b50919050565b80610af981612335565b610b32576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b336000610b3e8461234f565b9050806001600160a01b0316856001600160a01b031603610b96576040517ff2b21e1c0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610ac5565b6000610ba38284876123a6565b905080610bf6576040517f19f48dff0000000000000000000000000000000000000000000000000000000081526001600160a01b0380841660048301528416602482015260448101869052606401610ac5565b60008581526010602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a811691821790925591518893918616917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050505050565b6000610c7761241b565b905090565b6004546000906001600160a01b0316610cc1576040517fc71bad4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff841660009081526005602090815260408083206001600160a01b03891684529091529020548311610d2b576040517f706e18b90000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610ac5565b610d3785858585612425565b610d78576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0386166004820152602401610ac5565b60ff841660009081526005602090815260408083206001600160a01b0389168452909152902054610da99084613413565b90505b949350505050565b80610dbe81612335565b610df7576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b6001600160a01b038316610e37576040517f14242cb600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000610e438461234f565b9050806001600160a01b0316866001600160a01b031614610eaa576040517fe02b28e70000000000000000000000000000000000000000000000000000000081526001600160a01b0380831660048301528716602482015260448101859052606401610ac5565b6000610eb78284876123a6565b905080610f0a576040517f19f48dff0000000000000000000000000000000000000000000000000000000081526001600160a01b0380841660048301528416602482015260448101869052606401610ac5565b610f158287876124fa565b50505050505050565b60008083610f2b81612335565b610f64576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b610f6e85856126c3565b92509250509250929050565b6000610f858361155a565b8210610fcf576040517f374f8b4f0000000000000000000000000000000000000000000000000000000081526001600160a01b038416600482015260248101839052604401610ac5565b600060015b60065481101561103857610fe781612335565b801561100c5750610ff78161234f565b6001600160a01b0316856001600160a01b0316145b15611028578184036110215791506109e99050565b6001909101905b61103181613426565b9050610fd4565b505092915050565b33806110546002546001600160a01b031690565b6001600160a01b03161461109f576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b4760008190036110db576040517f1f84313900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f546040516001600160a01b0390911690600090829084908381818185875af1925050503d806000811461112c576040519150601f19603f3d011682016040523d82523d6000602084013e611131565b606091505b505090508061117e576040517f84020a7b0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101849052604401610ac5565b50505050565b61119f838383604051806020016040528060008152506119aa565b505050565b60006111ae611608565b82106111e9576040517f125c19b000000000000000000000000000000000000000000000000000000000815260048101839052602401610ac5565b5090565b33806112016002546001600160a01b031690565b6001600160a01b03161461124c576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600861119f83826134a4565b338061126c6002546001600160a01b031690565b6001600160a01b0316146112b7576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600460ff831611156112fa576040517f9b7c47a200000000000000000000000000000000000000000000000000000000815260ff83166004820152602401610ac5565b61130382612723565b5050565b60008161131381612335565b61134c576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b6113558361234f565b9392505050565b33806113706002546001600160a01b031690565b6001600160a01b0316146113bb576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b8151835181146113f7576040517f88adebd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815b8015611444578461140d600183613413565b8151811061141d5761141d6135a0565b60200260200101518261143091906135cf565b91508061143c816135e2565b9150506113fb565b5060075481111561148f576007546040517f016c69db000000000000000000000000000000000000000000000000000000008152610ac5918391600401918252602082015260400190565b600780548290039055815b80156114ea578080600190039150506114e58682815181106114be576114be6135a0565b60200260200101518683815181106114d8576114d86135a0565b60200260200101516127a1565b61149a565b505050505050565b33806115066002546001600160a01b031690565b6001600160a01b031614611551576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b6113038261289f565b60006001600160a01b03821661157257506000919050565b60008060015b6006548110156115ff5761158b81612335565b156115ef576000818152601260205260409020546001600160a01b0316156115c8576000818152601260205260409020546001600160a01b031691505b816001600160a01b0316856001600160a01b0316036115ef57826115eb81613426565b9350505b6115f881613426565b9050611578565b50909392505050565b60006001600654610c779190613413565b338061162d6002546001600160a01b031690565b6001600160a01b031614611678576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555050565b82806000036116ea576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805474010000000000000000000000000000000000000000900460ff1690811480159061171d575060ff8116600314155b15611757576040517f81d1489b00000000000000000000000000000000000000000000000000000000815260026004820152602401610ac5565b336004858588600061176b86868686610c7c565b9050818110156117b2576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b60006117bc611608565b600754600a546117cc9190613413565b6117d69190613413565b9050808c111561181c576040517f9abbab07000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610ac5565b600c5460009061182c908e613617565b9050348114611870576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b3360009081527f3eec716f11ba9e820c81ca75eb978ffb45831ef8b7a53e5e422c26008e1ca6d56020526040902080548e0190555b6118af338e6127a1565b50505050505050505050505050565b606060096005018054610a0190613397565b336001600160a01b03831681900361191f576040517ff2b21e1c0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ac5565b6001600160a01b0381811660008181526011602090815260408083209488168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001687151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6119b5848484610db4565b6119c1848484846129e0565b61117e576040517f015be56a0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ac5565b606081611a0e81612335565b611a47576040517f1cf4d9a400000000000000000000000000000000000000000000000000000000815260048101829052602401610ac5565b600060088054611a5690613397565b905011611a6b57611a6683612b49565b611355565b6008611a7684612b49565b604051602001611a8792919061362e565b604051602081830303815290604052915050919050565b60038181548110611aae57600080fd5b6000918252602090912001546001600160a01b0316905081565b8280600003611b03576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460039074010000000000000000000000000000000000000000900460ff168114611b7c576002546040517f81d1489b0000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910460ff166004820152602401610ac5565b3360038585886000611b9086868686610c7c565b905081811015611bd7576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b6000611be1611608565b600754600a54611bf19190613413565b611bfb9190613413565b9050808c1115611c41576040517f9abbab07000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610ac5565b600c54600090611c51908e613617565b9050348114611c95576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b3360009081527fa9bc9a3a348c357ba16b37005d7e6b3236198c0e939f4af8c5f19b8deeb8ebc06020526040902080548e0190556118a5565b3380611ce26002546001600160a01b031690565b6001600160a01b031614611d2d576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b61119f8383612c7e565b3380611d4b6002546001600160a01b031690565b6001600160a01b031614611d96576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b61130382612d02565b8080600003611dda576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460019074010000000000000000000000000000000000000000900460ff168114611e53576002546040517f81d1489b0000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910460ff166004820152602401610ac5565b600954831115611e9d576009546040517f5aaca4e4000000000000000000000000000000000000000000000000000000008152610ac5918591600401918252602082015260400190565b6000611ea7611608565b600754600a54611eb79190613413565b611ec19190613413565b905080841115611f07576040517f9abbab070000000000000000000000000000000000000000000000000000000081526004810185905260248101829052604401610ac5565b600b54600090611f179086613617565b9050348114611f5b576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b611f6533866127a1565b5050505050565b3380611f806002546001600160a01b031690565b6001600160a01b031614611fcb576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b50600f80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b338061201a6002546001600160a01b031690565b6001600160a01b031614612065576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b600280546001600160a01b038481167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b33806120e46002546001600160a01b031690565b6001600160a01b03161461212f576040517f55932a1b0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401610ac5565b50600b91909155600c55565b8280600003612176576040517f7fcfed3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805474010000000000000000000000000000000000000000900460ff169081148015906121a9575060ff8116600314155b156121e3576040517f81d1489b00000000000000000000000000000000000000000000000000000000815260026004820152602401610ac5565b33600285858860006121f786868686610c7c565b90508181101561223e576040517ff9790dfd0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b6000612248611608565b600754600a546122589190613413565b6122629190613413565b9050808c11156122a8576040517f9abbab07000000000000000000000000000000000000000000000000000000008152600481018d905260248101829052604401610ac5565b600c546000906122b8908e613617565b90503481146122fc576040517ff01adace00000000000000000000000000000000000000000000000000000000815234600482015260248101829052604401610ac5565b3360009081527f89832631fb3c3307a103ba2c84ab569c64d6182a18893dcd163f0f1c2090733a6020526040902080548e0190556118a5565b60008160000361234757506000919050565b506006541190565b60008181526012602052604081205482906001600160a01b03165b6001600160a01b0381166113555781612382816135e2565b6000818152601260205260409020549093506001600160a01b0316915061236a9050565b600080846001600160a01b0316846001600160a01b031614806123e257506123cd83610a84565b6001600160a01b0316846001600160a01b0316145b8061241257506001600160a01b0380861660009081526011602090815260408083209388168352929052205460ff165b95945050505050565b6000610c77611608565b6040805160ff851660208201529081018390526001600160a01b038516606082015260009081906080016040516020818303038152906040528051906020012090506000600182856040015186600001518760200151604051600081526020016040526040516124b1949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa1580156124d3573d6000803e3d6000fd5b5050604051601f1901516004546001600160a01b0390811691161498975050505050505050565b600081815260106020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001821161253d576001612548565b612548600183613413565b905060006125578360016135cf565b90506000838310801561256e575061256e83612335565b801561258f57506000838152601260205260409020546001600160a01b0316155b9050600061259c83612335565b80156125bd57506000838152601260205260409020546001600160a01b0316155b9050811561260557600084815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389161790555b801561264b57600083815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389161790555b60008581526012602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a811691821790925591518893918b16917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a450505050505050565b6000808215806126d35750600054155b156126ed5750506001546001600160a01b0316600061271c565b6000612710846000546127009190613617565b61270a9190613702565b6001546001600160a01b031693509150505b9250929050565b6002805460ff838116740100000000000000000000000000000000000000008181027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff85161790945560405193909204169182907f7285522ec93a20dcefa1a1d057094a227073a5463b91c0c19a23c6ef5c9c1fe490600090a35050565b60065460006127b083836135cf565b905060006127bf600183613413565b600084815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03881617905590508281111561284857600081815260126020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0387161790555b6006829055825b828110156114ea5760405181906001600160a01b038816906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a461289881613426565b905061284f565b60035480801561119f57808060019003915050826001600160a01b0316600382815481106128cf576128cf6135a0565b6000918252602090912001546001600160a01b03160361119f57816128f58260016135cf565b14612972576003612907600184613413565b81548110612917576129176135a0565b600091825260209091200154600380546001600160a01b039092169183908110612943576129436135a0565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600380548061298357612983613716565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505050565b6000833b8015612b3f576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0386169063150b7a0290612a359033908a9089908990600401613745565b6020604051808303816000875af1925050508015612a70575060408051601f3d908101601f19168201909252612a6d91810190613781565b60015b612af2573d808015612a9e576040519150601f19603f3d011682016040523d82523d6000602084013e612aa3565b606091505b508051600003612aea576040517f015be56a0000000000000000000000000000000000000000000000000000000081526001600160a01b0387166004820152602401610ac5565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149150610dac9050565b6001915050610dac565b606081600003612b8c57505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b8115612bb65780612ba081613426565b9150612baf9050600a83613702565b9150612b90565b60008167ffffffffffffffff811115612bd157612bd1612ee1565b6040519080825280601f01601f191660200182016040528015612bfb576020820181803683370190505b5090505b8415610dac57612c10600183613413565b9150612c1d600a8661379e565b612c289060306135cf565b60f81b818381518110612c3d57612c3d6135a0565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350612c77600a86613702565b9450612bff565b612710811115612cc5576040517f4ec3fd3a000000000000000000000000000000000000000000000000000000008152600481018290526127106024820152604401610ac5565b600055600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6003545b8015612d5557808060019003915050816001600160a01b031660038281548110612d3257612d326135a0565b6000918252602090912001546001600160a01b031603612d50575050565b612d06565b50600380546001810182556000919091527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b0180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114612dee57600080fd5b50565b600060208284031215612e0357600080fd5b813561135581612dc0565b60005b83811015612e29578181015183820152602001612e11565b50506000910152565b60008151808452612e4a816020860160208601612e0e565b601f01601f19169290920160200192915050565b6020815260006113556020830184612e32565b600060208284031215612e8357600080fd5b5035919050565b80356001600160a01b0381168114612ea157600080fd5b919050565b60008060408385031215612eb957600080fd5b612ec283612e8a565b946020939093013593505050565b803560ff81168114612ea157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715612f3957612f39612ee1565b604052919050565b600060608284031215612f5357600080fd5b6040516060810181811067ffffffffffffffff82111715612f7657612f76612ee1565b80604052508091508235815260208301356020820152612f9860408401612ed0565b60408201525092915050565b60008060008060c08587031215612fba57600080fd5b612fc385612e8a565b9350612fd160208601612ed0565b925060408501359150612fe78660608701612f41565b905092959194509250565b60008060006060848603121561300757600080fd5b61301084612e8a565b925061301e60208501612e8a565b9150604084013590509250925092565b6000806040838503121561304157600080fd5b50508035926020909101359150565b600067ffffffffffffffff83111561306a5761306a612ee1565b61307d6020601f19601f86011601612f10565b905082815283838301111561309157600080fd5b828260208301376000602084830101529392505050565b6000602082840312156130ba57600080fd5b813567ffffffffffffffff8111156130d157600080fd5b8201601f810184136130e257600080fd5b610dac84823560208401613050565b60006020828403121561310357600080fd5b61135582612ed0565b600067ffffffffffffffff82111561312657613126612ee1565b5060051b60200190565b600082601f83011261314157600080fd5b813560206131566131518361310c565b612f10565b82815260059290921b8401810191818101908684111561317557600080fd5b8286015b848110156131905780358352918301918301613179565b509695505050505050565b600080604083850312156131ae57600080fd5b823567ffffffffffffffff808211156131c657600080fd5b818501915085601f8301126131da57600080fd5b813560206131ea6131518361310c565b82815260059290921b8401810191818101908984111561320957600080fd5b948201945b8386101561322e5761321f86612e8a565b8252948201949082019061320e565b9650508601359250508082111561324457600080fd5b5061325185828601613130565b9150509250929050565b60006020828403121561326d57600080fd5b61135582612e8a565b600080600060a0848603121561328b57600080fd5b83359250602084013591506132a38560408601612f41565b90509250925092565b600080604083850312156132bf57600080fd5b6132c883612e8a565b9150602083013580151581146132dd57600080fd5b809150509250929050565b600080600080608085870312156132fe57600080fd5b61330785612e8a565b935061331560208601612e8a565b925060408501359150606085013567ffffffffffffffff81111561333857600080fd5b8501601f8101871361334957600080fd5b61335887823560208401613050565b91505092959194509250565b6000806040838503121561337757600080fd5b61338083612e8a565b915061338e60208401612e8a565b90509250929050565b600181811c908216806133ab57607f821691505b602082108103610ae9577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156109e9576109e96133e4565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613457576134576133e4565b5060010190565b601f82111561119f57600081815260208120601f850160051c810160208610156134855750805b601f850160051c820191505b818110156114ea57828155600101613491565b815167ffffffffffffffff8111156134be576134be612ee1565b6134d2816134cc8454613397565b8461345e565b602080601f83116001811461352557600084156134ef5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556114ea565b600085815260208120601f198616915b8281101561355457888601518255948401946001909101908401613535565b508582101561359057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b808201808211156109e9576109e96133e4565b6000816135f1576135f16133e4565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b80820281158282048414176109e9576109e96133e4565b600080845461363c81613397565b600182811680156136545760018114613687576136b6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506136b6565b8860005260208060002060005b858110156136ad5781548a820152908401908201613694565b50505082870194505b5050505083516136ca818360208801612e0e565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082613711576137116136d3565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b60006001600160a01b038087168352808616602084015250836040830152608060608301526137776080830184612e32565b9695505050505050565b60006020828403121561379357600080fd5b815161135581612dc0565b6000826137ad576137ad6136d3565b50069056fea264697066735822122021de66c5fe474d20aac363c752bb1d02980438178ac105c1eb6fb63f5363ae5864736f6c63430008110033

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 Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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.