2-of-3 多签如何保护你的钱:OpenVPT 托管合约逐项拆解
买家、卖家、平台三把密钥,任意两方签名才能放款。本文用大白话讲清 EIP-712 签名、合约检查项、每种签名组合,以及平台能做和不能做的事。
- 作者
- OpenVPT 团队
- 发布于
- 阅读
- 14 分钟阅读
- 标签
- 多签
- 托管
- EIP-712
- USDC
- 智能合约
- 资金安全
目录
TL;DR 在 OpenVPT 下单付款后,你的 USDC 不会进入平台账户,而是锁定在 Base 链上的托管合约
VPTEscrow中。要把钱取出来,必须由「买家、卖家、平台」三方中任意两个不同的主体对同一份分配方案签名。平台单独一方永远动不了这笔钱;合约所有者可以暂停新订单、更换平台签名地址、管理可用代币,但没有任何函数能让它结算或提款。代价是:如果没有任何两方愿意签名,资金会一直锁在合约里——下文会如实说明,并介绍改进规划。
先说结论:你的钱在哪里?
很多平台的「担保交易」是把钱转进平台自己的账户,你只能信任平台不挪用、不被黑、不跑路。
OpenVPT 的做法不一样。买家付款时,是用自己的钱包直接调用托管合约的 fund(),把 USDC(6 位小数的美元稳定币)转入合约。从这一刻起:
- 钱在合约里,不在平台的钱包里。
- 合约只有一个出口:
settle()结算函数。 settle()需要两个不同身份的 EIP-712 签名,缺一不可。
也就是说,OpenVPT 在设计上对平台是「非托管」的(non-custodial for the platform):平台没有任何单方面转移资金的途径。
三把密钥:「三方」分别是谁?
每一笔订单在合约里都记录了三个角色的地址:
| 角色 | 地址来源 | 签名代表什么 |
|---|---|---|
| 买家 | 调用 fund() 付款的那个钱包(必须是下单时指定、已通过 SIWE 验证的钱包,因为平台的 CreateOrder 签名绑定了这个地址) | 「我同意这样分配我付的钱」 |
| 卖家 | 卖家在 OpenVPT 通过 SIWE(Sign-In with Ethereum)验证过的钱包 | 「我同意这样分配货款」 |
| 平台 | 合约中设置的 platformSigner 地址 | 「平台按规则(确认收货、超时、仲裁结果)认可这个分配」 |
这里说的「密钥」就是各自钱包的私钥。买家和卖家的私钥在自己手里,OpenVPT 看不到也拿不到。
补充两点背景:
- 卖家门槛:在 OpenVPT 上架销售,需要完成 KYC(状态为 VERIFIED),并通过 SIWE 证明自己控制收款钱包。这样能确保合约里的「卖家地址」确实属于这位卖家。
- 下单时就绑定:买家付款时,平台会用自己的密钥签发一份
CreateOrder,把订单编号、买家、卖家、代币、金额、手续费和过期时间全部绑定在一起。合约会校验这份签名,所以没人能在付款环节偷偷篡改卖家地址或手续费。
EIP-712 是什么?大白话版
你可能在钱包里见过「签名请求」:有的是一串看不懂的十六进制乱码,有的则清楚列出每个字段和数值。后者就是 EIP-712 类型化结构数据签名(typed structured data signing)。
通俗地说,EIP-712 让你签的不是「一段神秘数据」,而是一张有固定格式的单据。OpenVPT 的结算单据长这样:
Settle(
bytes32 orderId, // 哪一笔订单
uint256 toSeller, // 给卖家多少
uint256 toBuyer, // 退给买家多少
uint256 toPlatform // 平台手续费多少
)另外,每张单据都带有一个「域」(domain):名称 VPTEscrow、版本 1、链 ID(Base 主网为 8453)以及合约地址。这带来三个实际好处:
- 看得懂:支持 EIP-712 的钱包会把
toSeller、toBuyer、toPlatform逐项展示给你。 - 不能挪用:因为域绑定了链和合约地址,这个签名拿到别的链或别的合约上都无效。
- 不能篡改:金额哪怕差 1 个最小单位,签名就对不上,合约会直接拒绝。
小提示:USDC 有 6 位小数,所以合约里的
1200000000表示 1,200 USDC。如果钱包显示的是原始整数,记得把小数点往左移 6 位再核对。
合约放款前,究竟检查了什么?
下面是 VPTEscrow.settle() 实际执行的检查,按顺序列出:
- 订单存在:这个
orderId必须确实已付款,否则返回OrderNotFound。 - 只能结算一次:订单如果已经结算,直接拒绝(
OrderAlreadySettled)。合约在转账之前就先把订单标记为已结算,并带有防重入保护。 - 金额之和必须正好等于托管金额:
toSeller + toBuyer + toPlatform == amount,多一分少一分都不行(AmountMismatch)。不存在「余款留在合约里」的情况,也不会凭空多出钱来。 - 平台手续费有下限,且按比例计算:
toPlatform必须大于或等于fee × toSeller ÷ amount(整数除法,向下取整)。意思是:卖家拿到多大比例,平台手续费至少按这个比例收取;全额退款时,手续费下限为 0。 - 两个签名都必须有效:签名无法解析就拒绝(
InvalidSignature)。 - 签名者必须是该订单的三方之一:只接受这笔订单的买家、卖家或当前的
platformSigner,其他任何地址都会被拒绝(UnauthorizedSigner)。 - 两个签名者必须不同:同一个人签两次不算数(
DuplicateSigner)。
全部检查通过后,合约才会把钱分别转给卖家、买家以及平台的手续费收款地址。任何人都可以把这两份签名提交上链(实际操作中由平台代为提交并支付 gas),因为权限来自签名本身,而不是提交交易的人。
实际算一遍:1,200 USDC 的订单
假设商品售价 1,200 USDC,手续费率为默认的 5%(feeBps = 500):
- 手续费
fee = 1,200 × 500 ÷ 10,000 = 60 USDC
OpenVPT 的分配公式(splitSettlement)是先算出卖家「毛额」,再从毛额里按比例扣除手续费:
- 卖家毛额 = 金额 × 判给卖家的比例
- 平台 = 手续费 × 卖家毛额 ÷ 金额(向下取整)
- 卖家实收 = 卖家毛额 − 平台
- 买家退款 = 金额 − 卖家毛额
| 场景 | 卖家实收 | 买家退款 | 平台手续费 | 合约的手续费下限 |
|---|---|---|---|---|
| 正常完成(100% 给卖家) | 1,140 | 0 | 60 | 60 × 1,140 ÷ 1,200 = 57 |
| 全额退款(0% 给卖家) | 0 | 1,200 | 0 | 0 |
| 仲裁判给卖家 30% | 342 | 840 | 18 | 60 × 342 ÷ 1,200 = 17.1 |
30% 的计算过程:卖家毛额 = 1,200 × 30% = 360;平台 = 60 × 360 ÷ 1,200 = 18;卖家实收 = 360 − 18 = 342;买家退款 = 1,200 − 360 = 840。三者相加 342 + 840 + 18 = 1,200,正好等于托管金额。平台拿 18,高于合约要求的下限 17.1,因此能通过校验。
关键在于:平台手续费只跟随卖家实际拿到的那部分。全额退款时,平台一分钱都不收。
每种签名组合分别在什么时候用?
三方取二,一共三种组合。它们在 OpenVPT 流程中的实际用途如下:
| 签名组合 | 典型场景 | 谁先签 | 结果 |
|---|---|---|---|
| 买家 + 平台 | 买家点击「确认收货」 | 平台自动签,买家在钱包中签名 | 放款给卖家(扣除手续费) |
| 买家 + 平台 | 卖家超过交付期限仍未交付 | 平台签退款方案,买家签名后提交 | 全额退还买家 |
| 卖家 + 平台 | 验收期(默认交付后 3 天)届满,买家既未确认也未发起争议 | 平台签,卖家签名后提交 | 放款给卖家(扣除手续费) |
| 平台 + 买家或卖家 | 争议经仲裁裁决(例如 30/70) | 仲裁员裁决后平台签,再由买家或卖家其中一方共同签名 | 按裁决比例分配 |
| 买家 + 卖家 | 双方直接就同一方案达成一致 | 双方各自签名 | 按双方签署的方案分配,平台签名并非必需 |
几个值得说明的细节:
- 确认收货:买家确认时,平台会自动签署同一份放款方案,所以买家的那一个签名就凑齐了 2-of-3,平台随即代为提交交易。此时卖家无需再签。
- 超时退款与超时放款:这两种情况都由系统定时任务触发,平台先签,另一个签名通常由「会收到钱的那一方」补上——退款由买家签,放款由卖家签,因为收钱的人最有动力完成签名。从技术上讲,买家或卖家任意一方对同一方案的有效签名都能凑齐两票。
- 仲裁:买家可在验收期内发起争议,由指派的仲裁员审阅双方证据,以「给卖家多大比例」的形式作出裁决。平台按裁决签名,再由买家或卖家其中一方(通常是获得款项的一方)共同签名后提交。目前没有上诉机制,裁决即为最终方案。
- 平台只签一次:由于
Settle签名本身没有过期时间、也无法撤销,OpenVPT 目前的策略是每笔订单平台最多只签一份结算方案。如果之后有人要求平台再签另一个不同的方案,系统会拒绝并写入审计记录,转为人工处理。这就避免了「两份不同方案都带有平台签名」的风险。
平台能做什么?不能做什么?
VPTEscrow 合约有一个「所有者」(owner),也就是运营方的管理地址。它的权限清单很短,而且全部写在合约里,任何人都可以在链上核实:
| 所有者可以 | 所有者不可以 |
|---|---|
暂停和恢复新的 fund() 付款 | 调用 settle() 为任何订单结算 |
更换平台签名地址 platformSigner(如定期轮换) | 从合约提款或转走任何托管资金 |
| 设置可用代币白名单 | 修改已付款订单的买家、卖家、金额或手续费 |
| 更换手续费收款地址 | 放弃所有权(renounceOwnership 被刻意禁用,防止暂停和密钥轮换功能永久失效) |
特别注意:「暂停」只影响新的付款,settle() 不受暂停影响。也就是说,即使平台暂停了合约,已经在托管中的订单依然可以凭两方签名正常结算。
所有权转移采用两步流程(Ownable2Step):新所有者必须主动接受,降低因地址输错而丢失管理权的风险。
实话实说:2-of-3 防不住什么
多签能大幅降低风险,但并非万能。以下限制我们认为你应该了解:
- 两方串通:2-of-3 的前提是三方中至少有两方是诚实的。如果任意两方联手,就能签出任何金额加总正确的方案。平台侧通过「只签一次」、仲裁流程和审计记录来降低这类风险,但合约本身无法判断谁在撒谎。
- 你签了什么,就是什么:签名一旦发出就无法撤回。务必在钱包界面上核对订单编号和三个金额,不要在来路不明的网站或聊天中别人发来的链接上签名。
- 平台密钥安全:平台签名密钥一旦泄露,攻击者相当于拿到了「平台」这一票,但仍然需要买家或卖家其中一方的签名才能动用资金。所有者也可以立即轮换
platformSigner。 - 合约审计:上线前的第三方合约审计目前处于计划中,完成之前请根据自身的风险承受能力决定交易金额。
如果平台没了,我的钱怎么办?
按目前的设计,托管中的资金会一直留在合约里,直到两个不同的当事方对同一份方案签名为止。
这意味着:
- 如果买家和卖家能达成一致,双方可以绕过平台,自行对同一份
Settle方案签名,再由任何人把交易提交上链。合约只认签名,不看提交者。不过这需要技术能力(自行生成 EIP-712 签名、自行支付 gas),目前 OpenVPT 没有提供「平台停止运营时」的专用界面。 - 如果买家和卖家谈不拢,平台又无法签名,合约里没有「超时自动退款」或「单方提款」的机制,资金会保持锁定状态。
- 任何人(包括平台)都无法把钱挪作他用,因为没有任何函数能绕过两方签名。
我们选择如实说明。改善这一场景(例如为结算签名加入有效期、提供不依赖平台的退出路径)已列入后续合约版本的规划,目前属于计划中,尚未实现。在此之前,建议你把单笔交易金额控制在自己能承受的范围内。
付款环节的两道保险
多签保护的是「钱进入合约之后」。而在「钱还没进合约」的那一刻,也存在一个容易被忽视的风险:你点了取消,但付款交易其实已经发出、还在排队等待上链。OpenVPT 为此设计了两道保险。
第一道:短时效的 CreateOrder 签名
每次付款都需要平台签发的 CreateOrder 签名,其过期时间取「付款期限(下单后 24 小时)」与「当前时间起 15 分钟」中较早的那个。合约会拒绝已过期的签名。付款页面每次读取订单时都会重新签发一份新的,所以正常操作不受影响;但任何一张旧签名最多只有 15 分钟的有效期。
第二道:延迟生效的取消
如果你在付款前点击「取消」,订单不会立刻变成已取消,而是进入「取消中」状态:
- 系统记录取消请求的时间,此后不再签发新的付款签名。
- 至少等待 15 分钟再加一段缓冲时间,让你手里可能残留的旧签名全部过期,已发出的交易也有足够时间上链。
- 正式取消前,系统会再次检查链上是否已有这笔订单的付款记录。
- 如果付款抢先完成,付款优先:订单正常进入「已付款」,取消请求作废。
- 万一付款在取消之后才被确认(安全兜底),系统会自动走「仅退款」路径:平台签署全额退款方案,由你共同签名后提交,钱原路退回,平台不收手续费。
交易前后的自查清单
- 付款前,确认钱包显示的网络是 Base、代币是 USDC、金额与订单一致。
- 付款前,确认你是在 OpenVPT 官网的订单页面操作,而不是点了聊天里别人发来的链接。
- 签署
Settle前,逐项核对orderId、toSeller、toBuyer、toPlatform(别忘了 6 位小数)。 - 如果卖家要求你「先在站外付款」或「加个聊天软件私下交易」,请立即停止——站外付款不受合约保护,OpenVPT 的聊天功能也会对分享联系方式的信息给出提醒。
- 收到商品后在验收期内检查;有问题就在期限内发起争议并保留证据。交付文件会记录 SHA-256 哈希值,有助于在争议时确认实际交付的内容;授权码则加密存储。
- 确认没问题后再点「确认收货」,因为确认后即放款,无法撤回。
常见问题
平台能冻结我的钱吗? 平台可以暂停新的付款,但无法阻止已经具备两方有效签名的结算;同时,平台也无法单方面把钱转走。不过如前文所说,如果没有两方签名,资金会保持锁定。
被封禁的用户怎么办? 封禁不会取消或改变进行中的订单,定时任务和仲裁都会照常运行。但如果结算需要被封禁用户本人签名(例如退款给他),这笔结算会停留在「结算中」,需由管理员单独处理。
为什么不让平台一个人就能给我退款,这样不是更快吗? 因为「平台一个人就能动钱」恰恰是我们想要消除的风险。要求买家或卖家其中一方也对同一份方案签名,才能确保没人能在你不知情的情况下改变资金去向。
免责声明:本文仅介绍 OpenVPT 托管合约的技术设计,不构成法律、税务或投资建议。区块链交易具有不可逆等风险,请结合自身情况审慎评估。
下一步
- 延伸阅读:争议与仲裁:OpenVPT 如何处理交易纠纷
- 延伸阅读:为什么 OpenVPT 用 Base 上的 USDC 结算
- 了解完整交易流程:运作方式
- 查看手续费说明:收费说明
- 开始浏览商品:商品列表
- 还有疑问?请查看帮助中心或联系我们