Arbitrum OneArbitrum One
0x64...BcdB
Cubhub

Cubhub

CUB

收藏品
底价
0.004 ETH
$2,345.34
大小
1,000
收藏品
所有者
525
53% 独特的所有者
此合同的源代码已经过验证!
合同元数据
编译器
0.8.19+commit.7dd6d404
语言
Solidity
合同源代码
文件 1 的 1:Cubhub.sol
  // SPDX-License-Identifier: MIT 

  // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
  
  // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Interface of the ERC20 standard as defined in the EIP.
   */
  interface IERC20 {
      /**
       * @dev Emitted when "value" tokens are moved from one account ("from") to
       * another ("to").
       *
       * Note that "value" may be zero.
       */
      event Transfer(address indexed from, address indexed to, uint256 value);
  
      /**
       * @dev Emitted when the allowance of a "spender" for an "owner" is set by
       * a call to {approve}. "value" is the new allowance.
       */
      event Approval(
          address indexed owner,
          address indexed spender,
          uint256 value
      );
  
      /**
       * @dev Returns the amount of tokens in existence.
       */
      function totalSupply() external view returns (uint256);
  
      /**
       * @dev Returns the amount of tokens owned by "account".
       */
      function balanceOf(address account) external view returns (uint256);
  
      /**
       * @dev Moves "amount" tokens from the caller's account to "to".
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transfer(address to, uint256 amount) external returns (bool);
  
      /**
       * @dev Returns the remaining number of tokens that "spender" will be
       * allowed to spend on behalf of "owner" through {transferFrom}. This is
       * zero by default.
       *
       * This value changes when {approve} or {transferFrom} are called.
       */
      function allowance(address owner, address spender)
          external
          view
          returns (uint256);
  
      /**
       * @dev Sets "amount" as the allowance of "spender" over the caller's tokens.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * IMPORTANT: Beware that changing an allowance with this method brings the risk
       * that someone may use both the old and the new allowance by unfortunate
       * transaction ordering. One possible solution to mitigate this race
       * condition is to first reduce the spender's allowance to 0 and set the
       * desired value afterwards:
       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
       *
       * Emits an {Approval} event.
       */
      function approve(address spender, uint256 amount) external returns (bool);
  
      /**
       * @dev Moves "amount" tokens from "from" to "to" using the
       * allowance mechanism. "amount" is then deducted from the caller's
       * allowance.
       *
       * Returns a boolean value indicating whether the operation succeeded.
       *
       * Emits a {Transfer} event.
       */
      function transferFrom(
          address from,
          address to,
          uint256 amount
      ) external returns (bool);
  }
  
  // File: @openzeppelin/contracts/utils/introspection/IERC165.sol
  
  // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Interface of the ERC165 standard, as defined in the
   * https://eips.ethereum.org/EIPS/eip-165[EIP].
   *
   * Implementers can declare support of contract interfaces, which can then be
   * queried by others ({ERC165Checker}).
   *
   * For an implementation, see {ERC165}.
   */
  interface IERC165 {
      /**
       * @dev Returns true if this contract implements the interface defined by
       * "interfaceId". See the corresponding
       * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
       * to learn more about how these ids are created.
       *
       * This function call must use less than 30 000 gas.
       */
      function supportsInterface(bytes4 interfaceId) external view returns (bool);
  }
  
  // File: @openzeppelin/contracts/utils/introspection/ERC165.sol
  
  // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Implementation of the {IERC165} interface.
   *
   * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
   * for the additional interface id that will be supported. For example:
   *
   * """solidity
   * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
   *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
   * }
   * """
   *
   * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
   */
  abstract contract ERC165 is IERC165 {
      /**
       * @dev See {IERC165-supportsInterface}.
       */
      function supportsInterface(bytes4 interfaceId)
          public
          view
          virtual
          override
          returns (bool)
      {
          return interfaceId == type(IERC165).interfaceId;
      }
  }
  
  // File: @openzeppelin/contracts/interfaces/IERC2981.sol
  
  // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Interface for the NFT Royalty Standard.
   *
   * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
   * support for royalty payments across all NFT marketplaces and ecosystem participants.
   *
   * _Available since v4.5._
   */
  interface IERC2981 is IERC165 {
      /**
       * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
       * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
       */
      function royaltyInfo(uint256 tokenId, uint256 salePrice)
          external
          view
          returns (address receiver, uint256 royaltyAmount);
  }
  

   // File: @openzeppelin/contracts/token/common/ERC2981.sol
  
  // OpenZeppelin Contracts (last updated v4.9.0) (token/common/ERC2981.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
   *
   * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
   * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
   *
   * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
   * fee is specified in basis points by default.
   *
   * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
   * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
   * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
   *
   * _Available since v4.5._
   */
  abstract contract ERC2981 is IERC2981, ERC165 {
      struct RoyaltyInfo {
          address receiver;
          uint96 royaltyFraction;
      }
  
      RoyaltyInfo private _defaultRoyaltyInfo;
      mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
  
      /**
       * @dev See {IERC165-supportsInterface}.
       */
      function supportsInterface(bytes4 interfaceId)
          public
          view
          virtual
          override(IERC165, ERC165)
          returns (bool)
      {
          return
              interfaceId == type(IERC2981).interfaceId ||
              super.supportsInterface(interfaceId);
      }
  
      /**
       * @inheritdoc IERC2981
       */
      function royaltyInfo(uint256 tokenId, uint256 salePrice)
          public
          view
          virtual
          override
          returns (address, uint256)
      {
          RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId];
  
          if (royalty.receiver == address(0)) {
              royalty = _defaultRoyaltyInfo;
          }
  
          uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) /
              _feeDenominator();
  
          return (royalty.receiver, royaltyAmount);
      }
  
      /**
       * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
       * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
       * override.
       */
      function _feeDenominator() internal pure virtual returns (uint96) {
          return 10000;
      }
  
      /**
       * @dev Sets the royalty information that all ids in this contract will default to.
       *
       * Requirements:
       *
       * - "receiver" cannot be the zero address.
       * - "feeNumerator" cannot be greater than the fee denominator.
       */
      function _setDefaultRoyalty(address receiver, uint96 feeNumerator)
          internal
          virtual
      {
          require(
              feeNumerator <= _feeDenominator(),
              "ERC2981: royalty fee will exceed salePrice"
          );
          require(receiver != address(0), "ERC2981: invalid receiver");
  
          _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
      }
  
      /**
       * @dev Removes default royalty information.
       */
      function _deleteDefaultRoyalty() internal virtual {
          delete _defaultRoyaltyInfo;
      }
  
      /**
       * @dev Sets the royalty information for a specific token id, overriding the global default.
       *
       * Requirements:
       *
       * - "receiver" cannot be the zero address.
       * - "feeNumerator" cannot be greater than the fee denominator.
       */
      function _setTokenRoyalty(
          uint256 tokenId,
          address receiver,
          uint96 feeNumerator
      ) internal virtual {
          require(
              feeNumerator <= _feeDenominator(),
              "ERC2981: royalty fee will exceed salePrice"
          );
          require(receiver != address(0), "ERC2981: Invalid parameters");
  
          _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
      }
  
      /**
       * @dev Resets royalty information for the token id back to the global default.
       */
      function _resetTokenRoyalty(uint256 tokenId) internal virtual {
          delete _tokenRoyaltyInfo[tokenId];
      }
  }
  
  // File: @openzeppelin/contracts/utils/Context.sol
  
  // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Provides information about the current execution context, including the
   * sender of the transaction and its data. While these are generally available
   * via msg.sender and msg.data, they should not be accessed in such a direct
   * manner, since when dealing with meta-transactions the account sending and
   * paying for execution may not be the actual sender (as far as an application
   * is concerned).
   *
   * This contract is only required for intermediate, library-like contracts.
   */
  abstract contract Context {
      function _msgSender() internal view virtual returns (address) {
          return msg.sender;
      }
  
      function _msgData() internal view virtual returns (bytes calldata) {
          return msg.data;
      }
  }
  
  // File: @openzeppelin/contracts/access/Ownable.sol
  
  // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
  
  pragma solidity ^0.8.0;
  
  /**
   * @dev Contract module which provides a basic access control mechanism, where
   * there is an account (an owner) that can be granted exclusive access to
   * specific functions.
   *
   * By default, the owner account will be the one that deploys the contract. This
   * can later be changed with {transferOwnership}.
   *
   * This module is used through inheritance. It will make available the modifier
   * "onlyOwner", which can be applied to your functions to restrict their use to
   * the owner.
   */
  abstract contract Ownable is Context {
      address private _owner;
  
      event OwnershipTransferred(
          address indexed previousOwner,
          address indexed newOwner
      );
  
      /**
       * @dev Initializes the contract setting the deployer as the initial owner.
       */
      constructor() {
          _transferOwnership(_msgSender());
      }
  
      /**
       * @dev Throws if called by any account other than the owner.
       */
      modifier onlyOwner() {
          _checkOwner();
          _;
      }
  
      /**
       * @dev Returns the address of the current owner.
       */
      function owner() public view virtual returns (address) {
          return _owner;
      }
  
      /**
       * @dev Throws if the sender is not the owner.
       */
      function _checkOwner() internal view virtual {
          require(owner() == _msgSender(), "Ownable: caller is not the owner");
      }
  
      /**
       * @dev Leaves the contract without owner. It will not be possible to call
       * "onlyOwner" functions. Can only be called by the current owner.
       *
       * NOTE: Renouncing ownership will leave the contract without an owner,
       * thereby disabling any functionality that is only available to the owner.
       */
      function renounceOwnership() public virtual onlyOwner {
          _transferOwnership(address(0));
      }
  
      /**
       * @dev Transfers ownership of the contract to a new account ("newOwner").
       * Can only be called by the current owner.
       */
      function transferOwnership(address newOwner) public virtual onlyOwner {
          require(
              newOwner != address(0),
              "Ownable: new owner is the zero address"
          );
          _transferOwnership(newOwner);
      }
  
      /**
       * @dev Transfers ownership of the contract to a new account ("newOwner").
       * Internal function without access restriction.
       */
      function _transferOwnership(address newOwner) internal virtual {
          address oldOwner = _owner;
          _owner = newOwner;
          emit OwnershipTransferred(oldOwner, newOwner);
      }
  }
  
  // File: erc721a/contracts/IERC721A.sol
  
  // ERC721A Contracts v4.2.3
  // Creator: Chiru Labs
  
  pragma solidity ^0.8.4;
  
  /**
   * @dev Interface of ERC721A.
   */
  interface IERC721A {
      /**
       * The caller must own the token or be an approved operator.
       */
      error ApprovalCallerNotOwnerNorApproved();
  
      /**
       * The token does not exist.
       */
      error ApprovalQueryForNonexistentToken();
  
      /**
       * Cannot query the balance for the zero address.
       */
      error BalanceQueryForZeroAddress();
  
      /**
       * Cannot mint to the zero address.
       */
      error MintToZeroAddress();
  
      /**
       * The quantity of tokens minted must be more than zero.
       */
      error MintZeroQuantity();
  
      /**
       * The token does not exist.
       */
      error OwnerQueryForNonexistentToken();
  
      /**
       * The caller must own the token or be an approved operator.
       */
      error TransferCallerNotOwnerNorApproved();
  
      /**
       * The token must be owned by "from".
       */
      error TransferFromIncorrectOwner();
  
      /**
       * Cannot safely transfer to a contract that does not implement the
       * ERC721Receiver interface.
       */
      error TransferToNonERC721ReceiverImplementer();
  
      /**
       * Cannot transfer to the zero address.
       */
      error TransferToZeroAddress();
  
      /**
       * The token does not exist.
       */
      error URIQueryForNonexistentToken();
  
      /**
       * The "quantity" minted with ERC2309 exceeds the safety limit.
       */
      error MintERC2309QuantityExceedsLimit();
  
      /**
       * The "extraData" cannot be set on an unintialized ownership slot.
       */
      error OwnershipNotInitializedForExtraData();
  
      // =============================================================
      //                            STRUCTS
      // =============================================================
  
      struct TokenOwnership {
          // The address of the owner.
          address addr;
          // Stores the start time of ownership with minimal overhead for tokenomics.
          uint64 startTimestamp;
          // Whether the token has been burned.
          bool burned;
          // Arbitrary data similar to "startTimestamp" that can be set via {_extraData}.
          uint24 extraData;
      }
  
      // =============================================================
      //                         TOKEN COUNTERS
      // =============================================================
  
      /**
       * @dev Returns the total number of tokens in existence.
       * Burned tokens will reduce the count.
       * To get the total number of tokens minted, please see {_totalMinted}.
       */
      function totalSupply() external view returns (uint256);
  
      // =============================================================
      //                            IERC165
      // =============================================================
  
      /**
       * @dev Returns true if this contract implements the interface defined by
       * "interfaceId". See the corresponding
       * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
       * to learn more about how these ids are created.
       *
       * This function call must use less than 30000 gas.
       */
      function supportsInterface(bytes4 interfaceId) external view returns (bool);
  
      // =============================================================
      //                            IERC721
      // =============================================================
  
      /**
       * @dev Emitted when "tokenId" token is transferred from "from" to "to".
       */
      event Transfer(
          address indexed from,
          address indexed to,
          uint256 indexed tokenId
      );
  
      /**
       * @dev Emitted when "owner" enables "approved" to manage the "tokenId" token.
       */
      event Approval(
          address indexed owner,
          address indexed approved,
          uint256 indexed tokenId
      );
  
      /**
       * @dev Emitted when "owner" enables or disables
       * ("approved") "operator" to manage all of its assets.
       */
      event ApprovalForAll(
          address indexed owner,
          address indexed operator,
          bool approved
      );
  
      /**
       * @dev Returns the number of tokens in "owner"'s account.
       */
      function balanceOf(address owner) external view returns (uint256 balance);
  
      /**
       * @dev Returns the owner of the "tokenId" token.
       *
       * Requirements:
       *
       * - "tokenId" must exist.
       */
      function ownerOf(uint256 tokenId) external view returns (address owner);
  
      /**
       * @dev Safely transfers "tokenId" token from "from" to "to",
       * checking first that contract recipients are aware of the ERC721 protocol
       * to prevent tokens from being forever locked.
       *
       * Requirements:
       *
       * - "from" cannot be the zero address.
       * - "to" cannot be the zero address.
       * - "tokenId" token must exist and be owned by "from".
       * - If the caller is not "from", it must be have been allowed to move
       * this token by either {approve} or {setApprovalForAll}.
       * - If "to" refers to a smart contract, it must implement
       * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
       *
       * Emits a {Transfer} event.
       */
      function safeTransferFrom(
          address from,
          address to,
          uint256 tokenId,
          bytes calldata data
      ) external payable;
  
      /**
       * @dev Equivalent to "safeTransferFrom(from, to, tokenId, '')".
       */
      function safeTransferFrom(
          address from,
          address to,
          uint256 tokenId
      ) external payable;
  
      /**
       * @dev Transfers "tokenId" from "from" to "to".
       *
       * WARNING: Usage of this method is discouraged, use {safeTransferFrom}
       * whenever possible.
       *
       * Requirements:
       *
       * - "from" cannot be the zero address.
       * - "to" cannot be the zero address.
       * - "tokenId" token must be owned by "from".
       * - If the caller is not "from", it must be approved to move this token
       * by either {approve} or {setApprovalForAll}.
       *
       * Emits a {Transfer} event.
       */
      function transferFrom(
          address from,
          address to,
          uint256 tokenId
      ) external payable;
  
      /**
       * @dev Gives permission to "to" to transfer "tokenId" token to another account.
       * The approval is cleared when the token is transferred.
       *
       * Only a single account can be approved at a time, so approving the
       * zero address clears previous approvals.
       *
       * Requirements:
       *
       * - The caller must own the token or be an approved operator.
       * - "tokenId" must exist.
       *
       * Emits an {Approval} event.
       */
      function approve(address to, uint256 tokenId) external payable;
  
      /**
       * @dev Approve or remove "operator" as an operator for the caller.
       * Operators can call {transferFrom} or {safeTransferFrom}
       * for any token owned by the caller.
       *
       * Requirements:
       *
       * - The "operator" cannot be the caller.
       *
       * Emits an {ApprovalForAll} event.
       */
      function setApprovalForAll(address operator, bool _approved) external;
  
      /**
       * @dev Returns the account approved for "tokenId" token.
       *
       * Requirements:
       *
       * - "tokenId" must exist.
       */
      function getApproved(uint256 tokenId)
          external
          view
          returns (address operator);
  
      /**
       * @dev Returns if the "operator" is allowed to manage all of the assets of "owner".
       *
       * See {setApprovalForAll}.
       */
      function isApprovedForAll(address owner, address operator)
          external
          view
          returns (bool);
  
      // =============================================================
      //                        IERC721Metadata
      // =============================================================
  
      /**
       * @dev Returns the token collection name.
       */
      function name() external view returns (string memory);
  
      /**
       * @dev Returns the token collection symbol.
       */
      function symbol() external view returns (string memory);
  
      /**
       * @dev Returns the Uniform Resource Identifier (URI) for "tokenId" token.
       */
      function tokenURI(uint256 tokenId) external view returns (string memory);
  
      // =============================================================
      //                           IERC2309
      // =============================================================
  
      /**
       * @dev Emitted when tokens in "fromTokenId" to "toTokenId"
       * (inclusive) is transferred from "from" to "to", as defined in the
       * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
       *
       * See {_mintERC2309} for more details.
       */
      event ConsecutiveTransfer(
          uint256 indexed fromTokenId,
          uint256 toTokenId,
          address indexed from,
          address indexed to
      );
  }
  
  // File: erc721a/contracts/ERC721A.sol
  
  // ERC721A Contracts v4.2.3
  // Creator: Chiru Labs
  
  pragma solidity ^0.8.4;
  
  /**
   * @dev Interface of ERC721 token receiver.
   */
  interface ERC721A__IERC721Receiver {
      function onERC721Received(
          address operator,
          address from,
          uint256 tokenId,
          bytes calldata data
      ) external returns (bytes4);
  }
  
  /**
   * @title ERC721A
   *
   * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
   * Non-Fungible Token Standard, including the Metadata extension.
   * Optimized for lower gas during batch mints.
   *
   * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
   * starting from "_startTokenId()".
   *
   * Assumptions:
   *
   * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
   * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
   */
  contract ERC721A is IERC721A {
      // Bypass for a "--via-ir" bug (https://github.com/chiru-labs/ERC721A/pull/364).
      struct TokenApprovalRef {
          address value;
      }
  
      // =============================================================
      //                           CONSTANTS
      // =============================================================
  
      // Mask of an entry in packed address data.
      uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
  
      // The bit position of "numberMinted" in packed address data.
      uint256 private constant _BITPOS_NUMBER_MINTED = 64;
  
      // The bit position of "numberBurned" in packed address data.
      uint256 private constant _BITPOS_NUMBER_BURNED = 128;
  
      // The bit position of "aux" in packed address data.
      uint256 private constant _BITPOS_AUX = 192;
  
      // Mask of all 256 bits in packed address data except the 64 bits for "aux".
      uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
  
      // The bit position of "startTimestamp" in packed ownership.
      uint256 private constant _BITPOS_START_TIMESTAMP = 160;
  
      // The bit mask of the "burned" bit in packed ownership.
      uint256 private constant _BITMASK_BURNED = 1 << 224;
  
      // The bit position of the "nextInitialized" bit in packed ownership.
      uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
  
      // The bit mask of the "nextInitialized" bit in packed ownership.
      uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
  
      // The bit position of "extraData" in packed ownership.
      uint256 private constant _BITPOS_EXTRA_DATA = 232;
  
      // Mask of all 256 bits in a packed ownership except the 24 bits for "extraData".
      uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
  
      // The mask of the lower 160 bits for addresses.
      uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
  
      // The maximum "quantity" that can be minted with {_mintERC2309}.
      // This limit is to prevent overflows on the address data entries.
      // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
      // is required to cause an overflow, which is unrealistic.
      uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
  
      // The "Transfer" event signature is given by:
      // "keccak256(bytes("Transfer(address,address,uint256)"))".
      bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
          0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
  
      // =============================================================
      //                            STORAGE
      // =============================================================
  
      // The next token ID to be minted.
      uint256 private _currentIndex;
  
      // The number of tokens burned.
      uint256 private _burnCounter;
  
      // Token name
      string private _name;
  
      // Token symbol
      string private _symbol;
  
      // Mapping from token ID to ownership details
      // An empty struct value does not necessarily mean the token is unowned.
      // See {_packedOwnershipOf} implementation for details.
      //
      // Bits Layout:
      // - [0..159]   "addr"
      // - [160..223] "startTimestamp"
      // - [224]      "burned"
      // - [225]      "nextInitialized"
      // - [232..255] "extraData"
      mapping(uint256 => uint256) private _packedOwnerships;
  
      // Mapping owner address to address data.
      //
      // Bits Layout:
      // - [0..63]    "balance"
      // - [64..127]  "numberMinted"
      // - [128..191] "numberBurned"
      // - [192..255] "aux"
      mapping(address => uint256) private _packedAddressData;
  
      // Mapping from token ID to approved address.
      mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
  
      // Mapping from owner to operator approvals
      mapping(address => mapping(address => bool)) private _operatorApprovals;
  
      // =============================================================
      //                          CONSTRUCTOR
      // =============================================================
  
      constructor(string memory name_, string memory symbol_) {
          _name = name_;
          _symbol = symbol_;
          _currentIndex = _startTokenId();
      }
  
      // =============================================================
      //                   TOKEN COUNTING OPERATIONS
      // =============================================================
  
      /**
       * @dev Returns the starting token ID.
       * To change the starting token ID, please override this function.
       */
      function _startTokenId() internal view virtual returns (uint256) {
          return 0;
      }
  
      /**
       * @dev Returns the next token ID to be minted.
       */
      function _nextTokenId() internal view virtual returns (uint256) {
          return _currentIndex;
      }
  
      /**
       * @dev Returns the total number of tokens in existence.
       * Burned tokens will reduce the count.
       * To get the total number of tokens minted, please see {_totalMinted}.
       */
      function totalSupply() public view virtual override returns (uint256) {
          // Counter underflow is impossible as _burnCounter cannot be incremented
          // more than "_currentIndex - _startTokenId()" times.
          unchecked {
              return _currentIndex - _burnCounter - _startTokenId();
          }
      }
  
      /**
       * @dev Returns the total amount of tokens minted in the contract.
       */
      function _totalMinted() internal view virtual returns (uint256) {
          // Counter underflow is impossible as "_currentIndex" does not decrement,
          // and it is initialized to "_startTokenId()".
          unchecked {
              return _currentIndex - _startTokenId();
          }
      }
  
      /**
       * @dev Returns the total number of tokens burned.
       */
      function _totalBurned() internal view virtual returns (uint256) {
          return _burnCounter;
      }
  
      // =============================================================
      //                    ADDRESS DATA OPERATIONS
      // =============================================================
  
      /**
       * @dev Returns the number of tokens in "owner"'s account.
       */
      function balanceOf(address owner)
          public
          view
          virtual
          override
          returns (uint256)
      {
          if (owner == address(0)) revert BalanceQueryForZeroAddress();
          return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
      }
  
      /**
       * Returns the number of tokens minted by "owner".
       */
      function _numberMinted(address owner) internal view returns (uint256) {
          return
              (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) &
              _BITMASK_ADDRESS_DATA_ENTRY;
      }
  
      /**
       * Returns the number of tokens burned by or on behalf of "owner".
       */
      function _numberBurned(address owner) internal view returns (uint256) {
          return
              (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) &
              _BITMASK_ADDRESS_DATA_ENTRY;
      }
  
      /**
       * Returns the auxiliary data for "owner". (e.g. number of whitelist mint slots used).
       */
      function _getAux(address owner) internal view returns (uint64) {
          return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
      }
  
      /**
       * Sets the auxiliary data for "owner". (e.g. number of whitelist mint slots used).
       * If there are multiple variables, please pack them into a uint64.
       */
      function _setAux(address owner, uint64 aux) internal virtual {
          uint256 packed = _packedAddressData[owner];
          uint256 auxCasted;
          // Cast "aux" with assembly to avoid redundant masking.
          assembly {
              auxCasted := aux
          }
          packed =
              (packed & _BITMASK_AUX_COMPLEMENT) |
              (auxCasted << _BITPOS_AUX);
          _packedAddressData[owner] = packed;
      }
  
      // =============================================================
      //                            IERC165
      // =============================================================
  
      /**
       * @dev Returns true if this contract implements the interface defined by
       * "interfaceId". See the corresponding
       * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
       * to learn more about how these ids are created.
       *
       * This function call must use less than 30000 gas.
       */
      function supportsInterface(bytes4 interfaceId)
          public
          view
          virtual
          override
          returns (bool)
      {
          // The interface IDs are constants representing the first 4 bytes
          // of the XOR of all function selectors in the interface.
          // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
          // (e.g. "bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)")
          return
              interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
              interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
              interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
      }
  
      // =============================================================
      //                        IERC721Metadata
      // =============================================================
  
      /**
       * @dev Returns the token collection name.
       */
      function name() public view virtual override returns (string memory) {
          return _name;
      }
  
      /**
       * @dev Returns the token collection symbol.
       */
      function symbol() public view virtual override returns (string memory) {
          return _symbol;
      }
  
      /**
       * @dev Returns the Uniform Resource Identifier (URI) for "tokenId" token.
       */
      function tokenURI(uint256 tokenId)
          public
          view
          virtual
          override
          returns (string memory)
      {
          if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
  
          string memory baseURI = _baseURI();
          return
              bytes(baseURI).length != 0
                  ? string(abi.encodePacked(baseURI, _toString(tokenId)))
                  : "";
      }
  
      /**
       * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
       * token will be the concatenation of the "baseURI" and the "tokenId". Empty
       * by default, it can be overridden in child contracts.
       */
      function _baseURI() internal view virtual returns (string memory) {
          return "";
      }
  
      // =============================================================
      //                     OWNERSHIPS OPERATIONS
      // =============================================================
  
      /**
       * @dev Returns the owner of the "tokenId" token.
       *
       * Requirements:
       *
       * - "tokenId" must exist.
       */
      function ownerOf(uint256 tokenId)
          public
          view
          virtual
          override
          returns (address)
      {
          return address(uint160(_packedOwnershipOf(tokenId)));
      }
  
      /**
       * @dev Gas spent here starts off proportional to the maximum mint batch size.
       * It gradually moves to O(1) as tokens get transferred around over time.
       */
      function _ownershipOf(uint256 tokenId)
          internal
          view
          virtual
          returns (TokenOwnership memory)
      {
          return _unpackedOwnership(_packedOwnershipOf(tokenId));
      }
  
      /**
       * @dev Returns the unpacked "TokenOwnership" struct at "index".
       */
      function _ownershipAt(uint256 index)
          internal
          view
          virtual
          returns (TokenOwnership memory)
      {
          return _unpackedOwnership(_packedOwnerships[index]);
      }
  
      /**
       * @dev Initializes the ownership slot minted at "index" for efficiency purposes.
       */
      function _initializeOwnershipAt(uint256 index) internal virtual {
          if (_packedOwnerships[index] == 0) {
              _packedOwnerships[index] = _packedOwnershipOf(index);
          }
      }
  
      /**
       * Returns the packed ownership data of "tokenId".
       */
      function _packedOwnershipOf(uint256 tokenId)
          private
          view
          returns (uint256)
      {
          uint256 curr = tokenId;
  
          unchecked {
              if (_startTokenId() <= curr)
                  if (curr < _currentIndex) {
                      uint256 packed = _packedOwnerships[curr];
                      // If not burned.
                      if (packed & _BITMASK_BURNED == 0) {
                          // Invariant:
                          // There will always be an initialized ownership slot
                          // (i.e. "ownership.addr != address(0) && ownership.burned == false")
                          // before an unintialized ownership slot
                          // (i.e. "ownership.addr == address(0) && ownership.burned == false")
                          // Hence, "curr" will not underflow.
                          //
                          // We can directly compare the packed value.
                          // If the address is zero, packed will be zero.
                          while (packed == 0) {
                              packed = _packedOwnerships[--curr];
                          }
                          return packed;
                      }
                  }
          }
          revert OwnerQueryForNonexistentToken();
      }
  
      /**
       * @dev Returns the unpacked "TokenOwnership" struct from "packed".
       */
      function _unpackedOwnership(uint256 packed)
          private
          pure
          returns (TokenOwnership memory ownership)
      {
          ownership.addr = address(uint160(packed));
          ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
          ownership.burned = packed & _BITMASK_BURNED != 0;
          ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
      }
  
      /**
       * @dev Packs ownership data into a single uint256.
       */
      function _packOwnershipData(address owner, uint256 flags)
          private
          view
          returns (uint256 result)
      {
          assembly {
              // Mask "owner" to the lower 160 bits, in case the upper bits somehow aren't clean.
              owner := and(owner, _BITMASK_ADDRESS)
              // "owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags".
              result := or(
                  owner,
                  or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)
              )
          }
      }
  
      /**
       * @dev Returns the "nextInitialized" flag set if "quantity" equals 1.
       */
      function _nextInitializedFlag(uint256 quantity)
          private
          pure
          returns (uint256 result)
      {
          // For branchless setting of the "nextInitialized" flag.
          assembly {
              // "(quantity == 1) << _BITPOS_NEXT_INITIALIZED".
              result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
          }
      }
  
      // =============================================================
      //                      APPROVAL OPERATIONS
      // =============================================================
  
      /**
       * @dev Gives permission to "to" to transfer "tokenId" token to another account.
       * The approval is cleared when the token is transferred.
       *
       * Only a single account can be approved at a time, so approving the
       * zero address clears previous approvals.
       *
       * Requirements:
       *
       * - The caller must own the token or be an approved operator.
       * - "tokenId" must exist.
       *
       * Emits an {Approval} event.
       */
      function approve(address to, uint256 tokenId)
          public
          payable
          virtual
          override
      {
          address owner = ownerOf(tokenId);
  
          if (_msgSenderERC721A() != owner)
              if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                  revert ApprovalCallerNotOwnerNorApproved();
              }
  
          _tokenApprovals[tokenId].value = to;
          emit Approval(owner, to, tokenId);
      }
  
      /**
       * @dev Returns the account approved for "tokenId" token.
       *
       * Requirements:
       *
       * - "tokenId" must exist.
       */
      function getApproved(uint256 tokenId)
          public
          view
          virtual
          override
          returns (address)
      {
          if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
  
          return _tokenApprovals[tokenId].value;
      }
  
      /**
       * @dev Approve or remove "operator" as an operator for the caller.
       * Operators can call {transferFrom} or {safeTransferFrom}
       * for any token owned by the caller.
       *
       * Requirements:
       *
       * - The "operator" cannot be the caller.
       *
       * Emits an {ApprovalForAll} event.
       */
      function setApprovalForAll(address operator, bool approved)
          public
          virtual
          override
      {
          _operatorApprovals[_msgSenderERC721A()][operator] = approved;
          emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
      }
  
      /**
       * @dev Returns if the "operator" is allowed to manage all of the assets of "owner".
       *
       * See {setApprovalForAll}.
       */
      function isApprovedForAll(address owner, address operator)
          public
          view
          virtual
          override
          returns (bool)
      {
          return _operatorApprovals[owner][operator];
      }
  
      /**
       * @dev Returns whether "tokenId" exists.
       *
       * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
       *
       * Tokens start existing when they are minted. See {_mint}.
       */
      function _exists(uint256 tokenId) internal view virtual returns (bool) {
          return
              _startTokenId() <= tokenId &&
              tokenId < _currentIndex && // If within bounds,
              _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
      }
  
      /**
       * @dev Returns whether "msgSender" is equal to "approvedAddress" or "owner".
       */
      function _isSenderApprovedOrOwner(
          address approvedAddress,
          address owner,
          address msgSender
      ) private pure returns (bool result) {
          assembly {
              // Mask "owner" to the lower 160 bits, in case the upper bits somehow aren't clean.
              owner := and(owner, _BITMASK_ADDRESS)
              // Mask "msgSender" to the lower 160 bits, in case the upper bits somehow aren't clean.
              msgSender := and(msgSender, _BITMASK_ADDRESS)
              // "msgSender == owner || msgSender == approvedAddress".
              result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
          }
      }
  
      /**
       * @dev Returns the storage slot and value for the approved address of "tokenId".
       */
      function _getApprovedSlotAndAddress(uint256 tokenId)
          private
          view
          returns (uint256 approvedAddressSlot, address approvedAddress)
      {
          TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
          // The following is equivalent to "approvedAddress = _tokenApprovals[tokenId].value".
          assembly {
              approvedAddressSlot := tokenApproval.slot
              approvedAddress := sload(approvedAddressSlot)
          }
      }
  
      // =============================================================
      //                      TRANSFER OPERATIONS
      // =============================================================
  
      /**
       * @dev Transfers "tokenId" from "from" to "to".
       *
       * Requirements:
       *
       * - "from" cannot be the zero address.
       * - "to" cannot be the zero address.
       * - "tokenId" token must be owned by "from".
       * - If the caller is not "from", it must be approved to move this token
       * by either {approve} or {setApprovalForAll}.
       *
       * Emits a {Transfer} event.
       */
      function transferFrom(
          address from,
          address to,
          uint256 tokenId
      ) public payable virtual override {
          uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
  
          if (address(uint160(prevOwnershipPacked)) != from)
              revert TransferFromIncorrectOwner();
  
          (
              uint256 approvedAddressSlot,
              address approvedAddress
          ) = _getApprovedSlotAndAddress(tokenId);
  
          // The nested ifs save around 20+ gas over a compound boolean condition.
          if (
              !_isSenderApprovedOrOwner(
                  approvedAddress,
                  from,
                  _msgSenderERC721A()
              )
          )
              if (!isApprovedForAll(from, _msgSenderERC721A()))
                  revert TransferCallerNotOwnerNorApproved();
  
          if (to == address(0)) revert TransferToZeroAddress();
  
          _beforeTokenTransfers(from, to, tokenId, 1);
  
          // Clear approvals from the previous owner.
          assembly {
              if approvedAddress {
                  // This is equivalent to "delete _tokenApprovals[tokenId]".
                  sstore(approvedAddressSlot, 0)
              }
          }
  
          // Underflow of the sender's balance is impossible because we check for
          // ownership above and the recipient's balance can't realistically overflow.
          // Counter overflow is incredibly unrealistic as "tokenId" would have to be 2**256.
          unchecked {
              // We can directly increment and decrement the balances.
              --_packedAddressData[from]; // Updates: "balance -= 1".
              ++_packedAddressData[to]; // Updates: "balance += 1".
  
              // Updates:
              // - "address" to the next owner.
              // - "startTimestamp" to the timestamp of transfering.
              // - "burned" to "false".
              // - "nextInitialized" to "true".
              _packedOwnerships[tokenId] = _packOwnershipData(
                  to,
                  _BITMASK_NEXT_INITIALIZED |
                      _nextExtraData(from, to, prevOwnershipPacked)
              );
  
              // If the next slot may not have been initialized (i.e. "nextInitialized == false") .
              if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                  uint256 nextTokenId = tokenId + 1;
                  // If the next slot's address is zero and not burned (i.e. packed value is zero).
                  if (_packedOwnerships[nextTokenId] == 0) {
                      // If the next slot is within bounds.
                      if (nextTokenId != _currentIndex) {
                          // Initialize the next slot to maintain correctness for "ownerOf(tokenId + 1)".
                          _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                      }
                  }
              }
          }
  
          emit Transfer(from, to, tokenId);
          _afterTokenTransfers(from, to, tokenId, 1);
      }
  
      /**
       * @dev Equivalent to "safeTransferFrom(from, to, tokenId, '')".
       */
      function safeTransferFrom(
          address from,
          address to,
          uint256 tokenId
      ) public payable virtual override {
          safeTransferFrom(from, to, tokenId, "");
      }
  
      /**
       * @dev Safely transfers "tokenId" token from "from" to "to".
       *
       * Requirements:
       *
       * - "from" cannot be the zero address.
       * - "to" cannot be the zero address.
       * - "tokenId" token must exist and be owned by "from".
       * - If the caller is not "from", it must be approved to move this token
       * by either {approve} or {setApprovalForAll}.
       * - If "to" refers to a smart contract, it must implement
       * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
       *
       * Emits a {Transfer} event.
       */
      function safeTransferFrom(
          address from,
          address to,
          uint256 tokenId,
          bytes memory _data
      ) public payable virtual override {
          transferFrom(from, to, tokenId);
          if (to.code.length != 0)
              if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                  revert TransferToNonERC721ReceiverImplementer();
              }
      }
  
      /**
       * @dev Hook that is called before a set of serially-ordered token IDs
       * are about to be transferred. This includes minting.
       * And also called before burning one token.
       *
       * "startTokenId" - the first token ID to be transferred.
       * "quantity" - the amount to be transferred.
       *
       * Calling conditions:
       *
       * - When "from" and "to" are both non-zero, "from"'s "tokenId" will be
       * transferred to "to".
       * - When "from" is zero, "tokenId" will be minted for "to".
       * - When "to" is zero, "tokenId" will be burned by "from".
       * - "from" and "to" are never both zero.
       */
      function _beforeTokenTransfers(
          address from,
          address to,
          uint256 startTokenId,
          uint256 quantity
      ) internal virtual {}
  
      /**
       * @dev Hook that is called after a set of serially-ordered token IDs
       * have been transferred. This includes minting.
       * And also called after one token has been burned.
       *
       * "startTokenId" - the first token ID to be transferred.
       * "quantity" - the amount to be transferred.
       *
       * Calling conditions:
       *
       * - When "from" and "to" are both non-zero, "from"'s "tokenId" has been
       * transferred to "to".
       * - When "from" is zero, "tokenId" has been minted for "to".
       * - When "to" is zero, "tokenId" has been burned by "from".
       * - "from" and "to" are never both zero.
       */
      function _afterTokenTransfers(
          address from,
          address to,
          uint256 startTokenId,
          uint256 quantity
      ) internal virtual {}
  
      /**
       * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
       *
       * "from" - Previous owner of the given token ID.
       * "to" - Target address that will receive the token.
       * "tokenId" - Token ID to be transferred.
       * "_data" - Optional data to send along with the call.
       *
       * Returns whether the call correctly returned the expected magic value.
       */
      function _checkContractOnERC721Received(
          address from,
          address to,
          uint256 tokenId,
          bytes memory _data
      ) private returns (bool) {
          try
              ERC721A__IERC721Receiver(to).onERC721Received(
                  _msgSenderERC721A(),
                  from,
                  tokenId,
                  _data
              )
          returns (bytes4 retval) {
              return
                  retval ==
                  ERC721A__IERC721Receiver(to).onERC721Received.selector;
          } catch (bytes memory reason) {
              if (reason.length == 0) {
                  revert TransferToNonERC721ReceiverImplementer();
              } else {
                  assembly {
                      revert(add(32, reason), mload(reason))
                  }
              }
          }
      }
  
      // =============================================================
      //                        MINT OPERATIONS
      // =============================================================
  
      /**
       * @dev Mints "quantity" tokens and transfers them to "to".
       *
       * Requirements:
       *
       * - "to" cannot be the zero address.
       * - "quantity" must be greater than 0.
       *
       * Emits a {Transfer} event for each mint.
       */
      function _mint(address to, uint256 quantity) internal virtual {
          uint256 startTokenId = _currentIndex;
          if (quantity == 0) revert MintZeroQuantity();
  
          _beforeTokenTransfers(address(0), to, startTokenId, quantity);
  
          // Overflows are incredibly unrealistic.
          // "balance" and "numberMinted" have a maximum limit of 2**64.
          // "tokenId" has a maximum limit of 2**256.
          unchecked {
              // Updates:
              // - "balance += quantity".
              // - "numberMinted += quantity".
              //
              // We can directly add to the "balance" and "numberMinted".
              _packedAddressData[to] +=
                  quantity *
                  ((1 << _BITPOS_NUMBER_MINTED) | 1);
  
              // Updates:
              // - "address" to the owner.
              // - "startTimestamp" to the timestamp of minting.
              // - "burned" to "false".
              // - "nextInitialized" to "quantity == 1".
              _packedOwnerships[startTokenId] = _packOwnershipData(
                  to,
                  _nextInitializedFlag(quantity) |
                      _nextExtraData(address(0), to, 0)
              );
  
              uint256 toMasked;
              uint256 end = startTokenId + quantity;
  
              // Use assembly to loop and emit the "Transfer" event for gas savings.
              // The duplicated "log4" removes an extra check and reduces stack juggling.
              // The assembly, together with the surrounding Solidity code, have been
              // delicately arranged to nudge the compiler into producing optimized opcodes.
              assembly {
                  // Mask "to" to the lower 160 bits, in case the upper bits somehow aren't clean.
                  toMasked := and(to, _BITMASK_ADDRESS)
                  // Emit the "Transfer" event.
                  log4(
                      0, // Start of data (0, since no data).
                      0, // End of data (0, since no data).
                      _TRANSFER_EVENT_SIGNATURE, // Signature.
                      0, // "address(0)".
                      toMasked, // "to".
                      startTokenId // "tokenId".
                  )
  
                  // The "iszero(eq(,))" check ensures that large values of "quantity"
                  // that overflows uint256 will make the loop run out of gas.
                  // The compiler will optimize the "iszero" away for performance.
                  for {
                      let tokenId := add(startTokenId, 1)
                  } iszero(eq(tokenId, end)) {
                      tokenId := add(tokenId, 1)
                  } {
                      // Emit the "Transfer" event. Similar to above.
                      log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                  }
              }
              if (toMasked == 0) revert MintToZeroAddress();
  
              _currentIndex = end;
          }
          _afterTokenTransfers(address(0), to, startTokenId, quantity);
      }
  
      /**
       * @dev Mints "quantity" tokens and transfers them to "to".
       *
       * This function is intended for efficient minting only during contract creation.
       *
       * It emits only one {ConsecutiveTransfer} as defined in
       * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
       * instead of a sequence of {Transfer} event(s).
       *
       * Calling this function outside of contract creation WILL make your contract
       * non-compliant with the ERC721 standard.
       * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
       * {ConsecutiveTransfer} event is only permissible during contract creation.
       *
       * Requirements:
       *
       * - "to" cannot be the zero address.
       * - "quantity" must be greater than 0.
       *
       * Emits a {ConsecutiveTransfer} event.
       */
      function _mintERC2309(address to, uint256 quantity) internal virtual {
          uint256 startTokenId = _currentIndex;
          if (to == address(0)) revert MintToZeroAddress();
          if (quantity == 0) revert MintZeroQuantity();
          if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT)
              revert MintERC2309QuantityExceedsLimit();
  
          _beforeTokenTransfers(address(0), to, startTokenId, quantity);
  
          // Overflows are unrealistic due to the above check for "quantity" to be below the limit.
          unchecked {
              // Updates:
              // - "balance += quantity".
              // - "numberMinted += quantity".
              //
              // We can directly add to the "balance" and "numberMinted".
              _packedAddressData[to] +=
                  quantity *
                  ((1 << _BITPOS_NUMBER_MINTED) | 1);
  
              // Updates:
              // - "address" to the owner.
              // - "startTimestamp" to the timestamp of minting.
              // - "burned" to "false".
              // - "nextInitialized" to "quantity == 1".
              _packedOwnerships[startTokenId] = _packOwnershipData(
                  to,
                  _nextInitializedFlag(quantity) |
                      _nextExtraData(address(0), to, 0)
              );
  
              emit ConsecutiveTransfer(
                  startTokenId,
                  startTokenId + quantity - 1,
                  address(0),
                  to
              );
  
              _currentIndex = startTokenId + quantity;
          }
          _afterTokenTransfers(address(0), to, startTokenId, quantity);
      }
  
      /**
       * @dev Safely mints "quantity" tokens and transfers them to "to".
       *
       * Requirements:
       *
       * - If "to" refers to a smart contract, it must implement
       * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
       * - "quantity" must be greater than 0.
       *
       * See {_mint}.
       *
       * Emits a {Transfer} event for each mint.
       */
      function _safeMint(
          address to,
          uint256 quantity,
          bytes memory _data
      ) internal virtual {
          _mint(to, quantity);
  
          unchecked {
              if (to.code.length != 0) {
                  uint256 end = _currentIndex;
                  uint256 index = end - quantity;
                  do {
                      if (
                          !_checkContractOnERC721Received(
                              address(0),
                              to,
                              index++,
                              _data
                          )
                      ) {
                          revert TransferToNonERC721ReceiverImplementer();
                      }
                  } while (index < end);
                  // Reentrancy protection.
                  if (_currentIndex != end) revert();
              }
          }
      }
  
      /**
       * @dev Equivalent to "_safeMint(to, quantity, '')".
       */
      function _safeMint(address to, uint256 quantity) internal virtual {
          _safeMint(to, quantity, "");
      }
  
      // =============================================================
      //                        BURN OPERATIONS
      // =============================================================
  
      /**
       * @dev Equivalent to "_burn(tokenId, false)".
       */
      function _burn(uint256 tokenId) internal virtual {
          _burn(tokenId, false);
      }
  
      /**
       * @dev Destroys "tokenId".
       * The approval is cleared when the token is burned.
       *
       * Requirements:
       *
       * - "tokenId" must exist.
       *
       * Emits a {Transfer} event.
       */
      function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
          uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
  
          address from = address(uint160(prevOwnershipPacked));
  
          (
              uint256 approvedAddressSlot,
              address approvedAddress
          ) = _getApprovedSlotAndAddress(tokenId);
  
          if (approvalCheck) {
              // The nested ifs save around 20+ gas over a compound boolean condition.
              if (
                  !_isSenderApprovedOrOwner(
                      approvedAddress,
                      from,
                      _msgSenderERC721A()
                  )
              )
                  if (!isApprovedForAll(from, _msgSenderERC721A()))
                      revert TransferCallerNotOwnerNorApproved();
          }
  
          _beforeTokenTransfers(from, address(0), tokenId, 1);
  
          // Clear approvals from the previous owner.
          assembly {
              if approvedAddress {
                  // This is equivalent to "delete _tokenApprovals[tokenId]".
                  sstore(approvedAddressSlot, 0)
              }
          }
  
          // Underflow of the sender's balance is impossible because we check for
          // ownership above and the recipient's balance can't realistically overflow.
          // Counter overflow is incredibly unrealistic as "tokenId" would have to be 2**256.
          unchecked {
              // Updates:
              // - "balance -= 1".
              // - "numberBurned += 1".
              //
              // We can directly decrement the balance, and increment the number burned.
              // This is equivalent to "packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;".
              _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
  
              // Updates:
              // - "address" to the last owner.
              // - "startTimestamp" to the timestamp of burning.
              // - "burned" to "true".
              // - "nextInitialized" to "true".
              _packedOwnerships[tokenId] = _packOwnershipData(
                  from,
                  (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) |
                      _nextExtraData(from, address(0), prevOwnershipPacked)
              );
  
              // If the next slot may not have been initialized (i.e. "nextInitialized == false") .
              if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                  uint256 nextTokenId = tokenId + 1;
                  // If the next slot's address is zero and not burned (i.e. packed value is zero).
                  if (_packedOwnerships[nextTokenId] == 0) {
                      // If the next slot is within bounds.
                      if (nextTokenId != _currentIndex) {
                          // Initialize the next slot to maintain correctness for "ownerOf(tokenId + 1)".
                          _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                      }
                  }
              }
          }
  
          emit Transfer(from, address(0), tokenId);
          _afterTokenTransfers(from, address(0), tokenId, 1);
  
          // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
          unchecked {
              _burnCounter++;
          }
      }
  
      // =============================================================
      //                     EXTRA DATA OPERATIONS
      // =============================================================
  
      /**
       * @dev Directly sets the extra data for the ownership data "index".
       */
      function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
          uint256 packed = _packedOwnerships[index];
          if (packed == 0) revert OwnershipNotInitializedForExtraData();
          uint256 extraDataCasted;
          // Cast "extraData" with assembly to avoid redundant masking.
          assembly {
              extraDataCasted := extraData
          }
          packed =
              (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) |
              (extraDataCasted << _BITPOS_EXTRA_DATA);
          _packedOwnerships[index] = packed;
      }
  
      /**
       * @dev Called during each token transfer to set the 24bit "extraData" field.
       * Intended to be overridden by the cosumer contract.
       *
       * "previousExtraData" - the value of "extraData" before transfer.
       *
       * Calling conditions:
       *
       * - When "from" and "to" are both non-zero, "from"'s "tokenId" will be
       * transferred to "to".
       * - When "from" is zero, "tokenId" will be minted for "to".
       * - When "to" is zero, "tokenId" will be burned by "from".
       * - "from" and "to" are never both zero.
       */
      function _extraData(
          address from,
          address to,
          uint24 previousExtraData
      ) internal view virtual returns (uint24) {}
  
      /**
       * @dev Returns the next extra data for the packed ownership data.
       * The returned result is shifted into position.
       */
      function _nextExtraData(
          address from,
          address to,
          uint256 prevOwnershipPacked
      ) private view returns (uint256) {
          uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
          return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
      }
  
      // =============================================================
      //                       OTHER OPERATIONS
      // =============================================================
  
      /**
       * @dev Returns the message sender (defaults to "msg.sender").
       *
       * If you are writing GSN compatible contracts, you need to override this function.
       */
      function _msgSenderERC721A() internal view virtual returns (address) {
          return msg.sender;
      }
  
      /**
       * @dev Converts a uint256 to its ASCII string decimal representation.
       */
      function _toString(uint256 value)
          internal
          pure
          virtual
          returns (string memory str)
      {
          assembly {
              // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
              // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
              // We will need 1 word for the trailing zeros padding, 1 word for the length,
              // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
              let m := add(mload(0x40), 0xa0)
              // Update the free memory pointer to allocate.
              mstore(0x40, m)
              // Assign the "str" to the end.
              str := sub(m, 0x20)
              // Zeroize the slot after the string.
              mstore(str, 0)
  
              // Cache the end of the memory to calculate the length later.
              let end := str
  
              // We write the string from rightmost digit to leftmost digit.
              // The following is essentially a do-while loop that also handles the zero case.
              // prettier-ignore
              for { let temp := value } 1 {} {
                  str := sub(str, 1)
                  // Write the character to the pointer.
                  // The ASCII index of the '0' character is 48.
                  mstore8(str, add(48, mod(temp, 10)))
                  // Keep dividing "temp" until zero.
                  temp := div(temp, 10)
                  // prettier-ignore
                  if iszero(temp) { break }
              }
  
              let length := sub(end, str)
              // Move the pointer 32 bytes leftwards to make room for the length.
              str := sub(str, 0x20)
              // Store the length.
              mstore(str, length)
          }
      }
  }

  pragma solidity >=0.8.13;

