RobinhoodPixies

0x64713dda62c3559e3ee77873bb468c519b1a970a

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
17,638 bytes
ABI entries
93
30 read · 29 write
License
none

Contract information

Address
0x64713dda62c3559e3ee77873bb468c519b1a970a
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xad380f4dd0…c969dff516

Token

Name
Robinhood Pixies
Symbol
PIXIE
Decimals
Holders
329

Read contract (30)

MAX_SUPPLY()uint256
allowedSeaDrop(address)bool
balanceOf(address)uint256
baseURI()string
contractURI()string
displayMaxSupply()uint256
getAllowedSeaDrop()address[]
getApproved(uint256)address
getMintStats(address)uint256, uint256, uint256
getTransferValidationFunction()bytes4, bool
getTransferValidator()address
isApprovedForAll(address, address)bool
maxSupply()uint256
metadata()address
name()string
numMinted(address)uint256
owner()address
ownerOf(uint256)address
provenanceHash()bytes32
renderSVG(uint256)string
renderer()address
royaltyAddress()address
royaltyBps()uint96
royaltyInfo(uint256, uint256)address, uint256
royaltyReceiver()address
supportsInterface(bytes4)bool
symbol()string
tokenURI(uint256)string
totalSupply()uint256
transferValidator()address

Events (15)

