QuiverGenesis

0x9e8de7742b6c065996a34fc0b11772c62da8c4ef

Verification
Verified
v0.8.35+commit.47b9dedd
Type
Contract
18,488 bytes
ABI entries
86
26 read · 17 write
License
mit

Contract information

Address
0x9e8de7742b6c065996a34fc0b11772c62da8c4ef
Chain
Robinhood Chain (4663)
Compiler
v0.8.35+commit.47b9dedd
Optimization
Disabled
Creation tx
0x46d7fc582d…fc81845371

Token

Name
Quiver Genesis
Symbol
QUIVER
Decimals
Holders
963

Read contract (26)

FCFS_PHASE()uint256
GTD_PHASE()uint256
INITIAL_SALE_PRICE()uint96
MAX_SUPPLY()uint256
PUBLIC_PHASE()uint256
SALE_SUPPLY()uint256
TEAM_PHASE()uint256
TEAM_SUPPLY()uint256
balanceOf(address)uint256
getApproved(uint256)address
isApprovedForAll(address, address)bool
mintedByPhase(uint256, address)bool
name()string
owner()address
ownerOf(uint256)address
phases(uint256)uint64, uint64, bytes32, uint96, bool, bool
revealed()bool
saleMinted()uint256
supportsInterface(bytes4)bool
symbol()string
teamClaimed()bool
teamMinted()uint256
tokenByIndex(uint256)uint256
tokenOfOwnerByIndex(address, uint256)uint256
tokenURI(uint256)string
totalSupply()uint256

Events (13)

ApprovalApprovalForAllBaseURISetMerkleRootSetOwnershipTransferredPhaseActiveSetPhasePriceDecreasedPreRevealURISetRevealedSetScheduleConfiguredTeamClaimedTransferWithdrawn

ABI

