Whitelist/Allowlist Development for NFT Minting

Whitelist/Allowlist Development for NFT Minting Typical scenario: a 10,000 NFT collection, whitelist mint for 3,000 addresses 12 hours before public. Storing the whitelist on-chain as `mapping(address => bool)` costs about 15-20M gas just for `SSTORE` during contract deployment. At 20 gwei gas pr

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1441
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    998
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1267
  • image_logo-advance_0.webp
    B2B Advance company logo design
    713
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1003

Whitelist/Allowlist Development for NFT Minting

Typical scenario: a 10,000 NFT collection, whitelist mint for 3,000 addresses 12 hours before public. Storing the whitelist on-chain as mapping(address => bool) costs about 15-20M gas just for SSTORE during contract deployment. At 20 gwei gas price, that's around $4,000. Our team with 7+ years of experience in blockchain development and 50+ completed NFT mint projects offers efficient solutions. We develop turnkey whitelist/allowlist systems using Merkle tree, reducing costs to 50k gas — saving up to $4,000. Evaluate your project in 1 day — get a consultation.

How Merkle proof works and where mistakes happen

A Merkle tree is built off-chain: each address is hashed via keccak256(abi.encodePacked(address)), and the tree is built by pairwise hashing of leaves. The result is a 32-byte merkleRoot. This root is deployed in the contract. During mint, the user provides a proof[] — an array of sibling hashes along the path from their leaf to the root. The contract verifies it via MerkleProof.verify() from OpenZeppelin.

Common mistake — double mint. If the contract lacks a mapping(address => bool) public hasMinted (or mapping(address => uint256) public mintedCount), a whitelisted user can mint unlimited times. The proof remains valid. The contract has no record that the address already minted.

Another serious issue is leaf encoding. OpenZeppelin's MerkleProof expects the leaf to be keccak256(keccak256(data)) (double hash) to protect against preimage attacks in case tree nodes coincide with leaves. If you generate the tree via merkletreejs with single hashing, but the contract uses _leaf = keccak256(abi.encodePacked(account)) without double hashing, a collision attack may be possible under certain configurations. We use keccak256(bytes.concat(keccak256(abi.encode(addr)))) or the standard pairing of @openzeppelin/merkle-tree JS library + MerkleProof.sol.

Which method to choose for your project?

There are three main approaches to implementing a whitelist. Compare their characteristics:

Criteria Merkle proof ECDSA signature On-chain mapping
Deployment cost (gas) 50k (fixed) 50k + base cost 20k * N addresses
Update flexibility Requires root change Dynamic (any changes) Owner-only functions
Centralization None Depends on signer key None
Security High (proven) Medium (key risk) High
Ideal list size 100 — 1M+ Any, with unknown changes < 100 addresses

Merkle proof is the market standard, 40x cheaper than on-chain mapping for 10,000 addresses. ECDSA is used in gaming mints and dynamic campaigns. On-chain mapping is suitable only for very small fixed lists.

Comparison of schemes for multi-tier and phases

For projects with different access levels (OG, core, community) or time phases (pre-sale, allowlist, public), additional logic is needed. Typical configurations:

Scheme Number of roots Management Gas per mint
Single root + multi-tier via encoding 1 Simple but fixed quotas ~60k-70k
Separate roots per phase 3-5 Owner setPhase(), different prices ~50k + root change
Hybrid: root + ECDSA for dynamics 1 signature Backend signs permissions ~70k + signer risk

The choice depends on requirements: if quotas can change before mint, ECDSA is better; if fixed, Merkle proof with multi-tier encoding is preferable.

How to generate Merkle tree in practice?

  1. Collect all addresses and quotas into an array.
  2. Use the @openzeppelin/merkle-tree library:
const { StandardMerkleTree } = require('@openzeppelin/merkle-tree'); const values = [ ['0x...', 1], ['0x...', 3], ]; const tree = StandardMerkleTree.of(values, ['address', 'uint256']); const root = tree.root; 
  1. Store the root in the contract.
  2. For each user, generate a proof via tree.getProof([address, maxMint]) and pass it during mint.

Why Merkle proof is the market standard?

Regardless of list size, deployment costs are the same. The proof is submitted by the user (frontend generates it automatically); the contract only verifies it. We ensure no reentrancy and correct proof verification. Our contracts are audited using Slither and Mythril.

Additional mechanics

Multi-tier whitelist — different quotas for different levels. The Merkle tree contains leaves keccak256(abi.encode(address, maxMintAmount)). The user provides the proof plus their maxMintAmount; the contract verifies both parameters together.

Temporal phases — WL → Allowlist → Public. The contract holds enum SalePhase { PAUSED, WHITELIST, ALLOWLIST, PUBLIC }. Different roots for different phases, different prices. The owner changes the phase via setPhase().

Batch mint with WL — a user can mint N NFTs in one transaction if their quota allows. mintedCount[msg.sender] += amount instead of a bool flag.

What's included in development

  • Smart contract with Merkle verify, hasMinted mapping, and phase management
  • Comprehensive test suite in Foundry (edge cases: double mint, invalid proof, exhausted quota)
  • Frontend integration (proof generation via @openzeppelin/merkle-tree, wagmi useMint() hook)
  • Deployment via Foundry script with automatic Etherscan verification
  • Documentation and post-launch support

Time estimates

Whitelist contract with Merkle proof — 2-3 days including tests and frontend integration. Cost is calculated individually. Contact us to discuss your project — we will help you choose the optimal scheme and implement it with security guarantees.