AllowedSeaDropUpdatedApprovalApprovalForAllBaseURIUpdatedBatchMetadataUpdateContractURIUpdatedMaxSupplyUpdatedMetadataUpdatedMintedOwnershipTransferredProvenanceHashUpdatedRendererUpdatedRoyaltyInfoUpdatedTransferTransferValidatorUpdated

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "initialOwner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_renderer",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "_metadata",
        "type": "address"
      },
      {
        "internalType": "address[]",
        "name": "allowedSeaDrop_",
        "type": "address[]"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "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": [],
    "name": "ExceedsHardCap",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LengthMismatch",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "NonexistentToken",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotOwnerOrSelf",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OnlyAllowedSeaDrop",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OutOfRange",
    "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": "SoldOut",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ZeroAddress",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address[]",
        "name": "allowedSeaDrop",
        "type": "address[]"
      }
    ],
    "name": "AllowedSeaDropUpdated",
    "type": "event"
  },
  {
    "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": "newBaseURI",
        "type": "string"
      }
    ],
    "name": "BaseURIUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "_fromTokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "_toTokenId",
        "type": "uint256"
      }
    ],
    "name": "BatchMetadataUpdate",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "string",
        "name": "newContractURI",
        "type": "string"
      }
    ],
    "name": "ContractURIUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "newMaxSupply",
        "type": "uint256"
      }
    ],
    "name": "MaxSupplyUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "metadata",
        "type": "address"
      }
    ],
    "name": "MetadataUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      }
    ],
    "name": "Minted",
    "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": false,
        "internalType": "bytes32",
        "name": "previousHash",
        "type": "bytes32"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "newHash",
        "type": "bytes32"
      }
    ],
    "name": "ProvenanceHashUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "renderer",
        "type": "address"
      }
    ],
    "name": "RendererUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint96",
        "name": "bps",
        "type": "uint96"
      }
    ],
    "name": "RoyaltyInfoUpdated",
    "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": false,
        "internalType": "address",
        "name": "oldValidator",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "newValidator",
        "type": "address"
      }
    ],
    "name": "TransferValidatorUpdated",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "MAX_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "allowedSeaDrop",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "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": [],
    "name": "baseURI",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "contractURI",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "displayMaxSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "fromTokenId",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "toTokenId",
        "type": "uint256"
      }
    ],
    "name": "emitBatchMetadataUpdate",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getAllowedSeaDrop",
    "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": "minter",
        "type": "address"
      }
    ],
    "name": "getMintStats",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "minterNumMinted",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "currentTotalSupply",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxSupply_",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getTransferValidationFunction",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "functionSignature",
        "type": "bytes4"
      },
      {
        "internalType": "bool",
        "name": "isViewFunction",
        "type": "bool"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getTransferValidator",
    "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": "maxSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "metadata",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "minter",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "quantity",
        "type": "uint256"
      }
    ],
    "name": "mintSeaDrop",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "uint256",
            "name": "maxSupply",
            "type": "uint256"
          },
          {
            "internalType": "string",
            "name": "baseURI",
            "type": "string"
          },
          {
            "internalType": "string",
            "name": "contractURI",
            "type": "string"
          },
          {
            "internalType": "address",
            "name": "seaDropImpl",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "uint80",
                "name": "mintPrice",
                "type": "uint80"
              },
              {
                "internalType": "uint48",
                "name": "startTime",
                "type": "uint48"
              },
              {
                "internalType": "uint48",
                "name": "endTime",
                "type": "uint48"
              },
              {
                "internalType": "uint16",
                "name": "maxTotalMintableByWallet",
                "type": "uint16"
              },
              {
                "internalType": "uint16",
                "name": "feeBps",
                "type": "uint16"
              },
              {
                "internalType": "bool",
                "name": "restrictFeeRecipients",
                "type": "bool"
              }
            ],
            "internalType": "struct PublicDrop",
            "name": "publicDrop",
            "type": "tuple"
          },
          {
            "internalType": "string",
            "name": "dropURI",
            "type": "string"
          },
          {
            "components": [
              {
                "internalType": "bytes32",
                "name": "merkleRoot",
                "type": "bytes32"
              },
              {
                "internalType": "string[]",
                "name": "publicKeyURIs",
                "type": "string[]"
              },
              {
                "internalType": "string",
                "name": "allowListURI",
                "type": "string"
              }
            ],
            "internalType": "struct AllowListData",
            "name": "allowListData",
            "type": "tuple"
          },
          {
            "internalType": "address",
            "name": "creatorPayoutAddress",
            "type": "address"
          },
          {
            "internalType": "bytes32",
            "name": "provenanceHash",
            "type": "bytes32"
          },
          {
            "internalType": "address[]",
            "name": "allowedFeeRecipients",
            "type": "address[]"
          },
          {
            "internalType": "address[]",
            "name": "disallowedFeeRecipients",
            "type": "address[]"
          },
          {
            "internalType": "address[]",
            "name": "allowedPayers",
            "type": "address[]"
          },
          {
            "internalType": "address[]",
            "name": "disallowedPayers",
            "type": "address[]"
          },
          {
            "internalType": "address[]",
            "name": "tokenGatedAllowedNftTokens",
            "type": "address[]"
          },
          {
            "components": [
              {
                "internalType": "uint80",
                "name": "mintPrice",
                "type": "uint80"
              },
              {
                "internalType": "uint16",
                "name": "maxTotalMintableByWallet",
                "type": "uint16"
              },
              {
                "internalType": "uint48",
                "name": "startTime",
                "type": "uint48"
              },
              {
                "internalType": "uint48",
                "name": "endTime",
                "type": "uint48"
              },
              {
                "internalType": "uint8",
                "name": "dropStageIndex",
                "type": "uint8"
              },
              {
                "internalType": "uint32",
                "name": "maxTokenSupplyForStage",
                "type": "uint32"
              },
              {
                "internalType": "uint16",
                "name": "feeBps",
                "type": "uint16"
              },
              {
                "internalType": "bool",
                "name": "restrictFeeRecipients",
                "type": "bool"
              }
            ],
            "internalType": "struct TokenGatedDropStage[]",
            "name": "tokenGatedDropStages",
            "type": "tuple[]"
          },
          {
            "internalType": "address[]",
            "name": "disallowedTokenGatedAllowedNftTokens",
            "type": "address[]"
          },
          {
            "internalType": "address[]",
            "name": "signedMintValidationParamsSigners",
            "type": "address[]"
          },
          {
            "components": [
              {
                "internalType": "uint80",
                "name": "minMintPrice",
                "type": "uint80"
              },
              {
                "internalType": "uint24",
                "name": "maxMaxTotalMintableByWallet",
                "type": "uint24"
              },
              {
                "internalType": "uint40",
                "name": "minStartTime",
                "type": "uint40"
              },
              {
                "internalType": "uint40",
                "name": "maxEndTime",
                "type": "uint40"
              },
              {
                "internalType": "uint40",
                "name": "maxMaxTokenSupplyForStage",
                "type": "uint40"
              },
              {
                "internalType": "uint16",
                "name": "minFeeBps",
                "type": "uint16"
              },
              {
                "internalType": "uint16",
                "name": "maxFeeBps",
                "type": "uint16"
              }
            ],
            "internalType": "struct SignedMintValidationParams[]",
            "name": "signedMintValidationParams",
            "type": "tuple[]"
          },
          {
            "internalType": "address[]",
            "name": "disallowedSigners",
            "type": "address[]"
          }
        ],
        "internalType": "struct MultiConfigureStruct",
        "name": "config",
        "type": "tuple"
      }
    ],
    "name": "multiConfigure",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "name": "numMinted",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "count",
        "type": "uint256"
      }
    ],
    "name": "ownerMint",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "ownerOf",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "provenanceHash",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "id",
        "type": "uint256"
      }
    ],
    "name": "renderSVG",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renderer",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "royaltyAddress",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "royaltyBps",
    "outputs": [
      {
        "internalType": "uint96",
        "name": "",
        "type": "uint96"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "salePrice",
        "type": "uint256"
      }
    ],
    "name": "royaltyInfo",
    "outputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "royaltyAmount",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "royaltyReceiver",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "safeTransferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "safeTransferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "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": "string",
        "name": "newContractURI",
        "type": "string"
      }
    ],
    "name": "setContractURI",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "newMaxSupply",
        "type": "uint256"
      }
    ],
    "name": "setMaxSupply",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "mdata",
        "type": "address"
      }
    ],
    "name": "setMetadata",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "newProvenanceHash",
        "type": "bytes32"
      }
    ],
    "name": "setProvenanceHash",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "r",
        "type": "address"
      }
    ],
    "name": "setRenderer",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      },
      {
        "internalType": "uint96",
        "name": "feeNumerator",
        "type": "uint96"
      }
    ],
    "name": "setRoyaltyInfo",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "receiver",
            "type": "address"
          },
          {
            "internalType": "uint96",
            "name": "bps",
            "type": "uint96"
          }
        ],
        "internalType": "struct RobinhoodPixies.RoyaltyInfoArg",
        "name": "info",
        "type": "tuple"
      }
    ],
    "name": "setRoyaltyInfo",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "validator",
        "type": "address"
      }
    ],
    "name": "setTransferValidator",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes4",
        "name": "interfaceId",
        "type": "bytes4"
      }
    ],
    "name": "supportsInterface",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "tokenURI",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "transferValidator",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "bytes32",
            "name": "merkleRoot",
            "type": "bytes32"
          },
          {
            "internalType": "string[]",
            "name": "publicKeyURIs",
            "type": "string[]"
          },
          {
            "internalType": "string",
            "name": "allowListURI",
            "type": "string"
          }
        ],
        "internalType": "struct AllowListData",
        "name": "allowListData",
        "type": "tuple"
      }
    ],
    "name": "updateAllowList",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "feeRecipient",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "allowed",
        "type": "bool"
      }
    ],
    "name": "updateAllowedFeeRecipient",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address[]",
        "name": "allowedSeaDrop_",
        "type": "address[]"
      }
    ],
    "name": "updateAllowedSeaDrop",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "payoutAddress",
        "type": "address"
      }
    ],
    "name": "updateCreatorPayoutAddress",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "internalType": "string",
        "name": "dropURI",
        "type": "string"
      }
    ],
    "name": "updateDropURI",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "payer",
        "type": "address"
      },
      {
        "internalType": "bool",
        "name": "allowed",
        "type": "bool"
      }
    ],
    "name": "updatePayer",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "uint80",
            "name": "mintPrice",
            "type": "uint80"
          },
          {
            "internalType": "uint48",
            "name": "startTime",
            "type": "uint48"
          },
          {
            "internalType": "uint48",
            "name": "endTime",
            "type": "uint48"
          },
          {
            "internalType": "uint16",
            "name": "maxTotalMintableByWallet",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "feeBps",
            "type": "uint16"
          },
          {
            "internalType": "bool",
            "name": "restrictFeeRecipients",
            "type": "bool"
          }
        ],
        "internalType": "struct PublicDrop",
        "name": "publicDrop",
        "type": "tuple"
      }
    ],
    "name": "updatePublicDrop",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "signer",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "uint80",
            "name": "minMintPrice",
            "type": "uint80"
          },
          {
            "internalType": "uint24",
            "name": "maxMaxTotalMintableByWallet",
            "type": "uint24"
          },
          {
            "internalType": "uint40",
            "name": "minStartTime",
            "type": "uint40"
          },
          {
            "internalType": "uint40",
            "name": "maxEndTime",
            "type": "uint40"
          },
          {
            "internalType": "uint40",
            "name": "maxMaxTokenSupplyForStage",
            "type": "uint40"
          },
          {
            "internalType": "uint16",
            "name": "minFeeBps",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "maxFeeBps",
            "type": "uint16"
          }
        ],
        "internalType": "struct SignedMintValidationParams",
        "name": "signedMintValidationParams",
        "type": "tuple"
      }
    ],
    "name": "updateSignedMintValidationParams",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "seaDropImpl",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "allowedNftToken",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "uint80",
            "name": "mintPrice",
            "type": "uint80"
          },
          {
            "internalType": "uint16",
            "name": "maxTotalMintableByWallet",
            "type": "uint16"
          },
          {
            "internalType": "uint48",
            "name": "startTime",
            "type": "uint48"
          },
          {
            "internalType": "uint48",
            "name": "endTime",
            "type": "uint48"
          },
          {
            "internalType": "uint8",
            "name": "dropStageIndex",
            "type": "uint8"
          },
          {
            "internalType": "uint32",
            "name": "maxTokenSupplyForStage",
            "type": "uint32"
          },
          {
            "internalType": "uint16",
            "name": "feeBps",
            "type": "uint16"
          },
          {
            "internalType": "bool",
            "name": "restrictFeeRecipients",
            "type": "bool"
          }
        ],
        "internalType": "struct TokenGatedDropStage",
        "name": "dropStage",
        "type": "tuple"
      }
    ],
    "name": "updateTokenGatedDrop",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

