I've been revisiting ethers.js
recently to refresh my understanding of the details and to write a simple tutorial called "WTF Ethers" for beginners.
Twitter: @0xAA_Science
Community: Website wtf.academy | WTF Solidity | discord | WeChat Group Application
All the code and tutorials are open-sourced on GitHub: github.com/WTFAcademy/WTF-Ethers
In this chapter, we will introduce a method of using off-chain signatures as a whitelist for NFTs. If you are not familiar with the ECDSA
contract, please refer to WTF Solidity 37: Digital Signature.
Digital Signature
If you have used opensea
to trade NFTs, you will be familiar with signatures. The image below shows the window that pops up when signing with the small fox (Metamask
) wallet. It proves that you own the private key without needing to disclose it publicly.

The digital signature algorithm used by Ethereum is called Elliptic Curve Digital Signature Algorithm (ECDSA
), based on the digital signature algorithm of elliptic curve "private key - public key" pairs. It serves three main purposes:
- Identity Authentication: Proves that the signer is the holder of the private key.
- Non-Repudiation: The sender cannot deny sending the message.
- Integrity: The message cannot be modified during transmission.
Digital Signature Contract Overview
The SignatureNFT
contract in the WTF Solidity 37: Digital Signature uses ECDSA
to validate whitelist addresses and mint NFTs. Let's discuss two important functions:
-
Constructor: Initializes the name, symbol, and signing public key
signer
of the NFT. -
mint()
: Validates the whitelist address usingECDSA
and mints the NFT. The parameters are the whitelist addressaccount
, thetokenId
to be minted, and the signature.
Generating a Digital Signature
-
Message Packaging: According to the
ECDSA
standard in Ethereum, themessage
to be signed is thekeccak256
hash of a set of data, represented asbytes32
. We can use thesolidityKeccak256()
function provided byethers.js
to pack and compute the hash of any content we want to sign. It is equivalent tokeccak256(abi.encodePacked())
in Solidity.In the code below, we pack an
address
variable and auint256
variable, and calculate the hash to obtain themessage
: -
Signing: To prevent users from mistakenly signing malicious transactions,
EIP191
advocates adding the"\x19Ethereum Signed Message:\n32"
character at the beginning of themessage
, hashing it again withkeccak256
to obtain theEthereum signed message
, and then signing it. The wallet class inethers.js
provides thesignMessage()
function for signing according to theEIP191
standard. Note that if themessage
is of typestring
, it needs to be processed using thearrayify()
function. Example:
Off-Chain Signature Whitelist Minting of NFTs
-
Create a
provider
andwallet
, wherewallet
is the wallet used for signing. -
Generate the
message
and sign it based on the whitelist addresses and thetokenId
they can mint. -
Create a contract factory to prepare for deploying the NFT contract.
-
Deploy the NFT contract using the contract factory.
-
Call the
mint()
function of theNFT
contract, use off-chain signature to verify the whitelist, and mint anNFT
for theaccount
address.
For Production
To use off-chain signature verification whitelisting to issue NFT
in a production environment, follow these steps:
- Determine the whitelist.
- Maintain the private key of the signing wallet in the backend to generate the
message
andsignature
for whitelisted addresses. - Deploy the
NFT
contract and save the public key of the signing wallet (signer
) in the contract. - When a user wants to mint, request the
signature
corresponding to the address from the backend. - Use the
mint()
function to mint theNFT
.
Summary
In this lesson, we introduced how to use ethers.js
together with smart contracts to verify whitelisting using off-chain digital signatures for NFTs. Merkle Tree and off-chain digital signatures are currently the most popular and cost-effective ways to distribute whitelists. If the whitelist is already determined during contract deployment, we recommend using the Merkle Tree approach. If the whitelist needs to be constantly updated after contract deployment, such as in the case of the Galaxy Project's OAT
, we recommend using the off-chain signature verification approach, otherwise, the root
of the Merkle Tree in the contract needs to be constantly updated, which costs alot of gas.