跳至主要内容

公开测试版,运行在 Base Sepolia 测试网。 付款使用没有实际价值的测试 USDC,请勿转入真实资金。担保合约尚未完成外部安全审计,条款仍是待律师审阅的草稿。 测试版意味着什么

OpenVPT

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 的结算单据长这样:

text
Settle(
  bytes32 orderId,     // 哪一笔订单
  uint256 toSeller,    // 给卖家多少
  uint256 toBuyer,     // 退给买家多少
  uint256 toPlatform   // 平台手续费多少
)

另外,每张单据都带有一个「域」(domain):名称 VPTEscrow、版本 1、链 ID(Base 主网为 8453)以及合约地址。这带来三个实际好处:

  1. 看得懂:支持 EIP-712 的钱包会把 toSeller、toBuyer、toPlatform 逐项展示给你。
  2. 不能挪用:因为域绑定了链和合约地址,这个签名拿到别的链或别的合约上都无效。
  3. 不能篡改:金额哪怕差 1 个最小单位,签名就对不上,合约会直接拒绝。

小提示:USDC 有 6 位小数,所以合约里的 1200000000 表示 1,200 USDC。如果钱包显示的是原始整数,记得把小数点往左移 6 位再核对。

合约放款前,究竟检查了什么?

下面是 VPTEscrow.settle() 实际执行的检查,按顺序列出:

  1. 订单存在:这个 orderId 必须确实已付款,否则返回 OrderNotFound。
  2. 只能结算一次:订单如果已经结算,直接拒绝(OrderAlreadySettled)。合约在转账之前就先把订单标记为已结算,并带有防重入保护。
  3. 金额之和必须正好等于托管金额:toSeller + toBuyer + toPlatform == amount,多一分少一分都不行(AmountMismatch)。不存在「余款留在合约里」的情况,也不会凭空多出钱来。
  4. 平台手续费有下限,且按比例计算:toPlatform 必须大于或等于 fee × toSeller ÷ amount(整数除法,向下取整)。意思是:卖家拿到多大比例,平台手续费至少按这个比例收取;全额退款时,手续费下限为 0。
  5. 两个签名都必须有效:签名无法解析就拒绝(InvalidSignature)。
  6. 签名者必须是该订单的三方之一:只接受这笔订单的买家、卖家或当前的 platformSigner,其他任何地址都会被拒绝(UnauthorizedSigner)。
  7. 两个签名者必须不同:同一个人签两次不算数(DuplicateSigner)。

全部检查通过后,合约才会把钱分别转给卖家、买家以及平台的手续费收款地址。任何人都可以把这两份签名提交上链(实际操作中由平台代为提交并支付 gas),因为权限来自签名本身,而不是提交交易的人。

实际算一遍:1,200 USDC 的订单

假设商品售价 1,200 USDC,手续费率为默认的 5%(feeBps = 500):

  • 手续费 fee = 1,200 × 500 ÷ 10,000 = 60 USDC

OpenVPT 的分配公式(splitSettlement)是先算出卖家「毛额」,再从毛额里按比例扣除手续费:

  • 卖家毛额 = 金额 × 判给卖家的比例
  • 平台 = 手续费 × 卖家毛额 ÷ 金额(向下取整)
  • 卖家实收 = 卖家毛额 − 平台
  • 买家退款 = 金额 − 卖家毛额
场景卖家实收买家退款平台手续费合约的手续费下限
正常完成(100% 给卖家)1,14006060 × 1,140 ÷ 1,200 = 57
全额退款(0% 给卖家)01,20000
仲裁判给卖家 30%3428401860 × 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 分钟的有效期。

第二道:延迟生效的取消

如果你在付款前点击「取消」,订单不会立刻变成已取消,而是进入「取消中」状态:

  1. 系统记录取消请求的时间,此后不再签发新的付款签名。
  2. 至少等待 15 分钟再加一段缓冲时间,让你手里可能残留的旧签名全部过期,已发出的交易也有足够时间上链。
  3. 正式取消前,系统会再次检查链上是否已有这笔订单的付款记录。
  4. 如果付款抢先完成,付款优先:订单正常进入「已付款」,取消请求作废。
  5. 万一付款在取消之后才被确认(安全兜底),系统会自动走「仅退款」路径:平台签署全额退款方案,由你共同签名后提交,钱原路退回,平台不收手续费。

交易前后的自查清单

  • 付款前,确认钱包显示的网络是 Base、代币是 USDC、金额与订单一致。
  • 付款前,确认你是在 OpenVPT 官网的订单页面操作,而不是点了聊天里别人发来的链接。
  • 签署 Settle 前,逐项核对 orderId、toSeller、toBuyer、toPlatform(别忘了 6 位小数)。
  • 如果卖家要求你「先在站外付款」或「加个聊天软件私下交易」,请立即停止——站外付款不受合约保护,OpenVPT 的聊天功能也会对分享联系方式的信息给出提醒。
  • 收到商品后在验收期内检查;有问题就在期限内发起争议并保留证据。交付文件会记录 SHA-256 哈希值,有助于在争议时确认实际交付的内容;授权码则加密存储。
  • 确认没问题后再点「确认收货」,因为确认后即放款,无法撤回。

常见问题

平台能冻结我的钱吗? 平台可以暂停新的付款,但无法阻止已经具备两方有效签名的结算;同时,平台也无法单方面把钱转走。不过如前文所说,如果没有两方签名,资金会保持锁定。

被封禁的用户怎么办? 封禁不会取消或改变进行中的订单,定时任务和仲裁都会照常运行。但如果结算需要被封禁用户本人签名(例如退款给他),这笔结算会停留在「结算中」,需由管理员单独处理。

为什么不让平台一个人就能给我退款,这样不是更快吗? 因为「平台一个人就能动钱」恰恰是我们想要消除的风险。要求买家或卖家其中一方也对同一份方案签名,才能确保没人能在你不知情的情况下改变资金去向。

免责声明:本文仅介绍 OpenVPT 托管合约的技术设计,不构成法律、税务或投资建议。区块链交易具有不可逆等风险,请结合自身情况审慎评估。

下一步

延伸阅读