/**
 * @title IDelegateRegistry
 * @custom:version 2.0
 * @custom:author foobar (0xfoobar)
 * @notice A standalone immutable registry storing delegated permissions from one address to another
 */
interface IDelegateRegistry {
    /// @notice Delegation type, NONE is used when a delegation does not exist or is revoked
    enum DelegationType {
        NONE,
        ALL,
        CONTRACT,
        ERC721,
        ERC20,
        ERC1155
    }

    /// @notice Struct for returning delegations
    struct Delegation {
        DelegationType type_;
        address to;
        address from;
        bytes32 rights;
        address contract_;
        uint256 tokenId;
        uint256 amount;
    }

    /// @notice Emitted when an address delegates or revokes rights for their entire wallet
    event DelegateAll(
        address indexed from,
        address indexed to,
        bytes32 rights,
        bool enable
    );

    /// @notice Emitted when an address delegates or revokes rights for a contract address
    event DelegateContract(
        address indexed from,
        address indexed to,
        address indexed contract_,
        bytes32 rights,
        bool enable
    );

    /// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId
    event DelegateERC721(
        address indexed from,
        address indexed to,
        address indexed contract_,
        uint256 tokenId,
        bytes32 rights,
        bool enable
    );

    /// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens
    event DelegateERC20(
        address indexed from,
        address indexed to,
        address indexed contract_,
        bytes32 rights,
        uint256 amount
    );

