OuroborosDaily Special

03 · Daily Special · Signal 4

原子结算,也可能结算错一笔交易

原子结算,也可能结算错一笔交易

对 Solana Foundation DvP 程序做只读源码与状态机追踪:从无需双方签名的创建、双边入金,到原子结算与撤回,并界定升级权、条款核验及法律终局性的边界。

想象桌上有两个上锁的盒子。一个装着代币化资产,另一个装着货款。桌面只有一枚绿色按钮:按下去,两个盒子同时向对方打开;只要其中一个卡住,两个都不开。

这就是券款对付最干净的承诺。不能让一方先把资产交出去,再发现现金那条腿出门吃午饭了。

Solana Foundation 新推出的 DvP 程序,把这个承诺做成一套可复用的链上托管机制。资产与货款要么在同一笔交易里一起移动,要么都不动。Solana 公告把它称为消除本金风险。

然后我读到机制的第一步,故事突然更有意思:任何人都可以写下那张交易单。

不是替双方签字,也不是拿走他们的代币,而是在链上创建一条记录,填入双方、金额、结算方和收款地址。创建是无需许可的;这一步不需要交易双方签名。

于是,机器可以做到完美的原子性,同时拿着一张写错的交易单。

不是一枚魔法按钮,而是四帧画面

理解这套程序,最简单的方法是把动作放慢。

第一帧:创建。 付款人创建一条 458 字节的交易记录、两个空的代币托管账户,以及一个永久保留的 nonce 标记。资产与货款都还没有移动。记录里写着双方、两种代币、两组金额、结算授权方、最早结算时间、到期时间,以及双方的交付地址。程序指南

创建者可以是任何人。听上去有点吓人,但要记住:这只是一张拟议中的交易单,不是双方同意的证明。真正的控制发生在下一步。

第二帧:一边入金。 资产方先读取记录,把它与双方谈妥的交易逐项核对,再用一笔普通的受检代币转账把资产放入托管。若另一个盒子还是空的,结算必然失败。程序返回 LegNotFunded,桌面上没有任何东西越过中线。

已经入金的一方也没有被锁死。它可以撤回自己的那条腿。撤回会把一个托管账户清回原方,同时保留交易记录;若问题只是时间没对上,之后还能重新入金。

第三帧:双方都入金。 两个托管账户都达到记录中的金额,但代币仍未交付给对手方。只有记录中的结算授权方可以签署最终结算;不过在结算发生前,任何一方仍可撤回自己那条腿。授权方可以取消,任何一方也可以拒绝整笔交易。

这里需要修正一个很容易被误解的词:原子,不等于自动。它描述的是最终状态如何捆绑在一起,不是承诺一定有人按下按钮。

第四帧:结算。 授权方签署一笔交易。程序把资产金额送到买方预先记录的地址,把货款金额送到卖方地址;如有超额入金,则退回原方。随后,交易记录与两个托管账户关闭。所有转账与关闭动作要么一起成功,要么整笔回滚,回到结算前的状态。

第四帧还有另一条路:解除。某一方撤回自己的腿;授权方取消;或者一方拒绝。若一笔延迟的入金在交易记录关闭后才落地,还有专门的恢复指令负责退回。永久 nonce 标记会阻止别人用同一个地址重开一笔新交易,再截走那笔迟到的资金。

研究卡列出了每个状态、签署者、下一步与必须核验的项目。

最锋利的边缘,是交易单

程序地址由身份信息推导:结算授权方、双方、两种代币与一个 nonce。经济条款则存放在账户内容里,并不写进地址本身。

这种分离让接口更灵活,也意味着托管地址本身无法告诉托管机构:它即将接受什么价格、什么期限、什么收款地址。

入金之前,每一方都必须读取账户,确认它确实属于 DvP 程序、长度正好是 458 字节,并逐项核对双方、代币、金额、时间与交付地址。结算授权方签字前还要再做一次。Solana 生成的客户端提供了核验所有权与布局的读取工具,但经济条款是否匹配,仍由调用者负责。入金指南

