使用 Merkle 树实现一个完整的空投系统

181 阅读3分钟

空投合约和链下服务可以配合实现高效的代币分发,具体如下:

1. 架构设计

  • 链下服务
  • 准备空投名单,包括每个用户的地址和分发的代币数量
  • 生成 Merkle 树和对应的 Merkle 根
  • 为每个用户生成 Merkle 证明路径
  • 将 Merkle 根部署到链上,用于空投验证。
  • 链上合约
  • 存储 Merkle 根
  • 提供领取空投的接口,验证用户提交的地址、金额和 Merkle 证明是否有效
  • 记录已领取的地址,防止重复领取

2. 代码实现

2.1 链下服务

  • Python 示例:生成 Merkle 树和证明

import hashlib

def hash(data):
    """计算数据的哈希值"""
    return hashlib.sha256(data.encode('utf-8')).hexdigest()

def build_merkle_tree(data_list):
    """构建 Merkle 树"""
    if len(data_list) % 2 != 0:
        data_list.append(data_list[-1])  # 如果节点数是奇数,则复制最后一个节点

    tree = [data_list]  # 第一层是叶节点
    while len(tree[-1]) > 1:
        level = []
        for i in range(0len(tree[-1]), 2):
            combined = hash(tree[-1][i] + tree[-1][i + 1])
            level.append(combined)
        tree.append(level)
    return tree

def get_merkle_root(tree):
    """获取 Merkle 树根"""
    return tree[-1][0]

def get_proof(tree, index):
    """生成某个节点的 Merkle 证明"""
    proof = []
    for level in tree[:-1]:  # 不包含根
        sibling_index = index ^ 1  # 获取兄弟节点索引
        if sibling_index < len(level):
            proof.append(level[sibling_index])
        index //= 2  # 上一层的索引
    return proof

# 示例:生成空投数据
airdrop_list = {
    "0x123...abc"100,
    "0x456...def"200,
    "0x789...ghi"150,
}

# 计算每个用户的哈希值
hashed_data = [hash(f"{addr}:{amount}"for addr, amount in airdrop_list.items()]

# 构建 Merkle 树
merkle_tree = build_merkle_tree(hashed_data)
merkle_root = get_merkle_root(merkle_tree)

# 生成证明
for i, (addr, amount) in enumerate(airdrop_list.items()):
    proof = get_proof(merkle_tree, i)
    print(f"Address: {addr}, Amount: {amount}, Proof: {proof}")

print("Merkle Root:", merkle_root)

2.2链上合约


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MerkleAirdrop {
    address public admin;
    bytes32 public merkleRoot;
    IERC20 public token;

    // 记录已经领取的地址
    mapping(address => bool) public hasClaimed;

    event Claimed(address indexed account, uint256 amount);
    event MerkleRootUpdated(bytes32 merkleRoot);

    constructor(address _token) {
        admin = msg.sender;
        token = IERC20(_token);
    }

    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    /**
     * @notice 更新 Merkle 根
     * @param _merkleRoot 新的 Merkle 根
     */
    function updateMerkleRoot(bytes32 _merkleRoot) external onlyAdmin {
        merkleRoot = _merkleRoot;
        emit MerkleRootUpdated(_merkleRoot);
    }

    /**
     * @notice 领取空投
     * @param amount 领取的代币数量
     * @param proof Merkle 证明路径
     */
    function claim(uint256 amount, bytes32[] calldata proof) external {
        require(!hasClaimed[msg.sender], "Already claimed");

        // 验证 Merkle 证明
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender, amount));
        require(verify(leaf, proof), "Invalid proof");

        // 标记为已领取并发送代币
        hasClaimed[msg.sender] = true;
        require(token.transfer(msg.sender, amount), "Transfer failed");

        emit Claimed(msg.sender, amount);
    }

    /**
     * @notice 验证 Merkle 证明
     * @param leaf 被验证的叶子节点
     * @param proof Merkle 证明路径
     * @return 是否有效
     */
    function verify(bytes32 leaf, bytes32[] memory proof) public view returns (bool) {
        bytes32 computedHash = leaf;

        for (uint256 i0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];

            if (computedHash <= proofElement) {
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }

        return computedHash == merkleRoot;
    }
}

3. 完整流程

  • 链下服务
  • 准备空投数据,包括地址和金额
  • 计算每个地址的哈希值并生成 Merkle 树
  • 将 Merkle 根部署到链上
  • 为每个用户生成证明路径,并提供给用户
  • 链上合约
  • 管理员调用 updateMerkleRoot 设置新的空投 Merkle 根
  • 用户调用 claim 提交领取请求,提供地址、金额和证明路径
  • 合约验证 Merkle 证明,通过后将代币转给用户

The Web3 社区简介

The Web3 是一个专注于 Web3 技术解决方案设计与开发的社区,致力于为个人和企业提供专业提升的教程设计、研发与培训服务。此外,The web3 还提供项目安全审计、投研分析和项目孵化等全方位支持。