[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "initialPreRevealUri",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "initialBaseUri",
        "type": "string"
      },
      {
        "internalType": "address",
        "name": "initialOwner",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "ERC721EnumerableForbiddenBatchMint",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "ERC721IncorrectOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "operator",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "ERC721InsufficientApproval",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC721InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "operator",
        "type": "address"
      }
    ],
    "name": "ERC721InvalidOperator",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "ERC721InvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC721InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC721InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "ERC721NonexistentToken",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      }
    ],
    "name": "ERC721OutOfBoundsIndex",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPayment",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPhase",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPhaseWindow",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidProof",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PhaseEnded",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PhaseInactive",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PhaseNotConfigured",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PhaseNotStarted",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PhaseOverlap",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PriceNotDecreased",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PublicProofNotEmpty",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SaleSoldOut",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TeamAlreadyClaimed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "WalletPhaseLimit",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "WithdrawFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "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": false,
        "internalType": "string",
        "name": "uri",
        "type": "string"
      }
    ],
    "name": "BaseURISet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "merkleRoot",
        "type": "bytes32"
      }
    ],
    "name": "MerkleRootSet",
    "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": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "active",
        "type": "bool"
      }
    ],
    "name": "PhaseActiveSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint96",
        "name": "previousPrice",
        "type": "uint96"
      },
      {
        "indexed": false,
        "internalType": "uint96",
        "name": "newPrice",
        "type": "uint96"
      }
    ],
    "name": "PhasePriceDecreased",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "string",
        "name": "uri",
        "type": "string"
      }
    ],
    "name": "PreRevealURISet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "bool",
        "name": "revealed",
        "type": "bool"
      }
    ],
    "name": "RevealedSet",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint64[4]",
        "name": "starts",
        "type": "uint64[4]"
      },
      {
        "indexed": false,
        "internalType": "uint64[4]",
        "name": "ends",
        "type": "uint64[4]"
      }
    ],
    "name": "ScheduleConfigured",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "wallet",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "quantity",
        "type": "uint256"
      }
    ],
    "name": "TeamClaimed",
    "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"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "Withdrawn",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "FCFS_PHASE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "GTD_PHASE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_SALE_PRICE",
    "outputs": [
      {
        "internalType": "uint96",
        "name": "",
        "type": "uint96"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "PUBLIC_PHASE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "SALE_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TEAM_PHASE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TEAM_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint64[4]",
        "name": "starts",
        "type": "uint64[4]"
      },
      {
        "internalType": "uint64[4]",
        "name": "ends",
        "type": "uint64[4]"
      }
    ],
    "name": "configureSchedule",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "internalType": "uint96",
        "name": "newPrice",
        "type": "uint96"
      }
    ],
    "name": "decreasePhasePrice",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "getApproved",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "operator",
        "type": "address"
      }
    ],
    "name": "isApprovedForAll",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "internalType": "bytes32[]",
        "name": "proof",
        "type": "bytes32[]"
      }
    ],
    "name": "mint",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "mintedByPhase",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "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": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "phases",
    "outputs": [
      {
        "internalType": "uint64",
        "name": "startAt",
        "type": "uint64"
      },
      {
        "internalType": "uint64",
        "name": "endAt",
        "type": "uint64"
      },
      {
        "internalType": "bytes32",
        "name": "merkleRoot",
        "type": "bytes32"
      },
      {
        "internalType": "uint96",
        "name": "price",
        "type": "uint96"
      },
      {
        "internalType": "bool",
        "name": "active",
        "type": "bool"
      },
      {
        "internalType": "bool",
        "name": "configured",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "revealed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "safeTransferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "safeTransferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "saleMinted",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "operator",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "approved",
        "type": "bool"
      }
    ],
    "name": "setApprovalForAll",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "newUri",
        "type": "string"
      }
    ],
    "name": "setBaseURI",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "merkleRoot",
        "type": "bytes32"
      }
    ],
    "name": "setMerkleRoot",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "phaseId",
        "type": "uint256"
      },
      {
        "internalType": "bool",
        "name": "active",
        "type": "bool"
      }
    ],
    "name": "setPhaseActive",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "newUri",
        "type": "string"
      }
    ],
    "name": "setPreRevealURI",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bool",
        "name": "newRevealed",
        "type": "bool"
      }
    ],
    "name": "setRevealed",
    "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": "teamClaimed",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32[]",
        "name": "proof",
        "type": "bytes32[]"
      }
    ],
    "name": "teamMint",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "teamMinted",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      }
    ],
    "name": "tokenByIndex",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "index",
        "type": "uint256"
      }
    ],
    "name": "tokenOfOwnerByIndex",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "tokenURI",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address payable",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "withdraw",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract QuiverGenesis is ERC721Enumerable, Ownable, ReentrancyGuard {
    using Strings for uint256;

    struct Phase {
        uint64 startAt;
        uint64 endAt;
        bytes32 merkleRoot;
        uint96 price;
        bool active;
        bool configured;
    }

    uint256 public constant MAX_SUPPLY = 2222;
    uint256 public constant TEAM_SUPPLY = 100;
    uint256 public constant SALE_SUPPLY = 2122;
    uint256 public constant TEAM_PHASE = 0;
    uint256 public constant GTD_PHASE = 1;
    uint256 public constant FCFS_PHASE = 2;
    uint256 public constant PUBLIC_PHASE = 3;
    uint96 public constant INITIAL_SALE_PRICE = 0.0022 ether;

    string private preRevealTokenUri;
    string private baseTokenUri;

    bool public revealed;
    bool public teamClaimed;
    uint256 public teamMinted;
    uint256 public saleMinted;

    mapping(uint256 => Phase) public phases;
    mapping(uint256 => mapping(address => bool)) public mintedByPhase;

    error InvalidPhase();
    error InvalidPhaseWindow();
    error PhaseOverlap();
    error PhaseNotConfigured();
    error PhaseInactive();
    error PhaseNotStarted();
    error PhaseEnded();
    error InvalidProof();
    error InvalidPayment();
    error TeamAlreadyClaimed();
    error WalletPhaseLimit();
    error SaleSoldOut();
    error PriceNotDecreased();
    error ZeroAddress();
    error WithdrawFailed();
    error PublicProofNotEmpty();

    event ScheduleConfigured(uint64[4] starts, uint64[4] ends);
    event PhaseActiveSet(uint256 indexed phaseId, bool active);
    event MerkleRootSet(uint256 indexed phaseId, bytes32 merkleRoot);
    event PhasePriceDecreased(
        uint256 indexed phaseId,
        uint96 previousPrice,
        uint96 newPrice
    );
    event TeamClaimed(address indexed wallet, uint256 quantity);
    event PreRevealURISet(string uri);
    event BaseURISet(string uri);
    event RevealedSet(bool revealed);
    event Withdrawn(address indexed to, uint256 amount);

    constructor(
        string memory name_,
        string memory symbol_,
        string memory initialPreRevealUri,
        string memory initialBaseUri,
        address initialOwner
    ) ERC721(name_, symbol_) Ownable(initialOwner) {
        preRevealTokenUri = initialPreRevealUri;
        baseTokenUri = initialBaseUri;
        phases[GTD_PHASE].price = INITIAL_SALE_PRICE;
        phases[FCFS_PHASE].price = INITIAL_SALE_PRICE;
        phases[PUBLIC_PHASE].price = INITIAL_SALE_PRICE;
    }

    function configureSchedule(
        uint64[4] calldata starts,
        uint64[4] calldata ends
    ) external onlyOwner {
        for (uint256 phaseId; phaseId < 4; phaseId++) {
            if (ends[phaseId] <= starts[phaseId]) {
                revert InvalidPhaseWindow();
            }

            if (phaseId < PUBLIC_PHASE && ends[phaseId] > starts[phaseId + 1]) {
                revert PhaseOverlap();
            }
        }

        for (uint256 phaseId; phaseId < 4; phaseId++) {
            Phase storage phase = phases[phaseId];
            phase.startAt = starts[phaseId];
            phase.endAt = ends[phaseId];
            phase.configured = true;
        }

        emit ScheduleConfigured(starts, ends);
    }

    function setPhaseActive(uint256 phaseId, bool active) external onlyOwner {
        _requireFixedPhase(phaseId);
        if (!phases[phaseId].configured) revert PhaseNotConfigured();
        phases[phaseId].active = active;
        emit PhaseActiveSet(phaseId, active);
    }

    function setMerkleRoot(
        uint256 phaseId,
        bytes32 merkleRoot
    ) external onlyOwner {
        if (phaseId > FCFS_PHASE) revert InvalidPhase();
        phases[phaseId].merkleRoot = merkleRoot;
        emit MerkleRootSet(phaseId, merkleRoot);
    }

    function decreasePhasePrice(
        uint256 phaseId,
        uint96 newPrice
    ) external onlyOwner {
        if (phaseId < GTD_PHASE || phaseId > PUBLIC_PHASE) {
            revert InvalidPhase();
        }

        Phase storage phase = phases[phaseId];
        uint96 previousPrice = phase.price;
        if (newPrice >= previousPrice) revert PriceNotDecreased();
        phase.price = newPrice;
        emit PhasePriceDecreased(phaseId, previousPrice, newPrice);
    }

    function teamMint(bytes32[] calldata proof) external payable nonReentrant {
        _validateLivePhase(TEAM_PHASE);
        if (msg.value != 0) revert InvalidPayment();
        if (teamClaimed) revert TeamAlreadyClaimed();
        if (!_verifyWallet(phases[TEAM_PHASE].merkleRoot, msg.sender, proof)) {
            revert InvalidProof();
        }

        teamClaimed = true;
        teamMinted = TEAM_SUPPLY;
        _mintMany(msg.sender, TEAM_SUPPLY);
        emit TeamClaimed(msg.sender, TEAM_SUPPLY);
    }

    function mint(
        uint256 phaseId,
        bytes32[] calldata proof
    ) external payable nonReentrant {
        if (phaseId < GTD_PHASE || phaseId > PUBLIC_PHASE) {
            revert InvalidPhase();
        }

        _validateLivePhase(phaseId);
        Phase storage phase = phases[phaseId];

        if (msg.value != phase.price) revert InvalidPayment();
        if (mintedByPhase[phaseId][msg.sender]) revert WalletPhaseLimit();
        if (saleMinted >= SALE_SUPPLY) revert SaleSoldOut();

        if (phaseId == PUBLIC_PHASE) {
            if (proof.length != 0) revert PublicProofNotEmpty();
        } else if (!_verifyWallet(phase.merkleRoot, msg.sender, proof)) {
            revert InvalidProof();
        }

        mintedByPhase[phaseId][msg.sender] = true;
        saleMinted += 1;
        _safeMint(msg.sender, totalSupply() + 1);
    }

    function setPreRevealURI(string calldata newUri) external onlyOwner {
        preRevealTokenUri = newUri;
        emit PreRevealURISet(newUri);
    }

    function setBaseURI(string calldata newUri) external onlyOwner {
        baseTokenUri = newUri;
        emit BaseURISet(newUri);
    }

    function setRevealed(bool newRevealed) external onlyOwner {
        revealed = newRevealed;
        emit RevealedSet(newRevealed);
    }

    function withdraw(address payable to) external onlyOwner nonReentrant {
        if (to == address(0)) revert ZeroAddress();
        uint256 amount = address(this).balance;
        (bool sent, ) = to.call{value: amount}("");
        if (!sent) revert WithdrawFailed();
        emit Withdrawn(to, amount);
    }

    function tokenURI(
        uint256 tokenId
    ) public view override returns (string memory) {
        _requireOwned(tokenId);
        if (!revealed) return preRevealTokenUri;
        return string.concat(baseTokenUri, tokenId.toString(), ".json");
    }

    function _validateLivePhase(uint256 phaseId) private view {
        Phase storage phase = phases[phaseId];
        if (!phase.configured) revert PhaseNotConfigured();
        if (!phase.active) revert PhaseInactive();
        if (block.timestamp < phase.startAt) revert PhaseNotStarted();
        if (block.timestamp >= phase.endAt) revert PhaseEnded();
    }

    function _verifyWallet(
        bytes32 merkleRoot,
        address wallet,
        bytes32[] calldata proof
    ) private pure returns (bool) {
        bytes32 leaf = keccak256(abi.encodePacked(wallet));
        return MerkleProof.verify(proof, merkleRoot, leaf);
    }

    function _mintMany(address to, uint256 quantity) private {
        for (uint256 index; index < quantity; index++) {
            _safeMint(to, totalSupply() + 1);
        }
    }

    function _requireFixedPhase(uint256 phaseId) private pure {
        if (phaseId > PUBLIC_PHASE) revert InvalidPhase();
    }
}
Chain explorer2664msChain node82ms