RobinWoodPlank
0x327ceaaedbbcf55f40d6f1abc71bd9bc8adcb156
Verification
Verified
v0.8.27+commit.40a35a09
Type
Contract
12,350 bytes
ABI entries
119
46 read · 21 write
License
none
Contract information
- Address
- 0x327ceaaedbbcf55f40d6f1abc71bd9bc8adcb156
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.27+commit.40a35a09
- Optimization
- Enabled
- Creator
- 0x9F41aF1fCF…6B24B36EF6
- Creation tx
- 0x072c01ae10…9360c62169
Token
- Name
- RobinWood
- Symbol
- PLANK
- Decimals
- —
- Holders
- 348
- Market
- View token page →
Read contract (46)
COMMUNITY_POOL() → uint256
INITIAL_NON_COMMUNITY_ALLOCATION() → uint256
MAX_ALLOWLIST_PER_WALLET() → uint256
MAX_FREE_PER_WALLET() → uint256
MAX_PAID_PER_TRANSACTION() → uint256
MAX_PAID_PER_WALLET() → uint256
MAX_SUPPLY() → uint256
allowlistMintsByWallet(address) → uint256
allowlistMintsClaimed() → uint256
balanceOf(address) → uint256
communityMintsClaimed() → uint256
communitySupplyReleased() → bool
contractBalance() → uint256
currentNonCommunityCap() → uint256
freeMintsByWallet(address) → uint256
freeMintsClaimed() → uint256
getApproved(uint256) → address
isAllowlisted(address, bytes32[]) → bool
isApprovedForAll(address, address) → bool
merkleRoot() → bytes32
mintPrice() → uint256
name() → string
nextTokenId() → uint256
nonCommunityMintsClaimed() → uint256
owner() → address
ownerMintsClaimed() → uint256
ownerOf(uint256) → address
paidMintsByWallet(address) → uint256
paidMintsClaimed() → uint256
paused() → bool
publicMintCost(uint256) → uint256
remainingAllowlistMintsForWallet(address) → uint256
remainingCommunitySupply() → uint256
remainingFreeMintsForWallet(address) → uint256
remainingNonCommunitySupply() → uint256
remainingPaidMintsForWallet(address) → uint256
remainingTotalSupply() → uint256
royaltyInfo(uint256, uint256) → address, uint256
salePhase() → uint8
supportsInterface(bytes4) → bool
symbol() → string
tokenByIndex(uint256) → uint256
tokenOfOwnerByIndex(address, uint256) → uint256
tokenURI(uint256) → string
totalCommunityMintsForWallet(address) → uint256
totalSupply() → uint256
Events (16)
AllowlistMintCompletedApprovalApprovalForAllBaseURIUpdatedCommunitySupplyReleasedFreeMintCompletedMerkleRootUpdatedMintPriceUpdatedOwnerMintCompletedOwnershipTransferredPaidMintCompletedPausedSalePhaseUpdatedTransferUnpausedWithdrawal
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "initialOwner",
"type": "address"
},
{
"internalType": "string",
"name": "initialBaseURI",
"type": "string"
},
{
"internalType": "bytes32",
"name": "initialMerkleRoot",
"type": "bytes32"
},
{
"internalType": "address",
"name": "royaltyReceiver",
"type": "address"
},
{
"internalType": "uint96",
"name": "royaltyFeeNumerator",
"type": "uint96"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "AllowlistWalletLimitExceeded",
"type": "error"
},
{
"inputs": [],
"name": "CommunityMintPermanentlyClosed",
"type": "error"
},
{
"inputs": [],
"name": "CommunityPoolExceeded",
"type": "error"
},
{
"inputs": [],
"name": "CommunitySupplyAlreadyReleased",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "numerator",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "denominator",
"type": "uint256"
}
],
"name": "ERC2981InvalidDefaultRoyalty",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC2981InvalidDefaultRoyaltyReceiver",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "numerator",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "denominator",
"type": "uint256"
}
],
"name": "ERC2981InvalidTokenRoyalty",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC2981InvalidTokenRoyaltyReceiver",
"type": "error"
},
{
"inputs": [],
"name": "ERC721EnumerableForbiddenBatchMint",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "ERC721IncorrectOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ERC721InsufficientApproval",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "approver",
"type": "address"
}
],
"name": "ERC721InvalidApprover",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "ERC721InvalidOperator",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "ERC721InvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
}
],
"name": "ERC721InvalidReceiver",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "ERC721InvalidSender",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ERC721NonexistentToken",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "ERC721OutOfBoundsIndex",
"type": "error"
},
{
"inputs": [],
"name": "EnforcedPause",
"type": "error"
},
{
"inputs": [],
"name": "ExpectedPause",
"type": "error"
},
{
"inputs": [],
"name": "FreeWalletLimitExceeded",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "requiredPayment",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "suppliedPayment",
"type": "uint256"
}
],
"name": "IncorrectPayment",
"type": "error"
},
{
"inputs": [],
"name": "InvalidAllowlistProof",
"type": "error"
},
{
"inputs": [],
"name": "InvalidQuantity",
"type": "error"
},
{
"inputs": [],
"name": "MaxSupplyExceeded",
"type": "error"
},
{
"inputs": [],
"name": "NonCommunityAllocationExceeded",
"type": "error"
},
{
"inputs": [],
"name": "NothingToWithdraw",
"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": "PaidWalletLimitExceeded",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "SaleMustBeClosed",
"type": "error"
},
{
"inputs": [],
"name": "WithdrawalFailed",
"type": "error"
},
{
"inputs": [],
"name": "WrongSalePhase",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "wallet",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "firstTokenId",
"type": "uint256"
}
],
"name": "AllowlistMintCompleted",
"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": "previousBaseURI",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "newBaseURI",
"type": "string"
}
],
"name": "BaseURIUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "communityMinted",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "unusedCommunitySupply",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "finalNonCommunityCap",
"type": "uint256"
}
],
"name": "CommunitySupplyReleased",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "wallet",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "firstTokenId",
"type": "uint256"
}
],
"name": "FreeMintCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "previousRoot",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newRoot",
"type": "bytes32"
}
],
"name": "MerkleRootUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "previousPrice",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newPrice",
"type": "uint256"
}
],
"name": "MintPriceUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "firstTokenId",
"type": "uint256"
}
],
"name": "OwnerMintCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "wallet",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "firstTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amountPaid",
"type": "uint256"
}
],
"name": "PaidMintCompleted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "enum RobinWoodPlank.SalePhase",
"name": "previousPhase",
"type": "uint8"
},
{
"indexed": true,
"internalType": "enum RobinWoodPlank.SalePhase",
"name": "newPhase",
"type": "uint8"
}
],
"name": "SalePhaseUpdated",
"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": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "Withdrawal",
"type": "event"
},
{
"inputs": [],
"name": "COMMUNITY_POOL",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "INITIAL_NON_COMMUNITY_ALLOCATION",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_ALLOWLIST_PER_WALLET",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_FREE_PER_WALLET",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_PAID_PER_TRANSACTION",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_PAID_PER_WALLET",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
},
{
"internalType": "bytes32[]",
"name": "merkleProof",
"type": "bytes32[]"
}
],
"name": "allowlistMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "allowlistMintsByWallet",
"outputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allowlistMintsClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "communityMintsClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "communitySupplyReleased",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "contractBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "currentNonCommunityCap",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "deleteDefaultRoyalty",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"name": "freeMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "freeMintsByWallet",
"outputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "freeMintsClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"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": "wallet",
"type": "address"
},
{
"internalType": "bytes32[]",
"name": "merkleProof",
"type": "bytes32[]"
}
],
"name": "isAllowlisted",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"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": "merkleRoot",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "mintPrice",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "nextTokenId",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "nonCommunityMintsClaimed",
"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": "recipient",
"type": "address"
},
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"name": "ownerMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "ownerMintsClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "paidMintsByWallet",
"outputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "paidMintsClaimed",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "pause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "paused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"name": "publicMint",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "quantity",
"type": "uint256"
}
],
"name": "publicMintCost",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "releaseUnusedCommunitySupply",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "remainingAllowlistMintsForWallet",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "remainingCommunitySupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "remainingFreeMintsForWallet",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "remainingNonCommunitySupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "remainingPaidMintsForWallet",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "remainingTotalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "salePrice",
"type": "uint256"
}
],
"name": "royaltyInfo",
"outputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"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": [],
"name": "salePhase",
"outputs": [
{
"internalType": "enum RobinWoodPlank.SalePhase",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "newBaseURI",
"type": "string"
}
],
"name": "setBaseURI",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "receiver",
"type": "address"
},
{
"internalType": "uint96",
"name": "feeNumerator",
"type": "uint96"
}
],
"name": "setDefaultRoyalty",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "newMerkleRoot",
"type": "bytes32"
}
],
"name": "setMerkleRoot",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newMintPrice",
"type": "uint256"
}
],
"name": "setMintPrice",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "enum RobinWoodPlank.SalePhase",
"name": "newPhase",
"type": "uint8"
}
],
"name": "setSalePhase",
"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": "index",
"type": "uint256"
}
],
"name": "tokenByIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
}
],
"name": "tokenOfOwnerByIndex",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "wallet",
"type": "address"
}
],
"name": "totalCommunityMintsForWallet",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"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": "unpause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "recipient",
"type": "address"
}
],
"name": "withdraw",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.6.0
pragma solidity ^0.8.27;
import {Ownable} from
"@openzeppelin/contracts/access/Ownable.sol";
import {ERC721} from
"@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {ERC721Enumerable} from
"@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import {ERC721Pausable} from
"@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol";
import {ERC721Royalty} from
"@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol";
import {MerkleProof} from
"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {ReentrancyGuard} from
"@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract RobinWoodPlank is
ERC721,
ERC721Enumerable,
ERC721Pausable,
ERC721Royalty,
Ownable,
ReentrancyGuard
{
// =============================================================
// SUPPLY RULES
// =============================================================
uint256 public constant MAX_SUPPLY = 1_542;
// Free + allowlist mints share this allocation.
uint256 public constant COMMUNITY_POOL = 777;
// Guaranteed paid/owner allocation before community release.
uint256 public constant INITIAL_NON_COMMUNITY_ALLOCATION =
MAX_SUPPLY - COMMUNITY_POOL; // 765
uint256 public constant MAX_FREE_PER_WALLET = 2;
uint256 public constant MAX_ALLOWLIST_PER_WALLET = 2;
uint256 public constant MAX_PAID_PER_TRANSACTION = 33;
uint256 public constant MAX_PAID_PER_WALLET = 33;
uint256 public mintPrice = 0.01 ether;
// =============================================================
// SALE PHASES
// =============================================================
enum SalePhase {
Closed, // 0
Free, // 1
Allowlist, // 2
Paid // 3
}
SalePhase public salePhase = SalePhase.Closed;
// =============================================================
// MINT TRACKING
// =============================================================
// Token IDs begin at 1.
uint256 private _nextTokenId = 1;
// Combined total from freeMint and allowlistMint.
uint256 public communityMintsClaimed;
uint256 public freeMintsClaimed;
uint256 public allowlistMintsClaimed;
uint256 public paidMintsClaimed;
uint256 public ownerMintsClaimed;
mapping(address wallet => uint256 quantity)
public freeMintsByWallet;
mapping(address wallet => uint256 quantity)
public allowlistMintsByWallet;
mapping(address wallet => uint256 quantity)
public paidMintsByWallet;
// =============================================================
// ALLOWLIST DATA
// =============================================================
bytes32 public merkleRoot;
// =============================================================
// COMMUNITY RELEASE
// =============================================================
/**
* Once true:
* - Free and allowlist minting are permanently disabled.
* - Unused community tokens become available for paid/owner mint.
*/
bool public communitySupplyReleased;
// =============================================================
// METADATA
// =============================================================
string private _baseTokenURI;
// =============================================================
// ERRORS
// =============================================================
error WrongSalePhase();
error InvalidQuantity();
error FreeWalletLimitExceeded();
error AllowlistWalletLimitExceeded();
error PaidWalletLimitExceeded();
error InvalidAllowlistProof();
error CommunityPoolExceeded();
error NonCommunityAllocationExceeded();
error MaxSupplyExceeded();
error CommunityMintPermanentlyClosed();
error CommunitySupplyAlreadyReleased();
error SaleMustBeClosed();
error IncorrectPayment(
uint256 requiredPayment,
uint256 suppliedPayment
);
error ZeroAddress();
error NothingToWithdraw();
error WithdrawalFailed();
// =============================================================
// EVENTS
// =============================================================
event SalePhaseUpdated(
SalePhase indexed previousPhase,
SalePhase indexed newPhase
);
event FreeMintCompleted(
address indexed wallet,
uint256 quantity,
uint256 firstTokenId
);
event AllowlistMintCompleted(
address indexed wallet,
uint256 quantity,
uint256 firstTokenId
);
event PaidMintCompleted(
address indexed wallet,
uint256 quantity,
uint256 firstTokenId,
uint256 amountPaid
);
event OwnerMintCompleted(
address indexed recipient,
uint256 quantity,
uint256 firstTokenId
);
event CommunitySupplyReleased(
uint256 communityMinted,
uint256 unusedCommunitySupply,
uint256 finalNonCommunityCap
);
event MerkleRootUpdated(
bytes32 indexed previousRoot,
bytes32 indexed newRoot
);
event MintPriceUpdated(
uint256 previousPrice,
uint256 newPrice
);
event BaseURIUpdated(
string previousBaseURI,
string newBaseURI
);
event Withdrawal(
address indexed recipient,
uint256 amount
);
// =============================================================
// CONSTRUCTOR
// =============================================================
/**
* royaltyFeeNumerator uses basis points:
*
* 500 = 5%
* 750 = 7.5%
* 1000 = 10%
*/
constructor(
address initialOwner,
string memory initialBaseURI,
bytes32 initialMerkleRoot,
address royaltyReceiver,
uint96 royaltyFeeNumerator
)
ERC721("RobinWood", "PLANK")
Ownable(initialOwner)
{
if (
initialOwner == address(0) ||
royaltyReceiver == address(0)
) {
revert ZeroAddress();
}
_baseTokenURI = initialBaseURI;
merkleRoot = initialMerkleRoot;
_setDefaultRoyalty(
royaltyReceiver,
royaltyFeeNumerator
);
}
// =============================================================
// FREE MINT
// =============================================================
/**
* Public free mint.
*
* Maximum:
* - 2 per wallet
* - Shared 777-token community pool
*
* No ETH should be sent.
*/
function freeMint(uint256 quantity)
external
nonReentrant
whenNotPaused
{
if (salePhase != SalePhase.Free) {
revert WrongSalePhase();
}
if (
quantity == 0 ||
quantity > MAX_FREE_PER_WALLET
) {
revert InvalidQuantity();
}
if (
freeMintsByWallet[msg.sender] + quantity >
MAX_FREE_PER_WALLET
) {
revert FreeWalletLimitExceeded();
}
_enforceCommunityAllocation(quantity);
uint256 firstTokenId = _nextTokenId;
// Update state before safe-mint callbacks.
freeMintsByWallet[msg.sender] += quantity;
freeMintsClaimed += quantity;
communityMintsClaimed += quantity;
_mintMultiple(msg.sender, quantity);
emit FreeMintCompleted(
msg.sender,
quantity,
firstTokenId
);
}
// =============================================================
// ALLOWLIST MINT
// =============================================================
/**
* Free allowlist mint.
*
* Maximum:
* - 2 per allowlisted wallet
* - Shared 777-token community pool
*
* A wallet that already minted 2 through freeMint may still mint
* 2 through allowlistMint.
*/
function allowlistMint(
uint256 quantity,
bytes32[] calldata merkleProof
)
external
nonReentrant
whenNotPaused
{
if (salePhase != SalePhase.Allowlist) {
revert WrongSalePhase();
}
if (
quantity == 0 ||
quantity > MAX_ALLOWLIST_PER_WALLET
) {
revert InvalidQuantity();
}
if (
allowlistMintsByWallet[msg.sender] + quantity >
MAX_ALLOWLIST_PER_WALLET
) {
revert AllowlistWalletLimitExceeded();
}
bytes32 leaf = _allowlistLeaf(msg.sender);
if (
!MerkleProof.verifyCalldata(
merkleProof,
merkleRoot,
leaf
)
) {
revert InvalidAllowlistProof();
}
_enforceCommunityAllocation(quantity);
uint256 firstTokenId = _nextTokenId;
// Update state before safe-mint callbacks.
allowlistMintsByWallet[msg.sender] += quantity;
allowlistMintsClaimed += quantity;
communityMintsClaimed += quantity;
_mintMultiple(msg.sender, quantity);
emit AllowlistMintCompleted(
msg.sender,
quantity,
firstTokenId
);
}
// =============================================================
// PAID MINT
// =============================================================
function publicMint(uint256 quantity)
external
payable
nonReentrant
whenNotPaused
{
if (salePhase != SalePhase.Paid) {
revert WrongSalePhase();
}
if (
quantity == 0 ||
quantity > MAX_PAID_PER_TRANSACTION
) {
revert InvalidQuantity();
}
if (
paidMintsByWallet[msg.sender] + quantity >
MAX_PAID_PER_WALLET
) {
revert PaidWalletLimitExceeded();
}
_enforceNonCommunityAllocation(quantity);
uint256 requiredPayment = mintPrice * quantity;
if (msg.value != requiredPayment) {
revert IncorrectPayment(
requiredPayment,
msg.value
);
}
uint256 firstTokenId = _nextTokenId;
// Update state before safe-mint callbacks.
paidMintsByWallet[msg.sender] += quantity;
paidMintsClaimed += quantity;
_mintMultiple(msg.sender, quantity);
emit PaidMintCompleted(
msg.sender,
quantity,
firstTokenId,
msg.value
);
}
// =============================================================
// OWNER MINT
// =============================================================
/**
* Owner mint for team, giveaways, or reserves.
*
* Owner mints consume the same supply allocation as paid mint.
* They cannot consume the protected community allocation before
* that allocation has been released.
*/
function ownerMint(
address recipient,
uint256 quantity
)
external
onlyOwner
nonReentrant
whenNotPaused
{
if (recipient == address(0)) {
revert ZeroAddress();
}
if (quantity == 0) {
revert InvalidQuantity();
}
_enforceNonCommunityAllocation(quantity);
uint256 firstTokenId = _nextTokenId;
ownerMintsClaimed += quantity;
_mintMultiple(recipient, quantity);
emit OwnerMintCompleted(
recipient,
quantity,
firstTokenId
);
}
// =============================================================
// ALLOCATION ENFORCEMENT
// =============================================================
function _enforceCommunityAllocation(
uint256 quantity
)
internal
view
{
if (communitySupplyReleased) {
revert CommunityMintPermanentlyClosed();
}
if (
communityMintsClaimed + quantity >
COMMUNITY_POOL
) {
revert CommunityPoolExceeded();
}
if (totalSupply() + quantity > MAX_SUPPLY) {
revert MaxSupplyExceeded();
}
}
function _enforceNonCommunityAllocation(
uint256 quantity
)
internal
view
{
uint256 nonCommunityMinted =
paidMintsClaimed + ownerMintsClaimed;
if (
nonCommunityMinted + quantity >
currentNonCommunityCap()
) {
revert NonCommunityAllocationExceeded();
}
if (totalSupply() + quantity > MAX_SUPPLY) {
revert MaxSupplyExceeded();
}
}
/**
* Before release:
* Paid + owner cap = 765
*
* After release:
* Paid + owner cap =
* 1,542 minus community tokens already minted
*/
function currentNonCommunityCap()
public
view
returns (uint256)
{
if (!communitySupplyReleased) {
return INITIAL_NON_COMMUNITY_ALLOCATION;
}
return MAX_SUPPLY - communityMintsClaimed;
}
/**
* Permanently ends free and allowlist minting.
*
* Any unused portion of the 777 community pool becomes available
* for paid and owner minting.
*
* The sale must first be Closed.
*/
function releaseUnusedCommunitySupply()
external
onlyOwner
{
if (communitySupplyReleased) {
revert CommunitySupplyAlreadyReleased();
}
if (salePhase != SalePhase.Closed) {
revert SaleMustBeClosed();
}
communitySupplyReleased = true;
uint256 unusedCommunitySupply =
COMMUNITY_POOL - communityMintsClaimed;
emit CommunitySupplyReleased(
communityMintsClaimed,
unusedCommunitySupply,
currentNonCommunityCap()
);
}
// =============================================================
// INTERNAL MINT LOGIC
// =============================================================
function _mintOne(
address recipient
)
internal
returns (uint256 tokenId)
{
tokenId = _nextTokenId;
unchecked {
++_nextTokenId;
}
_safeMint(recipient, tokenId);
}
function _mintMultiple(
address recipient,
uint256 quantity
)
internal
{
for (uint256 i; i < quantity; ) {
_mintOne(recipient);
unchecked {
++i;
}
}
}
// =============================================================
// OWNER SETTINGS
// =============================================================
/**
* Remix phase values:
*
* 0 = Closed
* 1 = Free
* 2 = Allowlist
* 3 = Paid
*/
function setSalePhase(
SalePhase newPhase
)
external
onlyOwner
{
if (
communitySupplyReleased &&
(
newPhase == SalePhase.Free ||
newPhase == SalePhase.Allowlist
)
) {
revert CommunityMintPermanentlyClosed();
}
SalePhase previousPhase = salePhase;
salePhase = newPhase;
emit SalePhaseUpdated(
previousPhase,
newPhase
);
}
function setMerkleRoot(
bytes32 newMerkleRoot
)
external
onlyOwner
{
bytes32 previousRoot = merkleRoot;
merkleRoot = newMerkleRoot;
emit MerkleRootUpdated(
previousRoot,
newMerkleRoot
);
}
function setMintPrice(
uint256 newMintPrice
)
external
onlyOwner
{
uint256 previousPrice = mintPrice;
mintPrice = newMintPrice;
emit MintPriceUpdated(
previousPrice,
newMintPrice
);
}
function setBaseURI(
string calldata newBaseURI
)
external
onlyOwner
{
string memory previousBaseURI = _baseTokenURI;
_baseTokenURI = newBaseURI;
emit BaseURIUpdated(
previousBaseURI,
newBaseURI
);
}
function setDefaultRoyalty(
address receiver,
uint96 feeNumerator
)
external
onlyOwner
{
if (receiver == address(0)) {
revert ZeroAddress();
}
_setDefaultRoyalty(
receiver,
feeNumerator
);
}
function deleteDefaultRoyalty()
external
onlyOwner
{
_deleteDefaultRoyalty();
}
function pause()
external
onlyOwner
{
_pause();
}
function unpause()
external
onlyOwner
{
_unpause();
}
// =============================================================
// WITHDRAWAL
// =============================================================
function withdraw(
address payable recipient
)
external
onlyOwner
nonReentrant
{
if (recipient == address(0)) {
revert ZeroAddress();
}
uint256 amount = address(this).balance;
if (amount == 0) {
revert NothingToWithdraw();
}
(bool success, ) = recipient.call{
value: amount
}("");
if (!success) {
revert WithdrawalFailed();
}
emit Withdrawal(recipient, amount);
}
// =============================================================
// READ FUNCTIONS
// =============================================================
function remainingTotalSupply()
external
view
returns (uint256)
{
return MAX_SUPPLY - totalSupply();
}
function remainingCommunitySupply()
external
view
returns (uint256)
{
if (communitySupplyReleased) {
return 0;
}
return COMMUNITY_POOL - communityMintsClaimed;
}
function nonCommunityMintsClaimed()
public
view
returns (uint256)
{
return paidMintsClaimed + ownerMintsClaimed;
}
function remainingNonCommunitySupply()
external
view
returns (uint256)
{
return
currentNonCommunityCap() -
nonCommunityMintsClaimed();
}
function totalCommunityMintsForWallet(
address wallet
)
external
view
returns (uint256)
{
return
freeMintsByWallet[wallet] +
allowlistMintsByWallet[wallet];
}
function remainingFreeMintsForWallet(
address wallet
)
external
view
returns (uint256)
{
return
MAX_FREE_PER_WALLET -
freeMintsByWallet[wallet];
}
function remainingAllowlistMintsForWallet(
address wallet
)
external
view
returns (uint256)
{
return
MAX_ALLOWLIST_PER_WALLET -
allowlistMintsByWallet[wallet];
}
function remainingPaidMintsForWallet(
address wallet
)
external
view
returns (uint256)
{
return
MAX_PAID_PER_WALLET -
paidMintsByWallet[wallet];
}
function publicMintCost(
uint256 quantity
)
external
view
returns (uint256)
{
return mintPrice * quantity;
}
function isAllowlisted(
address wallet,
bytes32[] calldata merkleProof
)
external
view
returns (bool)
{
return MerkleProof.verifyCalldata(
merkleProof,
merkleRoot,
_allowlistLeaf(wallet)
);
}
function nextTokenId()
external
view
returns (uint256)
{
return _nextTokenId;
}
function contractBalance()
external
view
returns (uint256)
{
return address(this).balance;
}
function _allowlistLeaf(
address wallet
)
internal
pure
returns (bytes32)
{
// Compatible with OpenZeppelin StandardMerkleTree
// using ["address"] entries.
return keccak256(
bytes.concat(
keccak256(
abi.encode(wallet)
)
)
);
}
// =============================================================
// METADATA
// =============================================================
function _baseURI()
internal
view
override
returns (string memory)
{
return _baseTokenURI;
}
// =============================================================
// REQUIRED OZ OVERRIDES
// =============================================================
function _update(
address to,
uint256 tokenId,
address auth
)
internal
override(
ERC721,
ERC721Enumerable,
ERC721Pausable
)
returns (address)
{
return super._update(
to,
tokenId,
auth
);
}
function _increaseBalance(
address account,
uint128 value
)
internal
override(
ERC721,
ERC721Enumerable
)
{
super._increaseBalance(
account,
value
);
}
function supportsInterface(
bytes4 interfaceId
)
public
view
override(
ERC721,
ERC721Enumerable,
ERC721Royalty
)
returns (bool)
{
return super.supportsInterface(
interfaceId
);
}
}Chain explorer4114msChain node80ms