返回博客
WEB3 · ·9 min

非托管 escrow 作为 marketplace 原语:TaskMarket 设计笔记

Base 链上一个 4 状态 Solidity 合约,arbiter 二元调用,没有第三个目的地址。TaskMarket 如何用 USDC 结算却从不持有用户资金,以及每个不变式都防住了什么。

  • #solidity
  • #web3
  • #marketplace
  • #escrow
  • #base

大部分「校园任务」app 处理钱的方式正是金钱处理失败的地方:用户主页贴 Venmo / e-Transfer 号,DM 里谈备注,出问题走五页 support 流程。机制不可执行,平台的角色是品牌和发现,不是结算。

scope TaskMarket 时,问题不是「要不要加 escrow」,而是「如果结算没法强制执行,我们算 marketplace 吗」。答案是不算。所以设计目标翻转:写一个最小的链上代码片段,可以为一个 task 持有 USDC 押金、在结算时把钱精确路由给两方之一 —— 然后让其他所有东西(UI、搜索、聊天、评分)围绕这个核心运转。

TaskEscrow.sol 暴露的状态机只有 4 个状态:None / Funded / Released / Refunded。task 用 bytes32 taskId 标识。没有升级路径、没有 proxy、没有 admin slot、没有 selfdestruct。

关键 invariants:

  • 费率有常量上限 FEE_BPS_MAX = 2000 (20%),cap 本身没有 setter
  • 每个 taskId 一次性 —— 重复 deposit 直接 revert
  • self-deal 禁止 —— payer == payee 时 revert
  • Released / Refunded 终态 —— 不可重置
  • arbiter 没有 token allowance —— 合约持仓,arbiter key 只能触发状态转移

最关键的函数签名是 resolveByOwner(bytes32 taskId, bool favorPayee)。二元布尔,不是地址 + 金额。这把整个诈骗面收掉了:即使 arbiter key 被攻破,最糟也只是错误分配两个已存在方之间的押金,没法把钱提到第三方地址。

完整说明 + 「为什么这样设计」+「故意不做什么」见 英文版

相关