In this article I will show you three ways you can create a whitelist in a smart contract.
Here's what we'll discuss:
- On-chain whitelists
- Digital signatures
- Merkle trees
All methods are available in the repo here.
A whitelist is useful if you want to restrict access to a certain function or want to grant privileges to a certain group of users.
To compare these methods, I'm going to use very minimalistic smart contracts to reduce the unnecessary spending of gas.
Let's dive into it.
How to Create an On-Chain Whitelist
The main idea is to store all whitelist addresses in the smart contract.
Take a look at this schema:
When user calls the smart contract function, it checks if the address is in the whitelist. If it is, the function executes.
If you want to add or remove addresses from the whitelist, you can do it in the smart contract with additional external
functions.
Pros:
- easy to implement
- all addresses are stored in the smart contract and only the owner can edit them
Cons:
- it's the most expensive method
- you have to spend gas to add and remove the addresses
Here's what the smart contract looks like:
All addresses will be stored in the whitelist
variable.
The function addToWhitelist
allows the owner to add an array of addresses. Keep in mind that each address in the list will spend about 22904 gas units. To call that function costs 23994 gas units.
The function removeFromWhitelist
allows you to remove addresses from the whitelist.
And the function whitelistFunc
checks if the address belongs to the whitelist.
Gas spending:
How to Create a Digital Signature Whitelist
The main idea is to create signatures for addresses and check them inside the smart contract.
You store the whitelist on your server. Before making a call to the smart contract, you should check if the address is in the whitelist or not. If yes, create a signature for the address and pass that signature to the smart contract. Inside the smart contract you have to validate that signature.
Pros:
- No gas for adding or removing addresses from the whitelist.
- No need to interact with the smart contract about the whitelist
Cons:
- Whitelist is located in a database that can be compromised. If the audience trusts the owner of the project, then this is not a problem
- The most expensive price for contract deployment and whitelist validating
Here's the smart contract:
How to implement a digital signature
First, you'll need to create a new wallet address. It will be signer address.
ATTENTION: Do not send any funds to that wallet. It will be used only for making signatures.
Let's assume, that the signer wallet address is 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Specify it in the smart contract here:
address private signerAddress = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266;
In the root of your web project, create a .env
file with private key of that wallet:
SIGNER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
Specify only your own public and private keys, because these are publicly known.
Next, create the whitelist database. It can be PostgreSQL, MySQL, MongoDB – any one you want. You can easily add or remove addresses.
Then when it's time to interact with the smart contract, the user clicks a button on your website. You send the request to your server with the user's address.
If the user is in the whitelist, create the signature for the address on your server:
Then pass the signature to the smart contract function, where verifyAddressSigner
will validate it according to the sender's address.
Gas spending:
How to Create a Merkle Tree Whitelist
What is the Merkle tree?
Merkle tree is a tree in which every "leaf" (node) is labelled with the cryptographic hash of a data block, and every node that is not a leaf (called a branch, inner node, or inode) is labelled with the cryptographic hash of the labels of its child nodes. – Source
How does it connect to the whitelist problem?
We will use it to hash all addresses into one root hash.
This is the schema of work:
Like in the digital signature method, you need a database for the whitelisted addresses. When you are ready to start the sale or something else, you need to create the Merkle root hash and save it in the smart contract. This hash will validate all the addresses.
When the user wants to make a request to the smart contract, you need to create a Merkle proof for him, based on the Merkle tree of all addresses. Then you need to send proof to the smart contract. You can store the tree locally.
After editing the whitelist you should update the Merkle root hash and rewrite it to the smart contract. You should also update the local Merkle tree.
Pros:
- Deployment of the smart contract is much cheaper than the digital signature method
- Validating addresses in the smart contract is also cheaper
- No gas for adding or removing addresses from whitelist, until you start a sale
Cons:
- After the sale has started, it will be complicated to change the whitelist. You will need to update the smart contract and Merkle tree each time. Therefore, gas will be spent.
- You need to know how to create a Merkle root and update the smart contact. It's impossible to change the whitelist without interacting with the smart contract.
Here's the smart contract:
How to implement a Merkle tree on the web
First, create the whitelist database. It can be PostgreSQL, MySQL, MongoDB or any other you want. You can easily add or remove addresses.
When it's time to interact with the smart contract, create a Merkle root hash:
Then save the Merkle root hash in the smart contract.
Specify it before the deployment:
bytes32 public merkleRoot = 0x09485889b804a49c9e383c7966a2c480ab28a13a8345c4ebe0886a7478c0b73d;
Or use a function setMerkleRoot
for it:
function setMerkleRoot(bytes32 merkleRootHash) external onlyOwner
{
merkleRoot = merkleRootHash;
}
When the user clicks a button on your website, you send the request to your server with the user's address. If the user is in the whitelist, create the Merkle proof on your server:
Then pass proof to the smart contract function, where verifyAddress
will validate it according to the sender's address.
Gas spending:
Summary
Below you will find a comparison table of the gas units these different methods spend:
Property | On-chain | Digital signature | Merkle tree |
---|---|---|---|
Deployment | 329 724 | 486 182 | 352 790 |
Add to whitelist 1 address | 46 898 | 0 | 28 986 |
Add to whitelist 10 addresses | 253 010 | 0 | 28 986 |
Remove from whitelist | 24 930 | 0 | 28 986 |
Call function with whitelist | 23 443 | 29 365 | 26 065 |
Long story short:
- An on-chain whitelist easy to implement, but expensive to use. I would not recommend using it.
- A digital signature whitelist is a universal tool that does not require additional interactions with the smart contract. You can easily edit the whitelist at any time. But you have to pay for versatility. Deployment and function with the whitelist are the most expensive. If your addresses change frequently, then use digital signature.
- Merkle tree is the best option if your whitelist addresses will not change after you start presale or whatever you want. For example, it costs nothing to collect addresses and edit them in your database. When the sale starts, you stop editing the whitelist, create the root hash, save it to the smart contract and that's it. In that case the Merkle tree is better than digital signature.
What exactly to use is up to you!
Finally, I want to show you how to calculate gas price.
How to calculate gas price
Use the following formula:
(gas units) * (gas price per unit) = gas fee in gwei
Use https://ethgasstation.info/ or any other website to find gas price per unit. At the moment of writing this article, gas price is 22.
The value can change depending on the time of day.
Let's calculate how much it will cost to deploy a digital signature smart contract.
Deployment = 486 182 * 22 = 10 696 004 gwei = 0,010696004 ETH
Now since the ETH/USD price is $1,324, it means that deployment to the Mainnet will cost about $14.
Maybe you want to convert the comparison table to USD?
Gas price per unit
= 22, ETH
= $1,324
Property | On-chain | Digital signature | Merkle tree |
---|---|---|---|
Deployment | $9.6 | $14.16 | $10.28 |
Add to whitelist 1 address | $1.37 | 0 | $0.84 |
Add to whitelist 10 addresses | $7.37 | 0 | $0.84 |
Remove from whitelist | $0.73 | 0 | $0.84 |
Call function with whitelist | $0.68 | $0.86 | $0.76 |
Thank you for reading! ❤