Skip to content

Escrow ​

托管层(L2)负责:钱在什么状态、什么条件下释放、按什么比例分。当前只维护状态与结算指令,不转移真实资金。


职责 ​

负责不负责
托管状态机真实资金冻结 / 划转
金额守恒等 6 条不变量决定赔付比例(商务 / 法务)
结算指令(EscrowSettlement)汇率换算
赔付策略接线争议受理(fulfillment)
事实写入状态层对外写端点

数据模型 ​

集合:escrows

字段说明
taskId一单一托管
amount金额(整数最小单位)
currency币种(只记录,不换算)
statuspending / held / released / refunded / split
events仅追加时间线
settlementEscrowSettlement

EscrowSettlement ​

json
{
  "outcome": "split",
  "toAgent": 70000,
  "toBuyer": 30000,
  "toPlatform": 0,
  "currency": "CNY",
  "reason": "missing_items → 合同 §5.2 → 30%"
}

状态机 ​

pending ──fund──▶ held ──┬── release ──▶ released
                         ├── refund  ──▶ refunded
                         └── split   ──▶ split

六条不变量 ​

不变量校验
一单一托管taskId 唯一
只有 held 能结算状态前置检查
金额守恒toAgent + toBuyer + toPlatform = amount
时间线只追加events 无覆写
终态不可再迁移终态直接拒绝
actor 可定责每次变更记录责任方

为什么金额用整数 ​

js
899.99 + 100 !== 999.99   // true

浮点误差会让金额守恒失效,因此所有金额以"分"为单位,open() 强校验整数。


策略分工 ​

组件回答可替换
EscrowSettlementPolicy怎么分✅ 纯函数
CompensationPolicy赔多少✅ 纯函数
SettlementCoordinator把裁定接到结算✅ 独立服务
策略设置费率 / 上限 / SLA / 担保范围✅ 在线修改

CompensationPolicy 的输出必须带依据:

json
{
  "amount": 30000,
  "reason": "争议事由 missing_items → 条款 §5.2 → 比例 30%"
}

没有对应条款且裁定未给金额时返回 409,不猜比例。


与状态层 ​

托管事实写入 /tasks/{taskId}/escrow:

  • 强制写入,失败即抛错
  • 与 Mongo 写入同一事务
  • actor 区分买家托管 / 平台结算

将来接入资金体系时,只需消费 EscrowSettlement,状态机与痕迹不用改。


结算与分录 ​

结算成功后自动派生分录(挂在 settle() 这个唯一出口,而不是协调器):

借 escrow_held        amount
贷 payable_supplier   toAgent
贷 refundable_buyer   toBuyer
贷 payable_platform   toPlatform
  • 零金额行不输出
  • 金额守恒由结算层保证,所以分录借贷平衡是结构保证
  • 记账失败不回滚结算(补偿是重放分录,不是重放结算)

详见 Accounting 期间与账务。


参考案例 ​

bash
npm run case:reference              # dry-run
npm run case:reference -- --commit  # 写入

两条路径:

路径结果
releasedtoAgent 100000 / toBuyer 0
splittoAgent 70000 / toBuyer 30000

边界与限制 ​

限制说明
不动真钱只产出划转指令
单币种不换算
无部分释放一次结算完成
无退款重试失败需人工处理
赔付比例是假设缺件 30% / 质量不符 50% / 逾期 10%
无对外端点只读视图 + 策略设置

测试 ​

bash
npx jest libs/modules/src/escrow
npx jest --config ./apps/hushwork/test/jest-e2e.json --runInBand \
  --testPathPatterns="escrow"

源码位置 ​

libs/modules/src/escrow/
├── schemas/escrow.schema.ts
└── services/
    ├── escrow.service.ts
    ├── escrow-state.service.ts
    ├── escrow-settlement.policy.ts
    ├── compensation.policy.ts
    └── settlement.coordinator.ts

相关页面 ​

Released under the MIT License.