import {PixieTraits} from "./PixieTraits.sol";
import {
    INonFungibleSeaDropToken,
    ISeaDrop,
    PublicDrop,
    AllowListData,
    TokenGatedDropStage,
    SignedMintValidationParams,
    MultiConfigureStruct
} from "./ISeaDropInterfaces.sol";

interface IPixieRenderer {
    function render(uint256 id, PixieTraits.Traits memory t) external view returns (string memory);
}

interface IPixieMetadata {
    function tokenURI(uint256 id, PixieTraits.Traits memory t, address renderer)
        external view returns (string memory);
}

/// ERC721-C creator-token transfer validator — the on-chain mechanism OpenSea
/// uses to ENFORCE creator earnings. `validateTransfer` reverts to block a
/// transfer (e.g. by a marketplace that doesn't honour royalties).
interface ITransferValidator {
    function validateTransfer(address caller, address from, address to, uint256 tokenId) external;
}

/**
 * Robinhood Pixies — a fully on-chain ERC721 forest of 10,000 deterministic
 * pixel pixies. tokenId IS the seed: every trait (PixieTraits) and every pixel
 * of the artwork (PixieRenderer, via `tokenURI`) is derived from the id and
 * rendered in Solidity — no IPFS, no server, no external image. Eight ids
 * (625, 1875, … 9375) are the hand-crafted 1/1 legends, exactly where the
 * design's generator places them. Same token, same pixie, forever.
 *
 * SeaDrop-native (managed through OpenSea Studio) — same integration pattern
 * as On-Chain Ships / On-Chain Bonsai: the canonical SeaDrop singleton
 * 0x00005EA00Ac477B1030CE78506496e8C2dE24bf5 calls `mintSeaDrop` + `getMintStats`,
 * and every drop/allowlist/fee/royalty setting is forwarded from Studio.
 */
