And how to practically use the Merkle tree
In this article, we’ll dive into whitelisted NFT smart contracts, written in solidity. You’ll learn what is the whitelist, is the practical usage of the Merkle tree, and how to create whitelisted ERC721 in the most gas-efficient way when you have over a few thousand whitelisted addresses. Without further ado (here comes my favorite saying) — let’s get started.
Whitelisting is the process of allowing certain addresses to do certain things. In crypto space you allow address x to do some action, in a party, you can be whitelisted and thanks to that you can get in. Super simple. Anytime someone mentions whitelisting remember — it means that only certain people are allowed to do certain things (minting, getting into a party, etc.).
In NFT whitelisting is a popular process. People do that in order to disqualify bots and to build hype around a project. When something isn’t for everyone it drives people crazy. 🤯
As always in IT there are a few different ways of achieving the same goal. You could for example store whitelist addresses in mapping or array. There is one but though. Storing items is the most gas-expensive action in the blockchain so if there is a better way, why just don’t go for it? It turns out that there is.
Merkle tree is the answer. Technically speaking it’s a tree of hashes. So in order to calculate the root hash, which is the highest node, we have to calculate all of the previous hashes. Hashing is a one-directional operation so if any of the hashes used to calculate the root hash are incorrect the root hash will also be incorrect.
If we use addresses that we want to whitelist for creating leaves (the A,B,C … hashes) then we can easily verify if an address is whitelisted or not without storing a few thousand hashes, and save a lot of gas in the process 💸
The process is both off-chain and on-chain. We have to store the Merkle root in the smart contract, but first, we need to know one. How do we know it? We collect emails, addresses, and anything we want to whitelist off-chain, and then we use that data to calculate the Merkle root that we store afterward in the smart contract. Mapped into bullet points it would look like that:
- Collect emails, addresses, and anything you want to whitelist off-chain. It can be either on discord or through some online form,
- Get all of the things you want to whitelist and calculate a Merkle root for them,
- Inject a Merkle root to the smart contract,
- Your smart contract now supports whitelisting,
- You’re a happy developer (optional).
No more, no less. Now we’re gonna code it.
That’s it. Now let’s walk through the code.
Let’s assume that “whitelisted” is an array of addresses we want to whitelist. You got it from your discord server and now you’re loading it from your database. After loading you need to create a bytes array of length 64 out of it, because well, that’s the format you need to pass it. You create a buffer from a padded string, and padding means adding a character until the string is of a given length.
We create leaves that are a buffer of padded addresses and then calculate the MerkleTree using the keccak256 function. Keccak256 is a widely used hashing algorithm. We also set the sort option to true. The last step is to getHexRoot of the Merkle tree that we’ll use in our smart contract in order to be able to verify if an address that wants to mint is a whitelisted one. Voila.
From your front-end when you’ll code the minting function you’ll need to getHexProof with a padded sender address as an argument.
I won’t get through an ERC721 contract in this article. Instead, we’ll focus on whitelisting mechanism. There are 2 important operations. The first one is to inject the Merkle root that we calculated in the first step into the constructor. The second one is to pass Merkle proof calculated from a specific address. No magic here.
Since we’re in the blockchain baby, we need to test everything. That’s not an exception. The test I provided is self-explanatory, we get an array of fake addresses, and half of them are marked as whitelisted and the other half as not whitelisted. We then calculate the Merkle root of the tree and pass it as a constructor argument when deploying the contract. Preparing Merkle proof and invalidMerkleProof from an appropriate array and making sure that not whitelisted address indeed is not able to mint an NFT.
So what is a Merkle Tree? 🌲
A fast and efficient method to validate if something really is a part of some bigger data. In the whitelist example, it tells us if an address belongs to the whitelisted array and if it’s able to mint.