The NFT contracts created from the
ZoraNFTCreator are known as an
Each drop contract is cloned from an
implementation address and receives its own address.
Drops use the same base contract but have different metadata rendering contracts.
Every time an NFT is minted and sold using these contracts 5% of the primary sale amount will be reserved by the Zora DAO. Nothing is taken on secondary sales.
Edition: A collection where all the NFTs share the same media asset.
Drop: A collection where all the NFTs have individual pieces of media.
The sales configuration is set when the contract is created. The config holds the internal settings for all the minting/sales parameters.
*Times are Unix Timestamps
publicSaleStart: Start time for public minting
publicSaleEnd: End time for public minting
presaleStart: Start time for private minting
presaleEnd: End time for private minting
publicSalePrice: Price in the ETH required to mint an NFT
maxSalePurchasePerAddress: Max amount of NFTs an address can mint (only for public minting)
presaleMerkleRoot: A cryptographic proof that is used for presale minting (allow list)
presaleMerkleRoot can be set to
0x0000000000000000000000000000000000000000000000000000000000000000 if there are no plans for allow list minting.
Current values can be viewed by calling
salesConfig on the contract and it can be updated by calling
setSalesConfig with the new parameters.
Learn more about creating an allow list here.
function setSaleConfiguration( uint104 publicSalePrice, uint32 maxSalePurchasePerAddress, uint64 publicSaleStart, uint64 publicSaleEnd, uint64 presaleStart, uint64 presaleEnd, bytes32 presaleMerkleRoot)
A fixed-size collection is where there is a max number of NFTs that are allowed to be minted from the contract.
The max size is set when creating the contract and specifying the
An open edition collection has no max amount but instead has a certain time window where minting is open. However, once the period is over then no one can publically mint anymore.
finalizeOpenEdition must be called by an admin once the minting window has closed to make sure that it's not possible to mint any more NFTs from the contract.
An admin can mint a certain number of the NFTs to an address without having to pay the base price.
function adminMint(address recipient, uint256 quantity)
An admin can mint a single NFT to multiple different addresses in a single transaction without having to pay the base price. The function takes in an array of addresses to mint to.
function adminMintAirdrop(address calldata recipients)
A public minting function that can be called by anyone once the public sale has started.
function purchase(uint256 quantity)
A private sale function for allowlist minting that requires a merkle proof. Check out the section here for creating an allowlist.
function purchasePresale( uint256 quantity, uint256 maxQuantity, // Max quantity that can be purchased with a merkle proof uint256 pricePerToken, bytes32 calldata merkleProof)
The owner doesn't have access to any write functions on the contract. They are only able to set royalty and contract configurations on third-party applications that expect an owner. The owner address is set to the same address as the default admin argument when the contract was created but can be updated to any address by a default admin.
This admin has the most control and is set when the contract is first initialized. It is recommended to set the deployer address to the default admin when first creating the NFT contract. There can also be more than one default admin and can be updated to a new address. Capabilities include:
- Assign and revoke admin roles
- Change the owner Address
- Update the
bytes32 role = 0x0000000000000000000000000000000000000000000000000000000000000000
A restricted admin that is only able to access special minting functions such as
bytes32 role = MINTER_ROLE
A restricted admin that is only able to update the
salesConfig and call the
bytes32 role = SALES_MANAGER_ROLE
Note, admin roles can only be assigned and revoked by default admins.
isAdmin function checks if an address is an admin or not.
function isAdmin(address user)
hasRole is more granular and checks if an address has a specific admin role.
function hasRole(bytes32 role, address account)
grantRole allows for a default admin to add an admin.
function grantRole(bytes32 role, address account)
revokeRole allows for a default admin to remove an admin.
function revokeRole(bytes32 role, address account)
setOwner sets the owner of the contract to a new address.
function setOwner(address newOwner)
Once minting has concluded, the funds can be moved out of the contract by calling the
Withdraw can be called by a default admin, the
fundsRecipient address, a sales manager role, and the Zora DAO.
This will push the funds to the
fundsRecipient address, which is set to the default admin when the contract was initialized.
However, it can be updated to any address by calling the
function setFundsRecipient(address payable newRecipientAddress)
A Merkle root allows a large data set to be condensed and expressed in a small piece of data. The Merkle root is used to store a list of valid preSale minting addresses, without needing to store the whole list directly in the contract.
Here is both an interface and source code that makes it easy to generate a Merkle root and proofs for allowlist minting:
It is possible to upload an allowlist using the manage interface on the create website and then access the list of proofs from the API here.
Once the contract is deployed, the address that is set as the owner will need to log in to OpenSea to access and update the contract information.
Once deployed it is possible to upgrade the NFT contract to have new functionality. Note, that upgrade options are on the ones that are in the Zora registry. All upgrades are opt-in and can only be initiated by a default admin.
upgradeTo allows the NFT contract to upgrade to a new implementation contract to make delegate calls.
function upgradeTo(address newImplementation)
upgradeToAndCall allows a new implementation contract to be specified, but it also allows for call data to be passed in when updating.
function upgradeToAndCall(address newImplementation, bytes data)
OpenSea has enacted a policy that requires NFT contracts block other NFT exchanges to set royalties. Meaning the NFTs can't be sold on platforms that have 0% percent royalties. When creating NFTs using the Create tool there is the option to select the implementation version that allows you to set royalties on OpenSea.
Note it is possible to upgrade the contract to an implementation that doesn't contain this later on if you change your mind. You read more about the OpenSea policy here.