contract RobinhoodPixies is ERC721, Ownable, INonFungibleSeaDropToken {
    uint256 public constant MAX_SUPPLY = 6969;

    uint256 public totalSupply;
    address public renderer;
    address public metadata;

    // ───────────────────────── SEADROP ─────────────────────────
    /// SeaDrop addresses authorized to call `mintSeaDrop`. Canonical mainnet +
    /// testnet SeaDrop is `0x00005EA00Ac477B1030CE78506496e8C2dE24bf5`.
    mapping(address => bool) public allowedSeaDrop;
    /// Per-minter mint count — drives SeaDrop's per-wallet caps via
    /// `getMintStats`. Only `mintSeaDrop` bumps this; `ownerMint` does not.
    mapping(address => uint256) public numMinted;
    address[] internal _enumeratedAllowedSeaDrop;

    // ─────────────────── OPENSEA STUDIO METADATA SURFACE ───────────────────
    // Plain storage so Studio's `multiConfigure` bulk-publish doesn't trip on
    // missing setters. None of these affect mint logic; the hard cap is
    // MAX_SUPPLY regardless of `displayMaxSupply`.
    uint256 public displayMaxSupply;
    string  private _baseURIStorage;
    string  private _contractURI;
    bytes32 public  provenanceHash;

    // Inline ERC2981 royalty (default royalty only).
    address public royaltyReceiver;
    uint96  public royaltyBps;

    // ── ERC721-C creator-token standard (creator-earnings enforcement) ──
    // When set to a real validator contract, EVERY holder-to-holder transfer is
    // gated by it — this is what lets OpenSea show/enforce creator earnings.
    // Zero address = no validation (mints, burns and transfers pass freely).
    address public transferValidator;

    event Minted(uint256 indexed tokenId, address indexed to);
    event TransferValidatorUpdated(address oldValidator, address newValidator);
    event AllowedSeaDropUpdated(address[] allowedSeaDrop);
    event RendererUpdated(address indexed renderer);
    event MetadataUpdated(address indexed metadata);
    event MaxSupplyUpdated(uint256 newMaxSupply);
    event BaseURIUpdated(string newBaseURI);
    event ContractURIUpdated(string newContractURI);
    event ProvenanceHashUpdated(bytes32 previousHash, bytes32 newHash);
    event RoyaltyInfoUpdated(address receiver, uint96 bps);
    event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);

    error SoldOut();
    error NonexistentToken(uint256 tokenId);
    error OutOfRange();
    error ZeroAddress();
    error OnlyAllowedSeaDrop();
    error LengthMismatch();
    error NotOwnerOrSelf();
    error ExceedsHardCap();

    constructor(
        address initialOwner,
        address _renderer,
        address _metadata,
        address[] memory allowedSeaDrop_
    )
        ERC721("Robinhood Pixies", "PIXIE")
        Ownable(initialOwner)
    {
        if (_renderer == address(0) || _metadata == address(0)) revert ZeroAddress();
        renderer = _renderer;
        metadata = _metadata;
        displayMaxSupply = MAX_SUPPLY;
        royaltyReceiver = initialOwner;
        royaltyBps = 500; // 5% default creator earnings
        emit RendererUpdated(_renderer);
        emit MetadataUpdated(_metadata);
        emit MaxSupplyUpdated(MAX_SUPPLY);
        emit RoyaltyInfoUpdated(initialOwner, 500);

        for (uint256 k = 0; k < allowedSeaDrop_.length; k++) {
            address sd = allowedSeaDrop_[k];
            if (sd == address(0)) revert ZeroAddress();
            if (!allowedSeaDrop[sd]) {
                allowedSeaDrop[sd] = true;
                _enumeratedAllowedSeaDrop.push(sd);
            }
        }
        emit AllowedSeaDropUpdated(allowedSeaDrop_);
    }

    // ═══════════════════════ MINT ═══════════════════════

    /// SeaDrop mint entrypoint — called by the allowlisted SeaDrop singleton
    /// AFTER it has taken payment + enforced per-wallet / per-stage / fee splits
    /// via `getMintStats`.
    function mintSeaDrop(address minter, uint256 quantity) external payable {
        if (!allowedSeaDrop[msg.sender]) revert OnlyAllowedSeaDrop();
        if (totalSupply + quantity > MAX_SUPPLY) revert SoldOut();
        for (uint256 i = 0; i < quantity; i++) {
            uint256 id = ++totalSupply;
            _safeMint(minter, id);
            emit Minted(id, minter);
        }
        numMinted[minter] += quantity;
    }

    function ownerMint(address to, uint256 count) external onlyOwner {
        for (uint256 i = 0; i < count; i++) {
            if (totalSupply >= MAX_SUPPLY) revert SoldOut();
            uint256 id = ++totalSupply;
            _safeMint(to, id);
            emit Minted(id, to);
        }
    }

    // ─────────────────── SEADROP VIEWS + FORWARDERS ───────────────────

    function getMintStats(address minter)
        external
        view
        returns (uint256 minterNumMinted, uint256 currentTotalSupply, uint256 maxSupply_)
    {
        minterNumMinted = numMinted[minter];
        currentTotalSupply = totalSupply;
        maxSupply_ = displayMaxSupply;
    }

    function maxSupply() external view returns (uint256) { return displayMaxSupply; }

    function getAllowedSeaDrop() external view returns (address[] memory) {
        return _enumeratedAllowedSeaDrop;
    }

    modifier onlyAllowedSeaDrop(address seaDropImpl) {
        if (!allowedSeaDrop[seaDropImpl]) revert OnlyAllowedSeaDrop();
        _;
    }

    modifier onlyOwnerOrSelf() {
        if (msg.sender != owner() && msg.sender != address(this)) revert NotOwnerOrSelf();
        _;
    }

    function updateAllowedSeaDrop(address[] calldata allowedSeaDrop_) external onlyOwner {
        for (uint256 i = 0; i < _enumeratedAllowedSeaDrop.length; i++) {
            allowedSeaDrop[_enumeratedAllowedSeaDrop[i]] = false;
        }
        delete _enumeratedAllowedSeaDrop;
        for (uint256 i = 0; i < allowedSeaDrop_.length; i++) {
            address sd = allowedSeaDrop_[i];
            if (sd == address(0)) revert ZeroAddress();
            if (!allowedSeaDrop[sd]) {
                allowedSeaDrop[sd] = true;
                _enumeratedAllowedSeaDrop.push(sd);
            }
        }
        emit AllowedSeaDropUpdated(allowedSeaDrop_);
    }

    function updatePublicDrop(address seaDropImpl, PublicDrop calldata publicDrop)
        external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl)
    {
        ISeaDrop(seaDropImpl).updatePublicDrop(publicDrop);
    }

    function updateAllowList(address seaDropImpl, AllowListData calldata allowListData)
        external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl)
    {
        ISeaDrop(seaDropImpl).updateAllowList(allowListData);
    }

    function updateTokenGatedDrop(
        address seaDropImpl,
        address allowedNftToken,
        TokenGatedDropStage calldata dropStage
    ) external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl) {
        ISeaDrop(seaDropImpl).updateTokenGatedDrop(allowedNftToken, dropStage);
    }

    function updateDropURI(address seaDropImpl, string calldata dropURI)
        external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl)
    {
        ISeaDrop(seaDropImpl).updateDropURI(dropURI);
    }

    function updateCreatorPayoutAddress(address seaDropImpl, address payoutAddress)
        external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl)
    {
        ISeaDrop(seaDropImpl).updateCreatorPayoutAddress(payoutAddress);
    }

    function updateAllowedFeeRecipient(address seaDropImpl, address feeRecipient, bool allowed)
        external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl)
    {
        ISeaDrop(seaDropImpl).updateAllowedFeeRecipient(feeRecipient, allowed);
    }

    function updateSignedMintValidationParams(
        address seaDropImpl,
        address signer,
        SignedMintValidationParams calldata signedMintValidationParams
    ) external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl) {
        ISeaDrop(seaDropImpl).updateSignedMintValidationParams(signer, signedMintValidationParams);
    }

    function updatePayer(address seaDropImpl, address payer, bool allowed)
        external onlyOwnerOrSelf onlyAllowedSeaDrop(seaDropImpl)
    {
        ISeaDrop(seaDropImpl).updatePayer(payer, allowed);
    }

    // ─────────────────── COLLECTION-METADATA SETTERS ───────────────────

    function setMaxSupply(uint256 newMaxSupply) external onlyOwnerOrSelf {
        if (newMaxSupply > MAX_SUPPLY) revert ExceedsHardCap();
        displayMaxSupply = newMaxSupply;
        emit MaxSupplyUpdated(newMaxSupply);
    }

    function setBaseURI(string calldata newBaseURI) external onlyOwnerOrSelf {
        _baseURIStorage = newBaseURI;
        emit BaseURIUpdated(newBaseURI);
    }

    function baseURI() external view returns (string memory) { return _baseURIStorage; }

    function setContractURI(string calldata newContractURI) external onlyOwnerOrSelf {
        _contractURI = newContractURI;
        emit ContractURIUpdated(newContractURI);
    }

    function contractURI() external view returns (string memory) { return _contractURI; }

    function setProvenanceHash(bytes32 newProvenanceHash) external onlyOwnerOrSelf {
        bytes32 prev = provenanceHash;
        provenanceHash = newProvenanceHash;
        emit ProvenanceHashUpdated(prev, newProvenanceHash);
    }

    function setRoyaltyInfo(address receiver, uint96 feeNumerator) public onlyOwner {
        require(feeNumerator <= 10000, "bps>10000");
        royaltyReceiver = receiver;
        royaltyBps = feeNumerator;
        emit RoyaltyInfoUpdated(receiver, feeNumerator);
    }

    struct RoyaltyInfoArg { address receiver; uint96 bps; }
    function setRoyaltyInfo(RoyaltyInfoArg calldata info) external onlyOwner {
        setRoyaltyInfo(info.receiver, info.bps);
    }

    function royaltyAddress() external view returns (address) { return royaltyReceiver; }

    function royaltyInfo(uint256, uint256 salePrice)
        external view returns (address receiver, uint256 royaltyAmount)
    {
        receiver = royaltyReceiver;
        royaltyAmount = (salePrice * royaltyBps) / 10000;
    }

    function emitBatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId) external onlyOwner {
        emit BatchMetadataUpdate(fromTokenId, toTokenId);
    }

    // ─────────────────── multiConfigure (0x911f456b) ───────────────────

    function multiConfigure(MultiConfigureStruct calldata config) external onlyOwner {
        if (config.maxSupply > 0 && config.maxSupply != displayMaxSupply) {
            this.setMaxSupply(config.maxSupply);
        }
        if (bytes(config.baseURI).length != 0) this.setBaseURI(config.baseURI);
        if (bytes(config.contractURI).length != 0) this.setContractURI(config.contractURI);
        if (config.publicDrop.startTime != 0 || config.publicDrop.endTime != 0) {
            this.updatePublicDrop(config.seaDropImpl, config.publicDrop);
        }
        if (bytes(config.dropURI).length != 0) this.updateDropURI(config.seaDropImpl, config.dropURI);
        if (config.allowListData.merkleRoot != bytes32(0)) {
            this.updateAllowList(config.seaDropImpl, config.allowListData);
        }
        if (config.creatorPayoutAddress != address(0)) {
            this.updateCreatorPayoutAddress(config.seaDropImpl, config.creatorPayoutAddress);
        }
        if (config.provenanceHash != bytes32(0)) this.setProvenanceHash(config.provenanceHash);
        for (uint256 i = 0; i < config.allowedFeeRecipients.length; i++) {
            this.updateAllowedFeeRecipient(config.seaDropImpl, config.allowedFeeRecipients[i], true);
        }
        for (uint256 i = 0; i < config.disallowedFeeRecipients.length; i++) {
            this.updateAllowedFeeRecipient(config.seaDropImpl, config.disallowedFeeRecipients[i], false);
        }
        for (uint256 i = 0; i < config.allowedPayers.length; i++) {
            this.updatePayer(config.seaDropImpl, config.allowedPayers[i], true);
        }
        for (uint256 i = 0; i < config.disallowedPayers.length; i++) {
            this.updatePayer(config.seaDropImpl, config.disallowedPayers[i], false);
        }
        if (config.tokenGatedAllowedNftTokens.length != config.tokenGatedDropStages.length) {
            revert LengthMismatch();
        }
        for (uint256 i = 0; i < config.tokenGatedAllowedNftTokens.length; i++) {
            this.updateTokenGatedDrop(
                config.seaDropImpl, config.tokenGatedAllowedNftTokens[i], config.tokenGatedDropStages[i]
            );
        }
        TokenGatedDropStage memory emptyStage;
        for (uint256 i = 0; i < config.disallowedTokenGatedAllowedNftTokens.length; i++) {
            this.updateTokenGatedDrop(config.seaDropImpl, config.disallowedTokenGatedAllowedNftTokens[i], emptyStage);
        }
        if (config.signedMintValidationParamsSigners.length != config.signedMintValidationParams.length) {
            revert LengthMismatch();
        }
        for (uint256 i = 0; i < config.signedMintValidationParamsSigners.length; i++) {
            this.updateSignedMintValidationParams(
                config.seaDropImpl, config.signedMintValidationParamsSigners[i], config.signedMintValidationParams[i]
            );
        }
        SignedMintValidationParams memory emptySigned;
        for (uint256 i = 0; i < config.disallowedSigners.length; i++) {
            this.updateSignedMintValidationParams(config.seaDropImpl, config.disallowedSigners[i], emptySigned);
        }
    }

    // ═══════════════════════ RENDER / METADATA ═══════════════════════

    /// Raw SVG for any id in 1..MAX_SUPPLY — works for un-minted ids too, so
    /// front-ends can preview the whole forest deterministically.
    function renderSVG(uint256 id) public view returns (string memory) {
        if (id == 0 || id > MAX_SUPPLY) revert OutOfRange();
        return IPixieRenderer(renderer).render(id, PixieTraits.derive(id));
    }

    function tokenURI(uint256 tokenId) public view override returns (string memory) {
        _requireOwned(tokenId);
        return IPixieMetadata(metadata).tokenURI(tokenId, PixieTraits.derive(tokenId), renderer);
    }

    // ═══════════════════════ ERC165 / OWNER ═══════════════════════

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return
            interfaceId == type(INonFungibleSeaDropToken).interfaceId ||
            interfaceId == 0x2a55205a /* IERC2981 */ ||
            interfaceId == 0x49064906 /* IERC4906 */ ||
            interfaceId == 0xad0d7f6c /* ICreatorToken */ ||
            super.supportsInterface(interfaceId);
    }

    // ─────────────────── ERC721-C: creator-token transfer validator ───────────────────

    function getTransferValidator() external view returns (address) {
        return transferValidator;
    }

    /// Tells integrators (OpenSea, Limit Break) which function to call on the
    /// validator and that it is a view call.
    function getTransferValidationFunction()
        external
        pure
        returns (bytes4 functionSignature, bool isViewFunction)
    {
        return (ITransferValidator.validateTransfer.selector, true);
    }

    function setTransferValidator(address validator) external onlyOwner {
        address old = transferValidator;
        transferValidator = validator;
        emit TransferValidatorUpdated(old, validator);
    }

    /// OZ v5 transfer hook. Mints (from == 0) and burns (to == 0) are never
    /// gated; a real holder-to-holder transfer is validated by the configured
    /// validator, which reverts to block disallowed operators.
    function _update(address to, uint256 tokenId, address auth)
        internal
        virtual
        override
        returns (address from)
    {
        from = super._update(to, tokenId, auth);
        address validator = transferValidator;
        if (validator != address(0) && from != address(0) && to != address(0)) {
            ITransferValidator(validator).validateTransfer(_msgSender(), from, to, tokenId);
        }
    }

    function setRenderer(address r) external onlyOwner {
        if (r == address(0)) revert ZeroAddress();
        renderer = r;
        emit RendererUpdated(r);
    }

    function setMetadata(address mdata) external onlyOwner {
        if (mdata == address(0)) revert ZeroAddress();
        metadata = mdata;
        emit MetadataUpdated(mdata);
    }
}
Chain explorer3615msChain node86ms