An example script to deploy a token contract is located at DeployAndConfigureExampleToken.s.sol. It can be run with forge script script/DeployAndConfigureExampleToken.s.sol --rpc-url ${RPC_URL} --broadcast -vvvv --private-key ${PK} --etherscan-api-key ${ETHERSCAN_API_KEY} --verify --retries 10
ERC721SeaDrop
contains only an Owner role (assigned to the deployer of the contract) that has authorization for all methods.
To split responsibilities with an Administrator role who can set fee parameters, use ERC721PartnerSeaDrop
.
- Deploy
src/ERC721SeaDrop.sol
with constructor argsstring name, string symbol, address[] allowedSeaDrop
- e.g.
forge create --rpc-url ${RPC_URL} src/ERC721SeaDrop.sol:ERC721SeaDrop --constructor-args "TokenTest1" "TEST1" \[${SEADROP_ADDRESS}\] --private-key ${PK} --etherscan-api-key ${ETHERSCAN_API_KEY} --verify
- e.g.
- Set the token max supply with
token.setMaxSupply()
- Set the creator payout address with
token.updateCreatorPayoutAddress()
- Set the contract URI with
token.setContractURI()
- Set the base URI with
token.setBaseURI()
- Optionally:
- Set the provenance hash for random metadata reveals with
token.setProvenanceHash()
- Must be set before first token is minted
- Set an allow list drop stage with
token.updateAllowList()
- Set a token gated drop stage with
token.updateTokenGatedDrop()
- Add server-side signers with
token.updateSignedMintValidationParams()
- Set the provenance hash for random metadata reveals with
- Set a public drop stage with
token.updatePublicDrop()
- Set the drop URI with
token.setDropURI()
ERC721PartnerSeaDrop
is a token contract designed to split responsibilities between an Owner and Administrator.
- Deploy
src/ERC721PartnerSeaDrop.sol
with constructor argsstring name, string symbol, address administrator, address[] allowedSeaDrop
- e.g.
forge create --rpc-url ${RPC_URL} src/ERC721PartnerSeaDrop.sol:ERC721PartnerSeaDrop --constructor-args "TokenTest1" "TEST1" ${ADMIN_ADDRESS} \[${SEADROP_ADDRESS}\] --private-key ${PK} --etherscan-api-key ${ETHERSCAN_API_KEY} --verify
- e.g.
- Required to be sent by token Owner:
- Set the token max supply with
token.setMaxSupply()
- Set the creator payout address with
token.updateCreatorPayoutAddress()
- Set the contract URI with
token.setContractURI()
- Set the base URI with
token.setBaseURI()
- Set the token max supply with
- Can be sent by token Owner or Administrator:
- Optionally:
- Set the provenance hash for random metadata reveals with
token.setProvenanceHash()
- Must be set before first token is minted
- Instructions for generating the provenance hash here
- Set an allow list drop stage with
token.updateAllowList()
- Set a token gated drop stage with
token.updateTokenGatedDrop()
- Administrator must first initialize with feeBps
- Set a public drop stage with
token.updatePublicDrop()
- Administrator must first initialize with feeBps with
token.updatePublicDrop()
- If
restrictFeeRecipients
is set to true, Administrator must set allowed fee recipients withtoken.updateAllowedFeeRecipient()
- Administrator must first initialize with feeBps with
- Set the provenance hash for random metadata reveals with
- Set the drop URI with
token.setDropURI()
- Optionally:
Follows the pattern of tokenURI
— could be either on-chain data blob or external URI (IPFS) — that contains the metadata related to the drop and corresponding drop stages.
{
"name": "An Example Drop",
"description": "This is the description for this example drop.",
"stages": [
{
"name": "My Public Stage",
"description": "My public stage description.",
"uuid": "ecae5ad4-fa40-4e79-856b-ec304c3ea5d4",
"isPublic": true,
"mintPrice": 1000000000000000000,
"maxTotalMintableByWallet": 50,
"maxTokenSupplyForStage": 5000,
"startTime": 1659045594,
"endTime": 1659045594,
"feeBps": 500
},
{
"name": "My Private Allow List Stage",
"description": "My private stage description",
"uuid": "07e7a791-42ad-46e6-968a-564acf0c06dc",
"isPublic": false,
"mintPrice": 1000000000000000,
"maxTotalMintableByWallet": 5,
"maxTokenSupplyForStage": 1000,
"startTime": 1659043594,
"endTime": 1659044594,
"feeBps": 500
}
]
}
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"stages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"uuid": {
"type": "string"
},
"isPublic": {
"type": "boolean"
},
"allowListURI": {
"type": "string"
},
"allowedTokenAddresses": {
"type": "array",
"items": {
"type": "string"
}
},
"mintPrice": {
"type": "integer"
},
"maxTotalMintableByWallet": {
"type": "integer"
},
"maxTokenSupplyForStage": {
"type": "integer"
},
"startTime": {
"type": "integer"
},
"endTime": {
"type": "integer"
},
"feeBps": {
"type": "integer"
}
}
}
}
}
}
The allow list may be optionally encrypted with PGP when emitted with updateAllowList()
to retain privacy. The OpenSea public key is available here, although it may be rotated in the future, so please ask an OpenSea team member if it is the right key to use at the time of update.
[
{
"address": "0xf0E16c071E2cd421974dCb76d9af4DeDB578E059",
"mintPrice": 1000000000000000000,
"maxTotalMintableByWallet": 10,
"startTime": 1659045594,
"endTime": 1659045594,
"dropStageIndex": 1,
"maxTokenSupplyForStage": 1000,
"feeBps": 1000,
"restrictFeeRecipients": true
},
{
"address": "0x829bd824b016326a401d083b33d092293333a830",
"mintPrice": 1000000000000000000,
"maxTotalMintableByWallet": 5,
"startTime": 1659045594,
"endTime": 1659045594,
"dropStageIndex": 2,
"maxTokenSupplyForStage": 500,
"feeBps": 1250,
"restrictFeeRecipients": false
}
]
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"address": {
"type": "string"
},
"mintPrice": {
"type": "integer"
},
"maxTotalMintableByWallet": {
"type": "integer"
},
"startTime": {
"type": "integer"
},
"endTime": {
"type": "integer"
},
"dropStageIndex": {
"type": "integer"
},
"maxTokenSupplyForStage": {
"type": "integer"
},
"feeBps": {
"type": "integer"
},
"restrictFeeRecipients": {
"type": "boolean"
}
}
}