← 所有文章
Banking & FinTech / 工程笔记

把券与款放进同一笔交易,会发生什么?

以 TokenRail 的同链 DvP 实验为例,解释双方确认、ERC-20 授权、付款失败时的回滚,以及链上与链下的原子性边界。

这篇工程笔记整理自 TokenRail 的本地合约设计与原子性实验。案例使用模拟存款和合成债券,只讨论单条 EVM 链上的程序行为。

确认条款与授权额度

实验中,买方用 1,000,000 元模拟存款代币购买卖方的 1,000 单位债券。卖方先创建不可修改的指令,买方确认条款后进入 READY。

双方还要分别 approve DvP 合约。ERC-20 allowance 表达支出额度,不包含具体对手方、价格和期限,因此授权不能代替确认。READY 也没有锁定余额;真正执行前,需要重新检查资产、授权、身份与到期时间。

第二条转移失败时

DvP 的 execute 在一笔 EVM 交易内先转债券,再转现金。若现金腿(即资金转移环节)执行失败,且错误向上传播并触发 revert,本次交易中已发生的债券转移、allowance 消耗和指令状态变化都会回滚,失败路径上的事件也不会留下。

检查 READY 与执行条件
    ↓
暂置 SETTLED → 转移债券 → 转移现金
    ↓
全部成功:提交状态与事件
任一失败:回滚本次交易内的业务变更

失败交易仍会产生 receipt、消耗 gas 并推进发送者 nonce。所谓“余额不变”,指的是两种业务代币;不能据此说交易没有发生。

如何验证回滚

只把买方余额设成不足,可能在预检查时就被拒绝,无法证明第一条转移完成后仍能回滚。TokenRail 的测试专门让第二腿(本例中的资金转移)主动失败,并在真实 Anvil 交易后检查失败 receipt、余额、授权额度和 READY 状态。测试替身仅用于验证,不进入实际部署。

链下还有另一条流程

Java 服务随后消费 Transfer 事件并更新持仓投影。这里涉及数据库和链,无法通过一个数据库事务获得同样的原子性:链上已经确认的转移不会因数据库失败自动撤销。

因此提交尝试、链上交割和投影同步分别记录。RPC 超时进入待确认状态,投影按区块重扫并去重;对账固定同一区块水位。这些流程处理恢复与一致性,适用范围与合约内的原子交换不同。

完整本地实现尚未同步到公开仓库;本站项目介绍列出了已验证内容及发布范围。

EXPLORE THE PROJECT

TokenRail

Programmable Settlement Lab

感谢阅读。继续探索笔记