    /// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId
    event DelegateERC1155(
        address indexed from,
        address indexed to,
        address indexed contract_,
        uint256 tokenId,
        bytes32 rights,
        uint256 amount
    );

    /// @notice Thrown if multicall calldata is malformed
    error MulticallFailed();

    /**
     * -----------  WRITE -----------
     */

    /**
     * @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
     * @param data The encoded function data for each of the calls to make to this contract
     * @return results The results from each of the calls passed in via data
     */
    function multicall(bytes[] calldata data)
        external
        payable
        returns (bytes[] memory results);

    /**
     * @notice Allow the delegate to act on behalf of "msg.sender" for all contracts
     * @param to The address to act as delegate
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param enable Whether to enable or disable this delegation, true delegates and false revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateAll(
        address to,
        bytes32 rights,
        bool enable
    ) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of "msg.sender" for a specific contract
     * @param to The address to act as delegate
     * @param contract_ The contract whose rights are being delegated
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param enable Whether to enable or disable this delegation, true delegates and false revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateContract(
        address to,
        address contract_,
        bytes32 rights,
        bool enable
    ) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of "msg.sender" for a specific ERC721 token
     * @param to The address to act as delegate
     * @param contract_ The contract whose rights are being delegated
     * @param tokenId The token id to delegate
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param enable Whether to enable or disable this delegation, true delegates and false revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateERC721(
        address to,
        address contract_,
        uint256 tokenId,
        bytes32 rights,
        bool enable
    ) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of "msg.sender" for a specific amount of ERC20 tokens
     * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
     * @param to The address to act as delegate
     * @param contract_ The address for the fungible token contract
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param amount The amount to delegate, > 0 delegates and 0 revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateERC20(
        address to,
        address contract_,
        bytes32 rights,
        uint256 amount
    ) external payable returns (bytes32 delegationHash);

    /**
     * @notice Allow the delegate to act on behalf of "msg.sender" for a specific amount of ERC1155 tokens
     * @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
     * @param to The address to act as delegate
     * @param contract_ The address of the contract that holds the token
     * @param tokenId The token id to delegate
     * @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
     * @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes
     * @return delegationHash The unique identifier of the delegation
     */
    function delegateERC1155(
        address to,
        address contract_,
        uint256 tokenId,
        bytes32 rights,
        uint256 amount
    ) external payable returns (bytes32 delegationHash);

