Solidity--使用Merkletrees为链上合约添加白名单【降低gas消耗】

前言

目前的NFT市场越来越火爆,入场的人越来越多,在很多NFT在公开销售的之前就会有设置白名单,让这些白名单的人提前可以购买,又或者制定的白名单的人才能进行购买,从而达到他们饥饿营销的手段,那么关于Solidity如何实现白名单,并且可以最大程度降低我的gas费用,我这边在下面文章总结了两种方式给大家分享。


文章目录


一、实现方式分类

合约白名单主要的实现方式一般分两种:

第一种:

数组存储所有白名单的地址,当使用的时候for循环判断msg.sender是否是存在白名单中.

缺点:如果名单过多,会消耗极高的gas

第二种:

MerkleTrees验证

优点:大大的降低了gas费用

目前市面上最优的方案就是使用第二种Merkletrees验证方式

接下来我们看看Merkletrees验证方式原理和如何实现

二、原理分析

Merkletrees 有三个类型节点,叶节点, 父节点,根节点

验证原理:

将白名单丢到算法里,取出根节点【树根】 ,树根只是哈希值,但里面包含了 全部的地址的基因,将【树根】作为变量存储在智能合约上,当验证用户是否属于白名单中,我们把当前用户地址扔进算法,然后取出来哈希值,简称为【树叶】,再将树叶作为参数,传入 智能合约中判断,如果和树根基因匹配就证明是白名单中er址通过验证.

 三、具体实现

实现分两个版块前端和合约

  1.   前端代码:
const {MerkleTree} = require('merkletreejs');
const keccak256 = require('keccak256');
const {ethers} = require("hardhat");

async function main (){
  let whitelistAddresses = [
    '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4',
    '0xc12ae5Ba30Da6eB11978939379D383beb5Df9b33',
    '0x0a290c8cE7C35c40F4F94070a9Ed592fC85c62B9',
    '0x43Be076d3Cd709a38D2f83Cd032297a194196517',
    '0xC7FaB03eecA24CcaB940932559C5565a4cE9cFFb',
    '0xE4336D25e9Ca0703b574a6fd1b342A4d0327bcfa',
    '0xeDcB8a28161f966C5863b8291E80dDFD1eB78491',
    '0x77cbd0fa30F83a249da282e9fE90A86d7936FdE7',
    '0xc39F9406284CcAeB426D0039a3F6ADe14573BaFe',
    '0x16Beb6b55F145E4269279B82c040B7435f1088Ee',
    '0x900b2909127Dff529f8b4DB3d83b957E6aE964c2',
    '0xeA2A799793cE3D2eC6BcD066563f385F25401e95',
    '0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2',
    '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
]; 

    //1.叶子节点数据制作
    let  leafNodes =[]; 
    for(let test in whitelistAddresses ){
        let leafNode = ethers.utils.keccak256(whitelistAddresses[test]);
        leafNodes.push(leafNode)
    
    }
 
    //2.生成树根
    let tree = new MerkleTree(leafNodes, keccak256, { sortPairs: true });
    console.log('root: ', tree.getHexRoot());
     
    //3.生成叶子的proof(需要检验的地址)
    console.log(tree.getHexProof(leafNodes[0]));
}

main ()


2.合约代码:

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract Test {
  bytes32 root ;
  address private owner;

  modifier onlyOwner (){
    require(owner == msg.sender,"you are not owner");
       _;
  }
  
  constructor() {
        owner =msg.sender;
  }
  //在前端把树根生成,传入合约.
  function setRoot(bytes32 _root) public onlyOwner{
          root = _root;
           
  }
  //把树叶的proof生成传入做校验
  function verify(bytes32[] memory proof) public view returns(bool result){
          bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
        return MerkleProof.verify(proof,root,leaf);
  }
}

以上代码的使用流程:

第一步:

1.在js里面先确定好白名单的地址,再把地址都转换成哈希【叶节点】

2.然后【叶节点】生成树根

3.最后再生成验证数据.

第二步:

1.使用以上第一步生成的树根,传入合约设置root.

2. 最后校验地址是否是白名单的地址,就调用合约verify方法,如果返回true则说明,校验通过.

相关材料与链接

merkletreejs JavaScript库:merkletreejs - npm keccak256

JavaScript库:keccak256 - npm

MerkleProof协议说明:Utilities - OpenZeppelin Docs

以上就是今天要讲的内容,希望可以帮助大家.


如果对以上的文章有任何问题欢迎指正或者讲清楚的地方需要了解可联系我

wc:luo425116243

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Solidity中,可以通过使用智能合约来实现ERC20代币的锁仓与释放。以下是一个简单的锁仓合约示例: ``` pragma solidity ^0.8.0; import "./IERC20.sol"; import "./SafeMath.sol"; contract TokenVesting { using SafeMath for uint256; address public beneficiary; uint256 public cliff; uint256 public start; uint256 public duration; uint256 public released; IERC20 public token; constructor( address _beneficiary, uint256 _cliff, uint256 _duration, address _token ) public { require(_beneficiary != address(0)); require(_cliff <= _duration); beneficiary = _beneficiary; cliff = _cliff; duration = _duration; start = block.timestamp; token = IERC20(_token); } function release() public { uint256 unreleased = releasableAmount(); require(unreleased > 0); released = released.add(unreleased); token.transfer(beneficiary, unreleased); } function releasableAmount() public view returns (uint256) { return vestedAmount().sub(released); } function vestedAmount() public view returns (uint256) { uint256 currentBalance = token.balanceOf(address(this)); uint256 totalBalance = currentBalance.add(released); if (block.timestamp < start.add(cliff)) { return 0; } else if (block.timestamp >= start.add(duration)) { return totalBalance; } else { return totalBalance.mul(block.timestamp.sub(start)).div(duration); } } } ``` 在这个合约中,当创建合约时,需要传入受益人地址、锁仓期、释放期、代币地址等信息。锁仓期结束后,受益人可以通过调用 `release()` 函数来释放锁仓代币。如果释放函数被调用,但是当前时间还没有到达释放期,则会抛出异常。 为了保证代币不能被提前释放,合约还实现了 cliff 的概念,即在锁仓期结束之前,代币不能被释放。当 cliff 结束之后,代币将按照线性方式释放,直到释放期结束。 需要注意的是,以上示例只是一个简单的锁仓合约示例,实际生产环境中需要更加严格地考虑各种情况和安全性问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zeke链上学堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值