Appearance
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 中实现按投票比例分配)
- 根据应用场景合理设定
challengePeriod和votePeriod
7. 技术要点
| 要点 | 说明 |
|---|---|
| TCR 生命周期 | Applied → Challenged → Accepted/Rejected |
| 双向质押 | 申请者 + 挑战者都需要质押 MIN_DEPOSIT |
| 代币权重投票 | balanceOf(voter) 决定投票权重 |
| 经济裁决 | 胜方获得双方质押,败方损失质押 |
| 超时自动通过 | 无人挑战且超时 → autoAccept 返还质押 |
| 挑战窗口 | challengePeriod 决定公平挑战的时间 |
| 防重投 | hasVoted mapping 确保每个地址只投一次 |