Skip to content

调研:Merkl Protocol

Merkl Protocol 是一个 DeFi 奖励分发协议,通过链上合约 + 链下计算引擎 + Merkle 树验证,实现项目方自助创建奖励活动、用户一键领取多协议奖励。


调研动机

  1. DeFi 业务有接入 Merkl Protocol 的计划
  2. Merkl Protocol 的技术架构有创新性,值得学习参考
  3. 当前 DeFi Bonus 活动创建仍需后端和合约的手动操作,希望效仿 Merkl 实现自动化

背景:为什么需要 Bonus

Bonus 类似于 Web2 的大促打折,通过额外奖励吸引用户参与 DeFi 协议。对于小众协议尤其重要——用户不了解也没有意愿参与,Bonus 是引流的有效手段。

DeFi Bonus 演进

维度Bonus 2.0Bonus 3.0(Merkl)
技术架构链上金库 + 链下计算链上金库 + 链下计算
领取方式用户主动 claim用户主动 claim
活动创建手动申请 → 部署合约 → 配置活动项目方一键创建
领取验证私钥验签Merkle 树验证
领取范围一次只能领单一协议一次领取一条链上所有奖励

产品功能

Merkl Platform 面向两类用户:

普通用户

项目方

活动上线

参与活动

Create 页面

选择活动类型
设置奖励参数
存入奖励资金

Opportunities 页面
发现感兴趣的活动

Dashboard 页面
查看奖励 & 一键领取

支持的活动类型

  • Concentrated Liquidity Pool (CLAMM) 激励活动
  • Airdrop 空投活动
  • ERC20 代币激励活动(包含 LP Token、借贷代币等)
  • Silo 和 Radiant 借贷激励
  • Token Snapshot 快照活动

收费策略

只向项目方收费,用户不收费(领取时需自付 Gas):

  • 按量付费:活动抽成 3%,空投仅 0.5%
  • 订阅制:年奖励超 $1M 的项目可获定制方案和折扣

市场数据

  • 上线时间:2023 年 3 月
  • 每周分发奖励约 $610k
  • 活动主要集中在 ArbitrumEthereum 链上
  • 80% 以上的活动为流动性池类型

各链奖励发放排名

排名累计发放金额
Arbitrum1$15.32M
Ethereum2$14.47M
Polygon3$5.098M
Optimism4$2.776M
Immutable zkEVM5$1.395M
Base6$1.314M
Blast7$713.7K
Manta Pacific8$504.5K
Mode9$334.8K
Polygon zkEVM10$246.1K

Dune 数据看板:https://dune.com/clarkcui/merkl-angle


技术原理

整体架构

链下服务

链上合约

活动信息

查询链上数据

提交 Merkle Root

存储历史

读取

验证

发现错误则回滚

Creator Contract
创建活动 & 存储活动信息

Distributor Contract
存储奖励资金 & Merkle Root
用户 claim 交互

AccessControlManager
多签管理合约

Merkl Engine
(非公开)
计算奖励 & 生成 Merkle Root

Merkl Public API
(公开)
供前端查询奖励和 Proof

Dispute Bot
验证 Merkle Root 正确性

Merkl Rewards Bucket
存储历史 Merkle Root

RPC / Subgraph

完整生命周期

用户Dispute BotDistributor 合约链上数据Merkl EngineCreator 合约项目方用户Dispute BotDistributor 合约链上数据Merkl EngineCreator 合约项目方每 3-12 小时执行一次争议期 1-2 小时alt[发现错误]争议期结束后创建活动 & 存入奖励获取活动信息查询 LP 持仓等数据计算每个地址的奖励聚合生成 Merkle Root提交新的 Merkle Root验证 Merkle Root 正确性回滚到上一个 Merkle Root调用 claim 方法Merkle 证明验证发送奖励代币 💰

关键机制

Distribution Epochs(分发时期)

Merkl Engine 统计和计算收益的时间周期,一般 3-12 小时(不同链可能不同)。这决定了用户每天最多可以领取几次新奖励。例如 8 小时周期意味着每天最多 3 次。

Dispute Periods(争议期)

新 Merkle Root 生成后的 1-2 小时窗口期。在此期间:

  • 用户 claim 会失败(返回上一个有效的 Merkle Root)
  • Dispute Bot 验证新 Root 的正确性
  • 发现错误可使其无效并回滚

任何人都可以运行争议机器人:https://github.com/AngleProtocol/merkl-dispute

每条链只有 3 个合约

  • Creator:项目方创建活动,保存活动信息
  • Distributor:存储奖励资金和 Merkle Root,供用户 claim
  • AccessControlManager:2-3 多签管理合约

合约代码分析

Creator 合约

活动数据结构:

solidity
struct CampaignParameters {
    bytes32 campaignId;
    address creator;
    address rewardToken;
    uint256 amount;
    uint32 campaignType;
    uint32 startTimestamp;
    uint32 duration;
    bytes campaignData;
}

