# NFT白名单校验-Merkle Tree

By [xyyme.eth](https://paragraph.com/@xyyme) · 2022-03-10

---

目前NFT白名单校验主要有两种方式

*   Merkel Tree
    
*   签名验证
    

其中签名验证的详细介绍在这篇[文章](https://mirror.xyz/xyyme.eth/-e1FodE7HZcwhw60VuGnbUue2SfCN4kn6JVg0JjCFS4)。

这篇文章我们主要来介绍 Merkle Tree 的实现方法。关于其原理，我们这里就不再多赘述了，不太了解的朋友可以 Google 一下，今天主要讨论一下实现细节。

一般要实现 Merkle Tree 校验，主要有两部分的工作：

*   后台根据白名单地址生成一个 Merkle Tree，包括 Merkle Root。管理员将生成的 Merkle Root 设置到合约中
    
*   前端（或者后端）根据当前的用户，生成一个 Merkle Proof。将 Proof 作为参数传入合约中，与 **msg.sender** 和之前设置的 **Merkle Root** 进行校验
    

### 合约部分

这里的校验逻辑可以直接使用 Openzeppelin 的[现成合约库](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)，可以看到，需要的参数有：

*   proof（由链下生成传入，每个用户的 proof 都不同）
    
*   root（链下生成好之后设置为状态变量，所有用户均相同）
    
*   leaf（由用户的地址生成）
    

    function verify(
        bytes32[] memory proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }
    

那么如何调用 verify 方法呢：

    function verify(address addr, bytes32[] calldata _merkleProof) public view returns (bool) {
        bytes32 leaf = keccak256(abi.encode(addr));
        return MerkleProof.verify(_merkleProof, merkleRoot, leaf);
    }
    

通过 encode 编码之后再进行 hash 运算，便可以生成 Merkle Tree 的一个 leaf，这个 leaf 便是 verify 方法的参数 leaf。注意这里我们是将用户地址作为参数传给合约，实际开发时应该直接使用 **msg.sender** 作为原始参数，这是为了保证安全（否则不是白名单的地址就可以传递白名单地址来给自己 mint）。

verify 方法会返回一个 boolean 值，代表白名单校验是否成功。

### 链下计算部分

下面来说说链下的工作，前面说过，链下要根据白名单数据生成 Merkle Tree，我们这里使用 Javascript 来完成相关工作。

首先需要安装两个依赖包：

> npm install --save keccak256 merkletreejs

实例代码如下：

    const { MerkleTree } = require('merkletreejs');
    const keccak256 = require('keccak256');
    
    // 白名单地址，这里采用了硬编码，实际开发应该从数据库读取
    // 这里我们随机生成几个地址，作为白名单示例
    let whitelistAddresses = [
        "0x978DCD67B155b3dBecd221Ec0D193f6fa7d3B8c2",
        "0x41fed4790A6137083fac595e00090b2D01d012b6",
        "0xFbC43c738d17F4d43627B8675A8cdC691A603BB3",
        "0xBD925b9Fab6Eb9f713238Cc688A91a7f5c7Ff4c8",
        "0xc6c74C251aa41FCB0De4c55fb751eec04f66774A"
    ]
    
    // 计算 leaf 叶子结点的数据
    const leafNodes = whitelistAddresses.map(addr => keccak256(addr));
    // 生成 Merkle Tree
    const merkleTree = new MerkleTree(leafNodes, keccak256, { sortPairs: true });
    
    // 获取 Merkle Root
    const rootHash = merkleTree.getRoot();
    // 打印查看 Merkle Tree 全部数据
    console.log('Whitelist Merkle Tree\n', merkleTree.toString());
    // 打印查看 Root 数据，需要设置到合约中
    console.log("Root Hash: ", rootHash.toString('hex'));
    
    // 选择一个白名单地址进行校验
    const claimingAddress = keccak256("0xc6c74C251aa41FCB0De4c55fb751eec04f66774A");
    
    // 计算这个地址的 Merkle Proof，注意这就是我们要传给合约的参数 Proof
    const hexProof = merkleTree.getHexProof(claimingAddress);
    console.log(hexProof);
    
    // 校验
    console.log(merkleTree.verify(hexProof, claimingAddress, rootHash));
    

通过这段代码，我们就可以生成 Merkle Root，以及用户地址对应的 Merkle Proof

一般来说，合约中还会包括一个设置 Root 的方法，便于在合约部署之后，将 Root 设置进去：

    function setRoot(bytes32 _root) external onlyOwner {
        root = _root;
    }
    

### 总结

Merkle Tree 白名单校验的代码逻辑就是这些。一般来说，整个白名单业务顺序如下：

1.  根据所有白名单地址计算出 Merkle Root，并设置到合约中
    
2.  前端会根据用户地址请求后端获取对应 Merkle Proof
    
3.  将 Proof 传入合约进行校验
    

### 使用 Merkle Tree 进行验证的合约

*   [Cartoons](https://opensea.io/collection/cartoonsnft) → [代码](https://etherscan.io/address/0xee29700134aab4f45b113e43e29ff06ce10687b7#code)
    
*   [Tasty Bones](https://opensea.io/collection/tastybonesxyz) → [代码](https://etherscan.io/address/0x1b79c7832ed9358e024f9e46e9c8b6f56633691b#code)
    
*   [Invisible Friends](https://opensea.io/collection/invisiblefriends) → [代码](https://etherscan.io/address/0x59468516a8259058bad1ca5f8f4bff190d30e066#code)
    
*   …
    

### 参考

[

Using Merkle Trees for NFT Whitelists
-------------------------------------

Using Merkle Trees for NFT Whitelists Introduction Merkle Trees have long been a facet in the fields of both cryptography and computer science well before the blockchain we know and love today ever ...

https://medium.com

![](https://storage.googleapis.com/papyrus_images/6916cac495739cca0924b034854068c45489702a3b699ce2f44cf0dbe6514cbd.png)

](https://medium.com/@ItsCuzzo/using-merkle-trees-for-nft-whitelists-523b58ada3f9)

---

*Originally published on [xyyme.eth](https://paragraph.com/@xyyme/nft-merkle-tree)*
