web3默克尔树MerleTree白名单校验

默克尔树(⼜叫哈希树)是⼀种典型的⼆叉树结构,有⼀个根节点、⼀组中间节点和⼀ 组叶节点组成。

曾⼴泛⽤于⽂件系统和P2P系统中。⽐如 git 、 区块链 、 IPFS 等

主要特点:类似二叉树, 最下⾯的叶节点包含存储数据或其哈希值; ⾮叶⼦节点(包括中间节点和根节点)都是它的两个⼦节点内容的哈希值
在这里插入图片描述
比特币中的默克尔树
在这里插入图片描述

MerkleTree的校验

判断某个叶⼦节点是否存在于树中,不需要知道整棵树的所有 节点的hash值,只需要找到需要校验的叶⼦节点的相邻节点的HASH,以及祖先节点相 邻节点的HASH即可

空投白名单应用

步骤简单概括

  1. 创建默克尔树, 拿到merkleRoot和对应地址的Proof, 其中merkleRoot上传到智能合约
  2. 使用地址和对应的Proof调用合约去验证

相关开源库

合约开源库: https://docs.openzeppelin.com/contracts/4.x/api/utils#MerkleProof
前端开发库:https://github.com/miguelmota/merkletreejs

步骤

  1. 前端配置的⽩名单地址,⽣成根节点hash。

  2. 合约存根节点hash值。

  3. 前端传⼊领取空投的address,和兄弟节点以及祖先的兄弟节点hash

合约代码

pragma solidity ^0.8.9;
 pragma abicoder v2;
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
contract Merkletree{
    
    
    bytes32 public rootHash;
    function setRootHash(bytes32 _rootHash) public{
    
    
        // 设置节点hash,需要做权限管理 ,方便测试,不做限制
        rootHash = _rootHash; 
    }
    function claimable(bytes32[] memory proof, bytes32 leaf)  public view returns(bool) {
    
    
        // 校验 
        return MerkleProof.verify(proof, rootHash, leaf); 
    }

    function claim(bytes32[] memory proof, bytes32 leaf) public {
    
    
        // 验证当前地址是否是msg.sender
        require(leaf == keccak256(abi.encodePacked(msg.sender)), "only by sender"); 
        // 验证叶⼦是否在⽩名单
        require(claimable(proof, leaf), 'auth faild');
        // mint Token and transfer to leaf address
    }
}

js代码

import {
    
     MerkleTree } from "merkletreejs";
import keccak256 from "keccak256";
import {
    
     newContract,ChainId, multicallClient } from "@chainstarter/multicall-client.js";

const WhiteList = [
  "0xd4D75e2eB480D61822B9cA40EB54cb322F08d920",
  "0xdafea492d9c6733ae3d56b7ed1adb60692c98bc5",
  "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
  "0x8b8a11755a3f2B9f2cE384bc42Cb25053Eb4FF33",
  "0xd2Ece3F5A7738E4B14c13C0336E3e879755FCd77"
]

const leaves = WhiteList.map((x) => keccak256(x));
const merkleTree = new MerkleTree(leaves, keccak256);
const rootHash = merkleTree.getRoot().toString("hex");

const leaf = keccak256(inputAccount);
const proof = merkleTree.getProof(leaf);
//前端校验
const isWhiteList = merkleTree.verify(proof, leaf, rootHash)

// 合约校验
// 在此之前,需要调用setRootHash,将rootHash存入合约
const leaf32 = `0x${
      
      leaf.toString("hex")}`;
const proof32 = proof.map((x) => "0x" + x.data.toString("hex"));
const contract = newContract(
  MerkleTreeAbi,
  MerkleTreeAddress,
  ChainId.RINKEBY
);
multicallClient([
  contract.claimable(proof32, leaf32),
  contract.rootHash(),
]).then((res) => {
    
    
  console.log("是否存在白名单", res[0].returnData);
  console.log("合约rootHash", res[1].returnData);
  setIsWhiteList(!!res[0].returnData);
});

猜你喜欢

转载自blog.csdn.net/weixin_43840202/article/details/127181807