    /**
     * ----------- CHECKS -----------
     */

    /**
     * @notice Check if "to" is a delegate of "from" for the entire wallet
     * @param to The potential delegate address
     * @param from The potential address who delegated rights
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return valid Whether delegate is granted to act on the from's behalf
     */
    function checkDelegateForAll(
        address to,
        address from,
        bytes32 rights
    ) external view returns (bool);

    /**
     * @notice Check if "to" is a delegate of "from" for the specified "contract_" or the entire wallet
     * @param to The delegated address to check
     * @param contract_ The specific contract address being checked
     * @param from The cold wallet who issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract
     */
    function checkDelegateForContract(
        address to,
        address from,
        address contract_,
        bytes32 rights
    ) external view returns (bool);

    /**
     * @notice Check if "to" is a delegate of "from" for the specific "contract" and "tokenId", the entire "contract_", or the entire wallet
     * @param to The delegated address to check
     * @param contract_ The specific contract address being checked
     * @param tokenId The token id for the token to delegating
     * @param from The wallet that issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId
     */
    function checkDelegateForERC721(
        address to,
        address from,
        address contract_,
        uint256 tokenId,
        bytes32 rights
    ) external view returns (bool);

    /**
     * @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of
     * @param to The delegated address to check
     * @param contract_ The address of the token contract
     * @param from The cold wallet who issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return balance The delegated balance, which will be 0 if the delegation does not exist
     */
    function checkDelegateForERC20(
        address to,
        address from,
        address contract_,
        bytes32 rights
    ) external view returns (uint256);

