Skip to content
On this page

L2-18: Token Curated Registry(代币策展注册表)

1. 问题

使用代币质押机制构建去中心化的高质量列表——通过经济激励驱动列表内容的质量。申请者质押代币将条目加入列表;任何代币持有者可以发起挑战(也需质押);社区投票决定条目的去留;胜方获得败方的质押代币。

这是 Token Curated Registry (TCR) 模式——通过加密经济激励实现无需中心化审核的策展系统。

2. 原因

Web3 的去中心化本质需要去中心化的内容审核机制。传统互联网依赖中心化平台(Yelp、App Store、Trustpilot)来维护列表质量,但这些平台存在审核偏见、审查、和数据垄断问题。

TCR 通过经济激励解决了这些问题:

  • 质押即承诺:申请者用真金白银(代币)承诺其条目的质量
  • 挑战即制衡:任何人发现低质量条目可以发起挑战,赢则获奖励
  • 投票即治理:代币持有者通过投票参与策展决策
  • 经济安全:不诚实的提交者损失质押,诚实的策展者获得回报

应用场景:优质 DApp 列表、代币白名单、内容审核、去中心化的 Yelp 替代品。

3. 方案

合约架构

solidity
contract TokenCuratedRegistry {
    enum ListingState { None, Applied, Challenged, Accepted, Rejected }

    struct Listing {
        bytes32 listingHash;
        address applicant;
        address challenger;
        uint256 depositAmount;
        uint256 challengeAmount;
        uint256 applyTime;
        uint256 challengeTime;
        ListingState state;
        uint256 votesFor;
        uint256 votesAgainst;
        bool resolved;
    }

    IERC20 public immutable token;       // 质押代币
    uint256 public immutable minDeposit; // 最小质押量
    uint256 public immutable challengePeriod; // 挑战窗口期
    uint256 public immutable votePeriod; // 投票窗口期

    mapping(bytes32 => Listing) public listings;
    mapping(bytes32 => bool) public isListed;
}

生命周期

1. applyListing(hash) → 质押 MIN_DEPOSIT → state = Applied
2. challenge(hash)    → [挑战窗口期内] → 挑战者质押 → state = Challenged
3. vote(hash, accept) → 代币权重投票 → forVotes / againstVotes 累加
4. resolve(hash)      → [投票期结束] → 胜方获双方质押
5. autoAccept(hash)   → [无挑战 + 超时] → 返还质押,条目接受

投票权重

solidity
function vote(bytes32 listingHash, bool acceptVote) external {
    Listing storage listing = listings[listingHash];
    require(listing.state == ListingState.Challenged, "No active challenge");
    require(block.timestamp <= listing.challengeTime + votePeriod, "Vote ended");
    require(!hasVoted[listingHash][msg.sender], "Already voted");

    uint256 balance = token.balanceOf(msg.sender);
    require(balance > 0, "No tokens");

    if (acceptVote) {
        listing.votesFor += balance;
    } else {
        listing.votesAgainst += balance;
    }
}

4. 遭遇的陷阱

4.1 Sybil 攻击的风险

代币投票权重基于 balanceOf(msg.sender)。攻击者可以将代币分散到多个地址来获得更多投票权。这与 DAO 治理中的 Sybil 攻击是同一问题——TCR 的解决方案是要求最小质押量(提高攻击成本)。

4.2 投票冷漠(Voter Apathy)

大多数代币持有者不参与投票。如果只有少数人投票,TCR 容易被少数活跃用户操控。这需要机制设计来激励投票参与——例如,投票者分享一部分败方质押。

4.3 挑战窗口期的时间设定

challengePeriod 太短 → 社区来不及发现和挑战低质量条目。太长 → 条目在列表中处于不确定状态太久。典型值是 3-7 天。

4.4 质押资产的流动性锁定

申请者和挑战者的代币在争议期间被锁定(不可转让或使用)。如果挑战期 + 投票期很长(如 14 天),大量代币被锁定可能影响代币的流动性。

5. 陷阱的原因

5.1

基于代币余额的投票天然不对 Sybil 免疫。与基于身份的系统不同(如 1 人 1 票),TCR 假设经济激励能约束行为——攻击者需要大量代币才能操控投票,而这些代币的持有者也希望 TCR 正常工作(否则代币贬值)。

5.3

挑战窗口期是对效率和质量的权衡。金融类列表(如代币白名单)需要短窗口(快速决策),文化类列表(如艺术品策展)可以容忍长窗口(慢策展)。

6. 如何解决陷阱

  • minDeposit 需要足够高,使得 Sybil 攻击成本显著
  • 在链下建立通知系统(Twitter bot、Discord webhook),当新条目被提交时提醒社区
  • 可考虑「投票奖励」机制——将败方质押的一部分分配给投票者(需要在 resolve 中实现按投票比例分配)
  • 根据应用场景合理设定 challengePeriodvotePeriod

7. 技术要点

要点说明
TCR 生命周期Applied → Challenged → Accepted/Rejected
双向质押申请者 + 挑战者都需要质押 MIN_DEPOSIT
代币权重投票balanceOf(voter) 决定投票权重
经济裁决胜方获得双方质押,败方损失质押
超时自动通过无人挑战且超时 → autoAccept 返还质押
挑战窗口challengePeriod 决定公平挑战的时间
防重投hasVoted mapping 确保每个地址只投一次

Built with AiAda