创建活动时自动扣除手续费,将奖励资金转入 Distributor 合约,并将活动信息存入 campaignList

Distributor 合约

1. Merkle Root 存储与更新

solidity
MerkleTree public tree;      // 当前 Merkle Root
MerkleTree public lastTree;  // 上一个 Merkle Root

function updateTree(MerkleTree calldata _tree) external {
    // 检查:无争议 & 有更新权限 & 争议期已过
    MerkleTree memory _lastTree = tree;
    tree = _tree;
    lastTree = _lastTree;
}

合约只存储 Merkle Root(而非整棵树),因为验证只需要 Root + Proof 路径即可,完整的树数据存储在链下。

2. Merkle 证明验证

solidity
function getMerkleRoot() public view returns (bytes32) {
    // 争议期内返回上一个有效 Root,争议期后返回最新 Root
    if (block.timestamp >= endOfDisputePeriod && disputer == address(0))
        return tree.merkleRoot;
    else
        return lastTree.merkleRoot;
}

function _verifyProof(bytes32 leaf, bytes32[] memory proof) internal view returns (bool) {
    bytes32 currentHash = leaf;
    for (uint256 i; i < proof.length; ) {
        // 从叶子节点逐层向上计算 Root
        if (currentHash < proof[i]) {
            currentHash = keccak256(abi.encode(currentHash, proof[i]));
        } else {
            currentHash = keccak256(abi.encode(proof[i], currentHash));
        }
        unchecked { ++i; }
    }
    return currentHash == getMerkleRoot(); // 与链上存储的 Root 比对
}

3. 用户 Claim

solidity
function claim(
    address[] calldata users,
    address[] calldata tokens,
    uint256[] calldata amounts,
    bytes32[][] calldata proofs
) external {
    for (uint256 i; i < users.length; ) {
        // 权限检查:只有用户自己或被授权者可以 claim
        // 构造叶子节点:leaf = keccak256(user, token, amount)
        // 验证 Merkle 证明
        // 计算应发金额 = 累计金额 - 已领金额
        // 转账代币给用户
        unchecked { ++i; }
    }
}

Claim 的最小维度是币种(token)级别——用户可以一次性领取同一条链上所有协议的所有币种奖励。

争议期内 claim 如何被阻止

getMerkleRoot() 在争议期内返回的是 lastTree.merkleRoot(上一个已验证的 Root)。新周期的奖励数据只存在于新 Root 的 Merkle 树中,用旧 Root 验证新奖励的 Proof 会失败,所以争议期内新奖励无法被领取。

Merkle 验证流程图

+ proof[0]

+ proof[1]

+ proof[n]

比对

Yes

No

叶子节点
keccak256(user, token, amount)

中间节点 1

中间节点 2

计算得到的 Root

链上存储的
Merkle Root

相等?

✅ 验证通过
发放奖励

❌ 验证失败
拒绝领取


集成方式

通过 Merkl Public API 集成,前端可以独立构建 claim 页面:

API 调用示例

GET https://api.merkl.xyz/v3/userRewards?user={address}&chainId={chainId}&proof=true

返回数据包含每个代币的累计奖励、未领取金额和 Merkle Proof:

json
{
  "0x代币地址": {
    "accumulated": "1474003470054576877800",
    "symbol": "ANGLE",
    "unclaimed": "1474003470054576877800",
    "reasons": {
      "Arrakis": { "accumulated": "996...", "unclaimed": "996..." },
      "UniswapV3": { "accumulated": "349...", "unclaimed": "349..." }
    },
    "proof": ["0xf1c7...", "0x7192...", "..."]
  }
}

前端 Claim 代码

javascript
import { Distributor__factory } from "@angleprotocol/sdk";
import axios from "axios";

export const claim = async (chainId, signer) => {
  // 1. 从 API 获取用户奖励数据(含 proof)
  const { data } = await axios.get(
    `https://api.merkl.xyz/v3/userRewards?chainId=${chainId}&user=${signer._address}&proof=true`
  );

  // 2. 筛选有 proof 的代币
  const tokens = Object.keys(data).filter(k => data[k].proof?.length > 0);
  const claims = tokens.map(t => data[t].accumulated);
  const proofs = tokens.map(t => data[t].proof);

  // 3. 调用 Distributor 合约的 claim 方法
  const contract = Distributor__factory.connect(distributorAddress, signer);
  await (await contract.claim(
    tokens.map(() => signer._address), // users
    tokens,                             // tokens
    claims,                             // amounts
    proofs                              // proofs
  )).wait();
};

总结

优势

  • 项目方自助创建活动,无需人工操作,节省人力和合规风险
  • 用户一键领取所有奖励,无需辗转各协议页面,节省 Gas
  • Merkle 树验证机制安全可靠,争议期 + Dispute Bot 提供额外保障

不足

  • 核心 Merkl Engine 不开源,存在中心化风险
  • Public API 无需鉴权,容易被攻击(曾出现过 API 故障)
  • 奖励计算依赖链下服务,若引擎出错可能导致奖励分配不准确

参考资料