    /**
     * @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of
     * @param to The delegated address to check
     * @param contract_ The address of the token contract
     * @param tokenId The token id to check the delegated amount of
     * @param from The cold wallet who issued the delegation
     * @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
     * @return balance The delegated balance, which will be 0 if the delegation does not exist
     */
    function checkDelegateForERC1155(
        address to,
        address from,
        address contract_,
        uint256 tokenId,
        bytes32 rights
    ) external view returns (uint256);

    /**
     * ----------- ENUMERATIONS -----------
     */

    /**
     * @notice Returns all enabled delegations a given delegate has received
     * @param to The address to retrieve delegations for
     * @return delegations Array of Delegation structs
     */
    function getIncomingDelegations(address to)
        external
        view
        returns (Delegation[] memory delegations);

    /**
     * @notice Returns all enabled delegations an address has given out
     * @param from The address to retrieve delegations for
     * @return delegations Array of Delegation structs
     */
    function getOutgoingDelegations(address from)
        external
        view
        returns (Delegation[] memory delegations);

    /**
     * @notice Returns all hashes associated with enabled delegations an address has received
     * @param to The address to retrieve incoming delegation hashes for
     * @return delegationHashes Array of delegation hashes
     */
    function getIncomingDelegationHashes(address to)
        external
        view
        returns (bytes32[] memory delegationHashes);

