Skip to content

使用 Merkle 树做白名单验证 #3

@tangminjie

Description

@tangminjie

使用 Merkle 树做白名单验证,简单来说就是将所有的白名单钱包地址做为 Merkle 树的叶节点生成一棵 Merkle 树,在部署的NFT 合约中只存储 Merkle 树的 root hash,这样避免了在合约中存储所有白名单地址带来的高额 gas 费用。在 mint 时,链下生成钱包地址的 Merkle proof,调用合约进行验证。

合约实现

whitelist.sol中实现了传统mapping储存白名单的方式和Merkle树储存白名单的方式,因为使用mapping需要占用大量的存储空间,所以我们选择使用Merkle的方式来验证。

openzepplin MerkleProof

openzeppelin 提供了Merkle实现库,我们仅需要import '@openzeppelin/contracts/utils/cryptography/MerkleProof.sol';
并且实现:
1.设置Merkle root hash
2. 提供external接口对 proof进行验证,MerkleProof.verify(proof, _merkleTreeRoot, keccak256(abi.encodePacked(leaf) 其中leaf传入调用者的地址,也就是白名单中的地址才能校验成功。

Merkle proof 证明生成

调用合约验证的 Merkle proof 需要在前端生成。生成过程需要用到 merkletreejs和 keccak256 两个库,前者用于创建 Merkle 树,后者用于生成哈希。
链下实现代码在Utils/helpers.js文件中:

  1. 获取 hardhat-deploy生成的地址,当作白名单测试地址。
  2. 生成白名单地址的Merkle树:
    const leafNodes = whitelistAddresses.map((adr) => keccak256(adr));
    const merkleTree = new MerkleTree(leafNodes, keccak256, {
      sortPairs: true,
    });
  1. 对地址列表生成Merkle证明: proofs: whitelistAddresses.map((addr) => merkleTree.getHexProof(keccak256(addr))),
    生成证明格式:
Proof of 0xc12ae5Ba30Da6eB11978939379D383beb5Df9b33:  [
  '0x1575cc1dded49f942913392f94716824d29b8fa45876b2db6295d16a606533a4',
  '0x6c42c6099e51e28eef8f19f71765bb42c571d5c7177996f177606138f65c0c2b',
  '0xb0d6f760008340e3f60414d84b305702faa6418f44f31de07b10e05bf369eb3b',
  '0x4c880bf401add28c4e51270dfe16b28c3ca1b3d263ff7c5863fc8214b4046364'
]

验证过程

调用checkMerkleTreeRootForWhitelist 传入验证者address 和对应的 proof。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions