Whitelist allows collection creators to decide which wallet addresses can participate in the mint. For example, when you run a great exclusive community (like BFC) you want to be sure that only the right people will get your token. Almost every NFT drop is exclusive to a specific set of public addresses. Otherwise, strangers or trading bots would be able to get your precious NFTs and run away with them to the secondary market. That's why whitelisting is super important. Most collection creators do not want such situations to happen.
Collecting public wallet addresses usually happens off-chain (without touching any blockchain stuff). All you have to do is to contact your people, collect their wallet addresses and prepare the list. You may use Google Forms or any other tooling for it. That's a pretty straightforward procedure, so I won’t cover it in this article. Way more problematic part is the smart contract code. The contract needs to validate if the caller is approved to participate in the mint. Secondly, the contract cannot allow callers to mint more tokens than expected.
Having all the above in mind let's dive into three common techniques of whitelisting and examine their pros and cons.
Storing whitelist in contract memory
If you just learned Solidity basics you might already have a clue about how to store a whitelist in the memory. The simplest approach is to just prepare mapping inside the smart contract:
Then we need to allow a certain address (owner of the collection or some other "power user" wallet) to update above whitelist:
Obviously, this function might be called only by "power users". It cannot be a function that anyone can call. That’s why I used “onlyOwner” modifier. You may read about it more here.
Whitelist logic is pretty much ready, so now we have to validate every address before the mint and update the whitelist afterward:
That's it. Your contract now allows you to whitelist certain addresses for mint. Easy, huh?
However, this stupidly simple method is not ideal. The problem is with gas fees. Writing to contract memory is expensive. The owner of the collection needs to spend a lot of money on whitelisting. Costs cannot be covered by minters as only the owner can come up with the list. Of course, you may try to optimize the above code. Add batch functions and so on. That may reduce the costs, but only by a little amount. Whitelisting will be still damn expensive in comparison to other techniques.
- Easy to implement and deploy
- Simple process of adding/kicking out somebody from the whitelist
- No need to deliver anything to participants prior to mint
I personally recommend this technique for blockchains like Polygon/BSC/Arbitrum/Optimism because transactions are very cheap there and there is nothing to worry about.
Whitelisting 1k addresses may cost you ~$500 depending on current gas prices at mainnet.
As nobody wants to invest more than needed let’s take a look at cheaper solutions now.
Merkle tree whitelist
The second very popular solution is to use a data structure called Merkle Tree. The collection creator can generate Merkle tree completely off-chain without talking to the blockchain network and paying enormous gas fees.
The whole tree is built using secure cryptography. You may read about implementation details here. Anyway, that technique is powerful because you have total control of your whitelist and you do not have to spend too much on gas fees.
Before we dive into smart code let’s generate our proofs:
Once the tree and proofs are generated, the smart contract needs to get logic for validating them:
Passing wrong proof (from a different tree or just a random string) would result in an error. If some attacker would change the structure of the tree (by inserting their address or manipulating amounts) the Merkle root would be entirely different.
The smart contract just validates the generated proofs and it's not that memory extensive as Solidity example mentioned earlier. Proofs are long and random enough to not be easily guessed.
- Cheaper whitelisting and minting
- Changes to the whitelist require rebuilding Merkle tree and updating the root on the contract
- Delivery of Merkle proofs to list participants is necessary
Lazy minting with vouchers
Another whitelisting solution is using the concept of securely signed vouchers. The procedure is almost the same as with Merkle Tree. However, before the minting, you need to generate vouchers off-chain and sign them with your private key:
The voucher may contain information about which address can use it and which token id precisely can be minted. Of course, it’s possible just to mint any available id. In such a scenario, you’d need to refactor a bit structure of the voucher. Need to take payment for minting even for whitelisted guys? No problem… just make the redemption function payable and validate the amount sent to it.
The last step is to add logic to the contract that may validate if the voucher was produced by the minter address:
I personally prefer above technique than merkle proofs. I think it’s more flexible and still cheap.
- Cheaper minting
- Flexible, you may produce many vouchers over time
- Delivery of vouchers to participants is necessary
That’s pretty much it. If you understand how & when using the above techniques you are ready for building whitelists effectively.
Good luck with your upcoming drops. WAGMI