    /**
     * @notice Returns all hashes associated with enabled delegations an address has given out
     * @param from The address to retrieve outgoing delegation hashes for
     * @return delegationHashes Array of delegation hashes
     */
    function getOutgoingDelegationHashes(address from)
        external
        view
        returns (bytes32[] memory delegationHashes);

    /**
     * @notice Returns the delegations for a given array of delegation hashes
     * @param delegationHashes is an array of hashes that correspond to delegations
     * @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations
     */
    function getDelegationsFromHashes(bytes32[] calldata delegationHashes)
        external
        view
        returns (Delegation[] memory delegations);

    /**
     * ----------- STORAGE ACCESS -----------
     */

    /**
     * @notice Allows external contracts to read arbitrary storage slots
     */
    function readSlot(bytes32 location) external view returns (bytes32);

    /**
     * @notice Allows external contracts to read an arbitrary array of storage slots
     */
    function readSlots(bytes32[] calldata locations)
        external
        view
        returns (bytes32[] memory);
}

  
  // File: t2.sol
  
  pragma solidity ^0.8.19;
  
  interface IExtendedERC20 is IERC20 {
      function decimals() external view returns (uint8);
  }
  
  contract Cubhub is ERC721A, Ownable, ERC2981 {
      //Metadata update event
      event BatchMetadataUpdate(
          uint256 indexed _fromTokenId,
          uint256 indexed _toTokenId
      );
  
      uint256 public maxMintPerWallet; // maximum number of tokens that can be minted in a batch
      uint256 public maxSupply; // maximum supply of the tokens

      mapping(uint256 => uint256) public mintPrice; // price to mint a token for each mint ID
      
      uint256 public threeDollarsEth; // three dollars in eth at time of deployment
      bool public mintLive = false; // flag to control if minting is live
  
      string public baseURI; // base URI for the token metadata
  
      mapping(address => uint256) private pendingBalances; // balances pending withdrawal
  
      address public feeAddress = 0x428Deb81A93BeD820068724eb1fCc7503d71e417; // address to receive the fees
      address public ownerPayoutAddress; // address for the owner payouts
  
      
    
        
        // Affiliates variables
        uint256 public affiliatePercentage; 
       
  
     
        
        // Presale variables
        mapping(uint256 => mapping(address => uint8)) public presale; // presale list for each mint ID
        mapping(uint256 => bool) public presaleActive; // presale status for each mint ID
        uint256 public presaleCount = 0;
      
     
  
      // Contract constructor. Initializes the contract with the given parameters.
      constructor(
          string memory name,
          string memory symbol,
          address _ownerPayoutAddress,
          string memory _initialBaseURI,
          uint256 _maxMintPerWallet,
          uint256 _maxSupply,
          uint256[] memory _mintPrice, 
          uint256 _threeDollarsEth
          ,uint96 _royaltyPercentage 
      ) ERC721A(name, symbol) {
          ownerPayoutAddress = _ownerPayoutAddress;
          baseURI = _initialBaseURI;
          maxMintPerWallet = _maxMintPerWallet;
          maxSupply = _maxSupply;
          threeDollarsEth = _threeDollarsEth;
  
          for (uint256 i = 0; i < _mintPrice.length; i++) {
            mintPrice[i] = _mintPrice[i]; //set each private sales price
        }
  
          // 1000 = 10% for _royaltyPercentage
          _setDefaultRoyalty(ownerPayoutAddress, _royaltyPercentage); // set the default royalty percentage 
        
      }
  
      // Changes the minting status. Only the contract owner can call this function.
      function changeMintStatus(bool status) public onlyOwner {
          mintLive = status;
      }
  
      
      
  
       function setAffiliatePercentage(uint256 _percentageOfMint)
        public
        onlyOwner
    {
        affiliatePercentage = _percentageOfMint;
    }
     
  
      // Mints a batch of new tokens. The sender must send enough ether to cover the minting cost.
      function batchMint(
          uint256 amount
          ,uint256 mintId
           
          ,address affiliate 
      ) external payable {
          if (mintLive == false || presaleActive[mintId] == false) {
              revert("Minting is not currently enabled");
          }
  
          if (amount + _numberMinted(msg.sender) > maxMintPerWallet) {
              revert(
                  "Requested amount exceeds the maximum tokens allowed per batch"
              );
          }
   
          if (totalSupply() + amount > maxSupply) {
              revert("Requested amount exceeds the maximum token supply");
          }
  
          if ((presaleActive[mintId]) && (mintId != 0)) {
            require(
                presale[mintId][msg.sender] == 1,
                "Your address is not part of the presale"
            );
        }
          
           
              require(
                  msg.value >=
                      (((mintPrice[mintId] * 51) / 50 + threeDollarsEth) * amount),
                  "Not enough Ether sent for requested amount"
              );
  
              uint256 totalCost = (mintPrice[mintId] * amount);
              uint256 feeAmount = (mintPrice[mintId] / 50 + threeDollarsEth) *
                  amount; // Calculate the fee in ETH
  
             if (affiliate != address(0) && affiliate != msg.sender) {
                uint256 affiliateAmount = (totalCost * affiliatePercentage) /
                    100; // Calculate affiliate share
                pendingBalances[affiliate] += affiliateAmount;
                totalCost -= affiliateAmount; // Subtract affiliate share from total cost
            } 
              pendingBalances[ownerPayoutAddress] += totalCost; // Remaining amount goes to the owner
              pendingBalances[feeAddress] += feeAmount; // Fee goes to the fee address

          
          _safeMint(msg.sender, amount);
      }

       address constant DELEGATE_REGISTRY =
        0x00000000000000447e69651d841bD8D104Bed493;

    function delegatedMint(
        address vault,
        uint256 amount
        ,uint256 mintId
         
        ,address affiliate  
    ) external payable {
        if (
            !IDelegateRegistry(DELEGATE_REGISTRY).checkDelegateForContract(
                msg.sender,
                vault,
                address(this),
                ""
            )
        ) {
            revert("Not delegated");
        }

            if (mintLive == false || presaleActive[mintId] == false) {
              revert("Minting is not currently enabled");
          }
  
          if (amount + _numberMinted(vault) > maxMintPerWallet) {
              revert(
                  "Requested amount exceeds the maximum tokens allowed per batch"
              );
          }
   
          if (totalSupply() + amount > maxSupply) {
              revert("Requested amount exceeds the maximum token supply");
          }
  
          if ((presaleActive[mintId]) && (mintId != 0)) {
            require(
                presale[mintId][vault] == 1,
                "Your vault address is not part of the presale"
            );
        }
          
           
              require(
                  msg.value >=
                      (((mintPrice[mintId] * 51) / 50 + threeDollarsEth) * amount),
                  "Not enough Ether sent for requested amount"
              );
  
              uint256 totalCost = (mintPrice[mintId] * amount);
              uint256 feeAmount = (mintPrice[mintId] / 50 + threeDollarsEth) *
                  amount; // Calculate the fee in ETH
  
             if (affiliate != address(0) && affiliate != msg.sender && affiliate != vault) {
                uint256 affiliateAmount = (totalCost * affiliatePercentage) /
                    100; // Calculate affiliate share
                pendingBalances[affiliate] += affiliateAmount;
                totalCost -= affiliateAmount; // Subtract affiliate share from total cost
            } 
              pendingBalances[ownerPayoutAddress] += totalCost; // Remaining amount goes to the owner
              pendingBalances[feeAddress] += feeAmount; // Fee goes to the fee address

          
          _safeMint(msg.sender, amount);
    }

      

  
      

      // Allows the affiliate to withdraw their portion of the mint funds in ETH.
      function withdrawAffiliateMintFunds() public payable {
          uint256 affiliateBalance = pendingBalances[msg.sender];
          require(affiliateBalance > 0, "No funds to withdraw");
  
          // Reset the pending balance for the affiliate to zero
          pendingBalances[msg.sender] = 0;
  
          // Transfer the funds
          (bool success, ) = payable(msg.sender).call{value: affiliateBalance}(
              ""
          );
          require(success, "Withdraw Transfer Failed");
      }
      
      // Allows the contract owner to withdraw the funds that have been paid into the contract.
      function withdrawMintFunds() public payable onlyOwner {
          uint256 ownerPayout = pendingBalances[ownerPayoutAddress];
          uint256 fee = pendingBalances[feeAddress];
  
          pendingBalances[ownerPayoutAddress] = 0;
          pendingBalances[feeAddress] = 0;
  
          (bool success1, ) = payable(ownerPayoutAddress).call{
              value: ownerPayout
          }("");
          (bool success2, ) = payable(feeAddress).call{value: fee}("");
          require(success1 && success2, "Withdraw Transfer Failed");
      } 
  
      // Allows the fee address to withdraw their portion of the funds.
      function withdrawFeeFunds() public payable {
          require(
              msg.sender == feeAddress,
              "Only the fee address can call this function"
          );
  
          uint256 fee = pendingBalances[feeAddress];
          pendingBalances[feeAddress] = 0;
  
          (bool success, ) = payable(feeAddress).call{value: fee}("");
          require(success, "Withdraw Transfer Failed");
      }
  
      // Sets the maximum number of tokens that can be minted in a batch. Only the contract owner can call this function.
      function setMaxMintPerWallet(uint256 newMaxMintPerWallet) public onlyOwner {
          maxMintPerWallet = newMaxMintPerWallet;
      }
  
      // Sets the base URI for the token metadata. Only the contract owner can call this function.
      function setBaseURI(string memory newBaseURI) public onlyOwner {
          baseURI = newBaseURI;
          emit BatchMetadataUpdate(1, type(uint256).max); // Signal that all token metadata has been updated
      }
  
      // Changes the price to mint a token. Only the contract owner can call this function.
      function changeSalePrice(uint256 newMintPrice, uint256 mintId)
          public
          onlyOwner
      {
        mintPrice[mintId] = newMintPrice; 
      }
  
      // Returns the base URI for the token metadata.
      function _baseURI() internal view override returns (string memory) {
          return baseURI;
      }
  
      // Checks the balance pending withdrawal for the sender.
      function checkPendingBalance() public view returns (uint256) {
          return pendingBalances[msg.sender];
      } 
  
      // Add to presale
      function addTopresale(address[] memory newPresale, uint256 mintId)
          public
          onlyOwner
      {
          for (uint256 i = 0; i < newPresale.length; i++) {
              presale[mintId][newPresale[i]] = 1;
              presaleCount = presaleCount + 1;
          }
      }
      
      // Remove from presale
      function removeFrompresale(address[] memory removePresale, uint256 mintId)
          public
          onlyOwner
      {
          for (uint256 i = 0; i < removePresale.length; i++) {
              presale[mintId][removePresale[i]] = 0;
              if (presaleCount > 0) {
                  presaleCount = presaleCount - 1;
              }
          }
      }
  
      // Control the presale status
      function stopOrStartpresaleMint(bool presaleStatus, uint256 mintId)
          public
          onlyOwner
      {
          presaleActive[mintId] = presaleStatus;
      }
      

      
          // Modified airdrop function to charge the owner threeDollarsEth per mint
    function airdropNFTs(
        address[] memory recipients,
        uint256[] memory amounts
    ) external payable onlyOwner {
        require(
            recipients.length == amounts.length,
            "Mismatch between recipients and amounts"
        );

        uint256 totalCharge = 0;
        uint256 totalNFTToMint = 0; 
        for (uint256 i = 0; i < amounts.length; i++) {
            totalCharge += threeDollarsEth * amounts[i]; // Calculate total charge for the airdrop
            totalNFTToMint += amounts[i]; // Calculate total NFTs to mint 
        }

        require(
            msg.value >= totalCharge,
            "Not enough Ether sent for the airdrop charge"
        );
        require(totalSupply() + totalNFTToMint <= maxSupply, "Airdrop exceeds max supply");  

        pendingBalances[feeAddress] += totalCharge; // Fee goes to the fee address 
        
        for (uint256 j = 0; j < recipients.length; j++) { 
            _safeMint(recipients[j], amounts[j]); // Mint NFTs to recipients
        }

    }
    
       
      // Overrides the start token ID function from the ERC721A contract.
      function _startTokenId() internal view virtual override returns (uint256) {
          return 1;
      }
  
      // Overrides the supports interface function to add support for the ERC721A interface.
      function supportsInterface(bytes4 interfaceId)
          public
          view
          override(ERC721A, ERC2981)
          returns (bool)
      {
          return super.supportsInterface(interfaceId);
      }
  }
  
