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