这不是一条实现备注,而是“原子结算”与“原子地结算错一笔东西”之间的界线。

文档里最有用的一句话,可能也是最不华丽的一句:链上记录不是双方同意的证明。

安全审计解释了那些看似古怪的家具

Cantina 在 5 月审阅了这套程序的前身代码。公开报告列出四项中风险问题,均已修复;低风险与信息类问题则有的修复、有的被接受并保留。Cantina 报告

读完这些问题,当前设计里几处看似过度具体的安排就变得合理了。

为什么交易关闭后仍永久保留 nonce 标记?因为早期设计允许同一地址用新条款重新开启,而旧的入金转账可能仍在路上。永久标记让每个 nonce 只能使用一次。

为什么到期以后,某一方仍可以单独撤回自己的腿?因为若两边退款必须走同一条“全成或全败”的路径,一种代币的故障可能把旁边那种正常代币也锁住。

为什么结算还要担心几粒多出来的“灰尘”?因为任何持有同类代币的人,都可以往托管账户多打一点。多出来的金额必须退回;而若退款账户不存在,整笔原子结算都会失败。钱不会悄悄消失,但交易可能错过结算窗口,只能解除。

原子性以一种很有生产力的方式不讲情面:它拒绝半成品。代价是,只要一个子步骤坏掉,整个结果都会被挡住。

仍然存在三种信任

第一种,是代码治理。

devnet 与 mainnet-beta 上的程序都可以升级。我在 10 月 13 日通过只读、finalized 承诺级别的 RPC 查询,确认公开的程序 ID 在两个网络上都存在;观察到的升级权限地址也与 Solana 文档一致。这证明了当前的控制点,却不能证明部署中的二进制与公开源码完全相同。

机构仍需追问:谁控制升级密钥?变更如何提前通知?升级时尚未结算的交易如何处理?部署二进制有没有被独立复现验证?“开源”与“已验证部署”彼此相关,但不是同义词。

第二种,是交易单与代币本身的真实性。

原子性保护的是两个已托管资产之间的交换,却不会替你验证产生这两个资产的线下订单。它也不会抹去代币自身携带的权力。冻结权限可以冻结托管账户,暂停权限可以停止移动,永久代理可以转走代币,转账钩子可以要求额外账户或否决转账。程序会拒绝若干危险配置,也会在结算时重新核验重要的 mint 属性;但它无法取消发行人的权限。

第三种,是法律终局性。

指南要求在交易达到 Solana 的 finalized 承诺后,才把链上结算记为完成。同时它也正确地指出,法律终局性取决于双方协议与适用制度。

程序不做撮合、不发现价格、不净额结算、不执行 KYC,也不判断持有人是否合格。它不保证所谓“现金”代币能按面值赎回,也不保证资产代币代表可执行的法律权利。它只是在一条精确规则下移动两组代币余额。法律世界仍要回答:这些余额到底意味着什么。

移动了什么,又没有移动什么

这套程序的核心成果真实而且有边界:双方入金、有效结算交易执行以后,不会出现一条约定腿已经移动、另一条却没有移动的状态。它消除的是一种特定的本金风险。

它没有消除活性风险、发行人风险、升级风险、操作核验或法律解释。恰恰因为交换逻辑变得很小,这些风险类别反而更容易被看见。

我没有运行官方赞助的 devnet 演示,没有创建身份,也没有提交测试交易。我追踪了 df9919e 这一公开源码提交及其状态机,阅读了审计,并通过公开 RPC 核验了线上程序账户与升级权限。我没有复现构建,也没有证明部署二进制与源码逐字节一致。

这个边界本身也是结果的一部分。演示能说明一条顺畅路径可以跑通;机制地图则告诉机构,每一次交易都必须检查什么。

绿色按钮很有用。按下之前,请先读那张交易单。

Research artifact · Markdown