ERC721SeaDrop
0x74f46bdc53ed7652f3038622e419bd4cd6a9ca57
Verification
Verified
v0.8.17+commit.8df45f5f
Type
Contract
19,658 bytes
ABI entries
89
20 read · 28 write
License
none
Contract information
- Address
- 0x74f46bdc53ed7652f3038622e419bd4cd6a9ca57
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.17+commit.8df45f5f
- Optimization
- Enabled
- Creator
- 0xbe94988b54…5fD4B8e111
- Creation tx
- 0xa4443cdc00…392085e7cb
Token
- Name
- Robin Rebels
- Symbol
- SHILL
- Decimals
- —
- Holders
- 1,030
- Market
- View token page →
Read contract (20)
balanceOf(address) → uint256
baseURI() → string
contractURI() → string
getApproved(uint256) → address
getMintStats(address) → uint256, uint256, uint256
getTransferValidationFunction() → bytes4, bool
getTransferValidator() → address
isApprovedForAll(address, address) → bool
maxSupply() → uint256
name() → string
owner() → address
ownerOf(uint256) → address
provenanceHash() → bytes32
royaltyAddress() → address
royaltyBasisPoints() → uint256
royaltyInfo(uint256, uint256) → address, uint256
supportsInterface(bytes4) → bool
symbol() → string
tokenURI(uint256) → string
totalSupply() → uint256
Events (14)
AllowedSeaDropUpdatedApprovalApprovalForAllBatchMetadataUpdateConsecutiveTransferContractURIUpdatedMaxSupplyUpdatedOwnershipTransferredPotentialOwnerUpdatedProvenanceHashUpdatedRoyaltyInfoUpdatedSeaDropTokenDeployedTransferTransferValidatorUpdated
ABI
[
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address[]",
"name": "allowedSeaDrop",
"type": "address[]"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AlreadyInitialized",
"type": "error"
},
{
"inputs": [],
"name": "ApprovalCallerNotOwnerNorApproved",
"type": "error"
},
{
"inputs": [],
"name": "ApprovalQueryForNonexistentToken",
"type": "error"
},
{
"inputs": [],
"name": "BalanceQueryForZeroAddress",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newMaxSupply",
"type": "uint256"
}
],
"name": "CannotExceedMaxSupplyOfUint64",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "basisPoints",
"type": "uint256"
}
],
"name": "InvalidRoyaltyBasisPoints",
"type": "error"
},
{
"inputs": [],
"name": "MintERC2309QuantityExceedsLimit",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "total",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxSupply",
"type": "uint256"
}
],
"name": "MintQuantityExceedsMaxSupply",
"type": "error"
},
{
"inputs": [],
"name": "MintToZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "MintZeroQuantity",
"type": "error"
},
{
"inputs": [],
"name": "NewOwnerIsZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "NotNextOwner",
"type": "error"
},
{
"inputs": [],
"name": "OnlyAllowedSeaDrop",
"type": "error"
},
{
"inputs": [],
"name": "OnlyOwner",
"type": "error"
},
{
"inputs": [],
"name": "OwnerQueryForNonexistentToken",
"type": "error"
},
{
"inputs": [],
"name": "OwnershipNotInitializedForExtraData",
"type": "error"
},
{
"inputs": [],
"name": "ProvenanceHashCannotBeSetAfterMintStarted",
"type": "error"
},
{
"inputs": [],
"name": "RoyaltyAddressCannotBeZeroAddress",
"type": "error"
},
{
"inputs": [],
"name": "SameTransferValidator",
"type": "error"
},
{
"inputs": [],
"name": "SignersMismatch",
"type": "error"
},
{
"inputs": [],
"name": "TokenGatedMismatch",
"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": 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": "uint256",
"name": "_fromTokenId",
"type": "uint256"
},
{
"indexed": false,
"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": 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": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "newPotentialAdministrator",
"type": "address"
}
],
"name": "PotentialOwnerUpdated",
"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": false,
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "bps",
"type": "uint256"
}
],
"name": "RoyaltyInfoUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [],
"name": "SeaDropTokenDeployed",
"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": "acceptOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "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": "tokenId",
"type": "uint256"
}
],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "cancelOwnershipTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "contractURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"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": [
{
"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": [
{
"internalType": "address",
"name": "minter",
"type": "address"
},
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"name": "mintSeaDrop",
"outputs": [],
"stateMutability": "nonpayable",
"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": "signers",
"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 ERC721SeaDropStructsErrorsAndEvents.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": [],
"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": "provenanceHash",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"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": "royaltyBasisPoints",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"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": [
{
"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": "bytes32",
"name": "newProvenanceHash",
"type": "bytes32"
}
],
"name": "setProvenanceHash",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "royaltyAddress",
"type": "address"
},
{
"internalType": "uint96",
"name": "royaltyBps",
"type": "uint96"
}
],
"internalType": "struct ISeaDropTokenContractMetadata.RoyaltyInfo",
"name": "newInfo",
"type": "tuple"
}
],
"name": "setRoyaltyInfo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newValidator",
"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": "newPotentialOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"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.17;
import {
ERC721ContractMetadata,
ISeaDropTokenContractMetadata
} from "./ERC721ContractMetadata.sol";
import {
INonFungibleSeaDropToken
} from "./interfaces/INonFungibleSeaDropToken.sol";
import { ISeaDrop } from "./interfaces/ISeaDrop.sol";
import {
AllowListData,
PublicDrop,
TokenGatedDropStage,
SignedMintValidationParams
} from "./lib/SeaDropStructs.sol";
import {
ERC721SeaDropStructsErrorsAndEvents
} from "./lib/ERC721SeaDropStructsErrorsAndEvents.sol";
import { ERC721A } from "ERC721A/ERC721A.sol";
import { ReentrancyGuard } from "solmate/utils/ReentrancyGuard.sol";
import {
IERC165
} from "openzeppelin-contracts/utils/introspection/IERC165.sol";
/**
* @title ERC721SeaDrop
* @author James Wenzel (emo.eth)
* @author Ryan Ghods (ralxz.eth)
* @author Stephan Min (stephanm.eth)
* @author Michael Cohen (notmichael.eth)
* @custom:contributor Limit Break (@limitbreak)
* @notice ERC721SeaDrop is a token contract that contains methods
* to properly interact with SeaDrop.
* Implements Limit Break's Creator Token Standards transfer
* validation for royalty enforcement.
*/
contract ERC721SeaDrop is
ERC721ContractMetadata,
INonFungibleSeaDropToken,
ERC721SeaDropStructsErrorsAndEvents,
ReentrancyGuard
{
/// @notice Track the allowed SeaDrop addresses.
mapping(address => bool) internal _allowedSeaDrop;
/// @notice Track the enumerated allowed SeaDrop addresses.
address[] internal _enumeratedAllowedSeaDrop;
/**
* @dev Reverts if not an allowed SeaDrop contract.
* This function is inlined instead of being a modifier
* to save contract space from being inlined N times.
*
* @param seaDrop The SeaDrop address to check if allowed.
*/
function _onlyAllowedSeaDrop(address seaDrop) internal view {
if (_allowedSeaDrop[seaDrop] != true) {
revert OnlyAllowedSeaDrop();
}
}
/**
* @notice Deploy the token contract with its name, symbol,
* and allowed SeaDrop addresses.
*/
constructor(
string memory name,
string memory symbol,
address[] memory allowedSeaDrop
) ERC721ContractMetadata(name, symbol) {
// Put the length on the stack for more efficient access.
uint256 allowedSeaDropLength = allowedSeaDrop.length;
// Set the mapping for allowed SeaDrop contracts.
for (uint256 i = 0; i < allowedSeaDropLength; ) {
_allowedSeaDrop[allowedSeaDrop[i]] = true;
unchecked {
++i;
}
}
// Set the enumeration.
_enumeratedAllowedSeaDrop = allowedSeaDrop;
// Emit an event noting the contract deployment.
emit SeaDropTokenDeployed();
}
/**
* @notice Update the allowed SeaDrop contracts.
* Only the owner can use this function.
*
* @param allowedSeaDrop The allowed SeaDrop addresses.
*/
function updateAllowedSeaDrop(address[] calldata allowedSeaDrop)
external
virtual
override
onlyOwner
{
_updateAllowedSeaDrop(allowedSeaDrop);
}
/**
* @notice Internal function to update the allowed SeaDrop contracts.
*
* @param allowedSeaDrop The allowed SeaDrop addresses.
*/
function _updateAllowedSeaDrop(address[] calldata allowedSeaDrop) internal {
// Put the length on the stack for more efficient access.
uint256 enumeratedAllowedSeaDropLength = _enumeratedAllowedSeaDrop
.length;
uint256 allowedSeaDropLength = allowedSeaDrop.length;
// Reset the old mapping.
for (uint256 i = 0; i < enumeratedAllowedSeaDropLength; ) {
_allowedSeaDrop[_enumeratedAllowedSeaDrop[i]] = false;
unchecked {
++i;
}
}
// Set the new mapping for allowed SeaDrop contracts.
for (uint256 i = 0; i < allowedSeaDropLength; ) {
_allowedSeaDrop[allowedSeaDrop[i]] = true;
unchecked {
++i;
}
}
// Set the enumeration.
_enumeratedAllowedSeaDrop = allowedSeaDrop;
// Emit an event for the update.
emit AllowedSeaDropUpdated(allowedSeaDrop);
}
/**
* @notice Burns `tokenId`. The caller must own `tokenId` or be an
* approved operator.
*
* @param tokenId The token id to burn.
*/
// solhint-disable-next-line comprehensive-interface
function burn(uint256 tokenId) external {
_burn(tokenId, true);
}
/**
* @dev Overrides the `_startTokenId` function from ERC721A
* to start at token id `1`.
*
* This is to avoid future possible problems since `0` is usually
* used to signal values that have not been set or have been removed.
*/
function _startTokenId() internal view virtual override returns (uint256) {
return 1;
}
/**
* @dev Overrides the `tokenURI()` function from ERC721A
* to return just the base URI if it is implied to not be a directory.
*
* This is to help with ERC721 contracts in which the same token URI
* is desired for each token, such as when the tokenURI is 'unrevealed'.
*/
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
// Exit early if the baseURI is empty.
if (bytes(baseURI).length == 0) {
return "";
}
// Check if the last character in baseURI is a slash.
if (bytes(baseURI)[bytes(baseURI).length - 1] != bytes("/")[0]) {
return baseURI;
}
return string(abi.encodePacked(baseURI, _toString(tokenId)));
}
/**
* @notice Mint tokens, restricted to the SeaDrop contract.
*
* @dev NOTE: If a token registers itself with multiple SeaDrop
* contracts, the implementation of this function should guard
* against reentrancy. If the implementing token uses
* _safeMint(), or a feeRecipient with a malicious receive() hook
* is specified, the token or fee recipients may be able to execute
* another mint in the same transaction via a separate SeaDrop
* contract.
* This is dangerous if an implementing token does not correctly
* update the minterNumMinted and currentTotalSupply values before
* transferring minted tokens, as SeaDrop references these values
* to enforce token limits on a per-wallet and per-stage basis.
*
* ERC721A tracks these values automatically, but this note and
* nonReentrant modifier are left here to encourage best-practices
* when referencing this contract.
*
* @param minter The address to mint to.
* @param quantity The number of tokens to mint.
*/
function mintSeaDrop(address minter, uint256 quantity)
external
virtual
override
nonReentrant
{
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(msg.sender);
// Extra safety check to ensure the max supply is not exceeded.
if (_totalMinted() + quantity > maxSupply()) {
revert MintQuantityExceedsMaxSupply(
_totalMinted() + quantity,
maxSupply()
);
}
// Mint the quantity of tokens to the minter.
_safeMint(minter, quantity);
}
/**
* @notice Update the public drop data for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param publicDrop The public drop data.
*/
function updatePublicDrop(
address seaDropImpl,
PublicDrop calldata publicDrop
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the public drop data on SeaDrop.
ISeaDrop(seaDropImpl).updatePublicDrop(publicDrop);
}
/**
* @notice Update the allow list data for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param allowListData The allow list data.
*/
function updateAllowList(
address seaDropImpl,
AllowListData calldata allowListData
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the allow list on SeaDrop.
ISeaDrop(seaDropImpl).updateAllowList(allowListData);
}
/**
* @notice Update the token gated drop stage data for this nft contract
* on SeaDrop.
* Only the owner can use this function.
*
* Note: If two INonFungibleSeaDropToken tokens are doing
* simultaneous token gated drop promotions for each other,
* they can be minted by the same actor until
* `maxTokenSupplyForStage` is reached. Please ensure the
* `allowedNftToken` is not running an active drop during the
* `dropStage` time period.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param allowedNftToken The allowed nft token.
* @param dropStage The token gated drop stage data.
*/
function updateTokenGatedDrop(
address seaDropImpl,
address allowedNftToken,
TokenGatedDropStage calldata dropStage
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the token gated drop stage.
ISeaDrop(seaDropImpl).updateTokenGatedDrop(allowedNftToken, dropStage);
}
/**
* @notice Update the drop URI for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param dropURI The new drop URI.
*/
function updateDropURI(address seaDropImpl, string calldata dropURI)
external
virtual
override
{
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the drop URI.
ISeaDrop(seaDropImpl).updateDropURI(dropURI);
}
/**
* @notice Update the creator payout address for this nft contract on
* SeaDrop.
* Only the owner can set the creator payout address.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param payoutAddress The new payout address.
*/
function updateCreatorPayoutAddress(
address seaDropImpl,
address payoutAddress
) external {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the creator payout address.
ISeaDrop(seaDropImpl).updateCreatorPayoutAddress(payoutAddress);
}
/**
* @notice Update the allowed fee recipient for this nft contract
* on SeaDrop.
* Only the owner can set the allowed fee recipient.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param feeRecipient The new fee recipient.
* @param allowed If the fee recipient is allowed.
*/
function updateAllowedFeeRecipient(
address seaDropImpl,
address feeRecipient,
bool allowed
) external virtual {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the allowed fee recipient.
ISeaDrop(seaDropImpl).updateAllowedFeeRecipient(feeRecipient, allowed);
}
/**
* @notice Update the server-side signers for this nft contract
* on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param signer The signer to update.
* @param signedMintValidationParams Minimum and maximum parameters to
* enforce for signed mints.
*/
function updateSignedMintValidationParams(
address seaDropImpl,
address signer,
SignedMintValidationParams memory signedMintValidationParams
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the signer.
ISeaDrop(seaDropImpl).updateSignedMintValidationParams(
signer,
signedMintValidationParams
);
}
/**
* @notice Update the allowed payers for this nft contract on SeaDrop.
* Only the owner can use this function.
*
* @param seaDropImpl The allowed SeaDrop contract.
* @param payer The payer to update.
* @param allowed Whether the payer is allowed.
*/
function updatePayer(
address seaDropImpl,
address payer,
bool allowed
) external virtual override {
// Ensure the sender is only the owner or contract itself.
_onlyOwnerOrSelf();
// Ensure the SeaDrop is allowed.
_onlyAllowedSeaDrop(seaDropImpl);
// Update the payer.
ISeaDrop(seaDropImpl).updatePayer(payer, allowed);
}
/**
* @notice Returns a set of mint stats for the address.
* This assists SeaDrop in enforcing maxSupply,
* maxTotalMintableByWallet, and maxTokenSupplyForStage checks.
*
* @dev NOTE: Implementing contracts should always update these numbers
* before transferring any tokens with _safeMint() to mitigate
* consequences of malicious onERC721Received() hooks.
*
* @param minter The minter address.
*/
function getMintStats(address minter)
external
view
override
returns (
uint256 minterNumMinted,
uint256 currentTotalSupply,
uint256 maxSupply
)
{
minterNumMinted = _numberMinted(minter);
currentTotalSupply = _totalMinted();
maxSupply = _maxSupply;
}
/**
* @notice Returns whether the interface is supported.
*
* @param interfaceId The interface id to check against.
*/
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC165, ERC721ContractMetadata)
returns (bool)
{
return
interfaceId == type(INonFungibleSeaDropToken).interfaceId ||
interfaceId == type(ISeaDropTokenContractMetadata).interfaceId ||
// ERC721ContractMetadata returns supportsInterface true for
// EIP-2981
// ERC721A returns supportsInterface true for
// ERC165, ERC721, ERC721Metadata
super.supportsInterface(interfaceId);
}
/**
* @notice Configure multiple properties at a time.
*
* Note: The individual configure methods should be used
* to unset or reset any properties to zero, as this method
* will ignore zero-value properties in the config struct.
*
* @param config The configuration struct.
*/
function multiConfigure(MultiConfigureStruct calldata config)
external
onlyOwner
{
if (config.maxSupply > 0) {
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 (
_cast(config.publicDrop.startTime != 0) |
_cast(config.publicDrop.endTime != 0) ==
1
) {
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);
}
if (config.allowedFeeRecipients.length > 0) {
for (uint256 i = 0; i < config.allowedFeeRecipients.length; ) {
this.updateAllowedFeeRecipient(
config.seaDropImpl,
config.allowedFeeRecipients[i],
true
);
unchecked {
++i;
}
}
}
if (config.disallowedFeeRecipients.length > 0) {
for (uint256 i = 0; i < config.disallowedFeeRecipients.length; ) {
this.updateAllowedFeeRecipient(
config.seaDropImpl,
config.disallowedFeeRecipients[i],
false
);
unchecked {
++i;
}
}
}
if (config.allowedPayers.length > 0) {
for (uint256 i = 0; i < config.allowedPayers.length; ) {
this.updatePayer(
config.seaDropImpl,
config.allowedPayers[i],
true
);
unchecked {
++i;
}
}
}
if (config.disallowedPayers.length > 0) {
for (uint256 i = 0; i < config.disallowedPayers.length; ) {
this.updatePayer(
config.seaDropImpl,
config.disallowedPayers[i],
false
);
unchecked {
++i;
}
}
}
if (config.tokenGatedDropStages.length > 0) {
if (
config.tokenGatedDropStages.length !=
config.tokenGatedAllowedNftTokens.length
) {
revert TokenGatedMismatch();
}
for (uint256 i = 0; i < config.tokenGatedDropStages.length; ) {
this.updateTokenGatedDrop(
config.seaDropImpl,
config.tokenGatedAllowedNftTokens[i],
config.tokenGatedDropStages[i]
);
unchecked {
++i;
}
}
}
if (config.disallowedTokenGatedAllowedNftTokens.length > 0) {
for (
uint256 i = 0;
i < config.disallowedTokenGatedAllowedNftTokens.length;
) {
TokenGatedDropStage memory emptyStage;
this.updateTokenGatedDrop(
config.seaDropImpl,
config.disallowedTokenGatedAllowedNftTokens[i],
emptyStage
);
unchecked {
++i;
}
}
}
if (config.signedMintValidationParams.length > 0) {
if (
config.signedMintValidationParams.length !=
config.signers.length
) {
revert SignersMismatch();
}
for (
uint256 i = 0;
i < config.signedMintValidationParams.length;
) {
this.updateSignedMintValidationParams(
config.seaDropImpl,
config.signers[i],
config.signedMintValidationParams[i]
);
unchecked {
++i;
}
}
}
if (config.disallowedSigners.length > 0) {
for (uint256 i = 0; i < config.disallowedSigners.length; ) {
SignedMintValidationParams memory emptyParams;
this.updateSignedMintValidationParams(
config.seaDropImpl,
config.disallowedSigners[i],
emptyParams
);
unchecked {
++i;
}
}
}
}
}
Chain explorer1264msChain node121ms