Deploy NFT Collection
Create a professional NFT collection with 10,000 unique items, whitelist, and reveal mechanics.Collection Contract
Copy
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract NFTCollection is ERC721, Ownable {
using Strings for uint256;
uint256 public constant MAX_SUPPLY = 10000;
uint256 public constant MAX_PER_WALLET = 5;
uint256 public constant WHITELIST_PRICE = 0.05 ether;
uint256 public constant PUBLIC_PRICE = 0.08 ether;
uint256 private _tokenIdCounter;
string private _baseTokenURI;
string private _unrevealedURI;
bytes32 public merkleRoot;
bool public whitelistActive = false;
bool public publicActive = false;
bool public revealed = false;
mapping(address => uint256) public mintedPerWallet;
constructor(string memory unrevealedURI) ERC721("My Collection", "COLL") Ownable(msg.sender) {
_unrevealedURI = unrevealedURI;
}
function whitelistMint(uint256 quantity, bytes32[] calldata proof) external payable {
require(whitelistActive, "Whitelist not active");
require(_tokenIdCounter + quantity <= MAX_SUPPLY, "Exceeds max supply");
require(mintedPerWallet[msg.sender] + quantity <= MAX_PER_WALLET, "Exceeds max per wallet");
require(msg.value >= WHITELIST_PRICE * quantity, "Insufficient payment");
require(_verifyWhitelist(msg.sender, proof), "Not whitelisted");
mintedPerWallet[msg.sender] += quantity;
for (uint256 i = 0; i < quantity; i++) {
_safeMint(msg.sender, _tokenIdCounter++);
}
}
function publicMint(uint256 quantity) external payable {
require(publicActive, "Public mint not active");
require(_tokenIdCounter + quantity <= MAX_SUPPLY, "Exceeds max supply");
require(mintedPerWallet[msg.sender] + quantity <= MAX_PER_WALLET, "Exceeds max per wallet");
require(msg.value >= PUBLIC_PRICE * quantity, "Insufficient payment");
mintedPerWallet[msg.sender] += quantity;
for (uint256 i = 0; i < quantity; i++) {
_safeMint(msg.sender, _tokenIdCounter++);
}
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_ownerOf(tokenId) != address(0), "Token does not exist");
if (!revealed) return _unrevealedURI;
return string(abi.encodePacked(_baseTokenURI, tokenId.toString(), ".json"));
}
function _verifyWhitelist(address account, bytes32[] calldata proof) private view returns (bool) {
bytes32 leaf = keccak256(abi.encodePacked(account));
return MerkleProof.verify(proof, merkleRoot, leaf);
}
function setMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
merkleRoot = _merkleRoot;
}
function toggleWhitelist() external onlyOwner {
whitelistActive = !whitelistActive;
}
function togglePublic() external onlyOwner {
publicActive = !publicActive;
}
function reveal(string calldata baseURI) external onlyOwner {
_baseTokenURI = baseURI;
revealed = true;
}
function withdraw() external onlyOwner {
payable(owner()).transfer(address(this).balance);
}
function totalSupply() public view returns (uint256) {
return _tokenIdCounter;
}
}
Generate Merkle Tree
scripts/generate-whitelist.js
Copy
const { MerkleTree } = require('merkletreejs');
const keccak256 = require('keccak256');
const fs = require('fs');
const whitelist = [
"0xAddress1",
"0xAddress2",
"0xAddress3",
// Add all whitelisted addresses
];
const leaves = whitelist.map(addr => keccak256(addr));
const tree = new MerkleTree(leaves, keccak256, { sortPairs: true });
const root = tree.getHexRoot();
console.log("Merkle Root:", root);
// Generate proofs for each address
const proofs = {};
whitelist.forEach(addr => {
const leaf = keccak256(addr);
const proof = tree.getHexProof(leaf);
proofs[addr] = proof;
});
fs.writeFileSync('whitelist-proofs.json', JSON.stringify({ root, proofs }, null, 2));
console.log("Proofs saved to whitelist-proofs.json");
Batch Metadata Generation
scripts/generate-metadata.py
Copy
import json
import os
BASE_URI = "ipfs://QmYourBaseURI/"
TOTAL_SUPPLY = 10000
traits = {
"background": ["Blue", "Red", "Green", "Yellow"],
"body": ["Robot", "Alien", "Human"],
"accessory": ["Hat", "Glasses", "None"]
}
for i in range(TOTAL_SUPPLY):
metadata = {
"name": f"Collection #{i}",
"description": "A unique NFT from the collection",
"image": f"{BASE_URI}{i}.png",
"attributes": [
{"trait_type": "Background", "value": traits["background"][i % 4]},
{"trait_type": "Body", "value": traits["body"][i % 3]},
{"trait_type": "Accessory", "value": traits["accessory"][i % 3]}
]
}
with open(f"metadata/{i}.json", "w") as f:
json.dump(metadata, f, indent=2)
print(f"Generated {TOTAL_SUPPLY} metadata files")
Launch Workflow
1
Generate Assets
Create 10,000 unique images and metadata files
2
Upload to IPFS
Upload images and metadata to IPFS, get base URI
3
Deploy Contract
Deploy with unrevealed URI
4
Set Whitelist
Generate and set Merkle root for whitelist
5
Enable Minting
Activate whitelist mint, then public mint
6
Reveal Collection
Call reveal() with real base URI after sellout