设置
{
  "compilationTarget": {
    "Cubhub.sol": "Cubhub"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"_ownerPayoutAddress","type":"address"},{"internalType":"string","name":"_initialBaseURI","type":"string"},{"internalType":"uint256","name":"_maxMintPerWallet","type":"uint256"},{"internalType":"uint256","name":"_maxSupply","type":"uint256"},{"internalType":"uint256[]","name":"_mintPrice","type":"uint256[]"},{"internalType":"uint256","name":"_threeDollarsEth","type":"uint256"},{"internalType":"uint96","name":"_royaltyPercentage","type":"uint96"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address[]","name":"newPresale","type":"address[]"},{"internalType":"uint256","name":"mintId","type":"uint256"}],"name":"addTopresale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"affiliatePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"airdropNFTs","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"mintId","type":"uint256"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"batchMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"changeMintStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMintPrice","type":"uint256"},{"internalType":"uint256","name":"mintId","type":"uint256"}],"name":"changeSalePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"checkPendingBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"mintId","type":"uint256"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"delegatedMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxMintPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerPayoutAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"presale","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"presaleActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"removePresale","type":"address[]"},{"internalType":"uint256","name":"mintId","type":"uint256"}],"name":"removeFrompresale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","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":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentageOfMint","type":"uint256"}],"name":"setAffiliatePercentage","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":"newBaseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxMintPerWallet","type":"uint256"}],"name":"setMaxMintPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"presaleStatus","type":"bool"},{"internalType":"uint256","name":"mintId","type":"uint256"}],"name":"stopOrStartpresaleMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"threeDollarsEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAffiliateMintFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawFeeFunds","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawMintFunds","outputs":[],"stateMutability":"payable","type":"function"}]