跳到主要内容

05 — 巧妙之处、边界与横向对比

收口章。前四章的细节这里提炼成"可带走的精华",再诚实交代它的边界,最后放进协议生态里对比,并给一张可 grep 的代码地图。

5.1 巧妙之处(值得借鉴的技术)

① 消息层彻底链无关 —— 一个 payload: Record<string, unknown> 逃生舱。 核心结构 PaymentPayload.payload 是个不带类型约束的对象(core/src/types/payments.ts:34)。EVM 往里塞"签名 + EIP-3009 授权",Solana 往里塞"序列化交易",谁都不影响谁。妙在:编排器完全不懂链也能把消息路由到对的 scheme。加一条链 = 写一个新 mechanism,核心代码一行不改。

② "钱货同生共死"靠缓冲响应实现。 verify 与 settle 拆成两步、且 settle 夹在 handler 之后;中间件缓冲 handler 的输出,确认状态 < 400 才结算(http/express/src/index.ts:286:321)。handler 崩了就 cancellationDispatcher.cancel,授权永不上链。这把"先收钱后翻脸"和"先给货后赖账"两个风险一起堵死。

③ "verify 必须预测 settle"是一条铁律。 facilitator 的 verify 不光验签,还 getCode 查资产是合约、eth_call 模拟整笔交易(mechanisms/evm/src/exact/facilitator/eip3009.ts:216:222);对反事实智能钱包,verify 端也提前套用 settle 的工厂白名单(:138-152,注释明说"verify must predict settle")。这样资源服务器看到 isValid:true 就能放心跑业务,几乎不会在 settle 阶段才发现付不了。

④ 多层防重放。 规范 §10.1 列了多层防护,逐条是:EIP-3009 随机 nonce(每笔授权一个唯一的 32 字节 nonce)+ Blockchain Protection(EIP-3009 合约在链上层面拒绝 nonce 复用)+ Time Constraints(validAfter/validBefore 时间窗限制授权寿命)+ Signature Verification(授权由付款人加密签名)。 在 §10.1 之外,参考实现还叠了两道代码层面的额外保护(非 §10.1 原文条目):签名域绑定 chainId+verifyingContract,让一笔授权跨链/跨币即失效(见第 3 章 signEIP3009Authorization);客户端"已尝试过就抛错",避免无限签名重试(http/fetch/src/index.ts:108)。

⑤ extension 的"只增不改"不变式。 客户端回显 extension 只能追加字段、不能删改服务器声明的(validateExtensionscore/src/server/x402ResourceServer.ts:1267);报价里非空的 payTo 在扩展 enrich 时不可变(assertAcceptsAllowlistedAfterExtensionEnrich)。防止扩展把资金改道——这是把"可插拔"和"安全"调和的关键。

5.2 边界与局限(它刻意不做什么)

规范 §文档范围 把一串东西明确划为 out of scope,这不是没做完,是有意为之——保持核心协议小而稳:

它不管为什么 / 谁来管
客户端预算管理是客户端策略,用 x402Clientpolicy 自己加(第 2 章)
会话 / 订阅 / 时限访问应用层在 x402 之上自己搭(micropayment 拼订阅)
关联追踪 / 操作分组实现特定,规范只给 use-case 不给机制
传输细节交给各 transport 规范(HTTP/MCP/A2A 各一份)

几个真实的信任/能力边界:

  • facilitator 是信任集中点。 资源服务器把验签和上链全托付给它。规范的缓解是"trust minimizing"原则——任何 scheme 都不能让 facilitator 把钱转到客户端没签的地方(EIP-3009 的 to 被签名固定、EVM upto 用 Permit2 witness 绑定 to)。所以 facilitator 能"扣你签过的那笔",但不能"把钱转给它自己"。但 facilitator 仍可"不结算/审查"某笔付款——它是可用性上的信任点,不是资金安全上的。
  • 资产受限。 EVM 侧要求代币实现 EIP-3009(USDC 是标杆;exact 方案的 fallback 路径用 Permit2/ERC-20 approve 处理不支持 EIP-3009 的代币,见 mechanisms/evm/src/exact/ 下 permit2/erc20approval)。Solana 侧支持 SPL / Token-2022。
  • 金额是"精确"的硬约束。 exact 方案 verify 第 7 关要求金额一分不差(eip3009.ts:205);要可变金额得换 upto 方案。
  • 代码里看不出的: 各语言端口(Go/Python/Java)的成熟度差异、各 facilitator 服务的实际网络/代币覆盖,得看各自部署,规范层面不保证。

5.3 横向对比(生态里的位置)

x402 常和 MCP、A2A 一起出现,但它们解决的是不同维度的问题。一句话区分:MCP/A2A 负责"传消息、调能力",x402 负责"传钱"——所以它们是叠加而非竞争。

维度x402MCP(见本 shelf mcp-spec/A2A传统支付(Stripe 等)
解决什么按请求付费agent ↔ 工具/资源 的调用协议agent ↔ agent 协作商户收款(卡/钱包)
付款触发HTTP 402 等价信号x402 可作为 MCP 的付款层x402 可作为 A2A 的付款层预先建账号 + 结账流程
账号无需,一次一签必须预先注册
gas/链细节对客户端隐藏(facilitator 承担)不涉及链
结算物链上稳定币/代币(可扩法币)法币

关键互补关系:x402 的 v2 规范专门定义了 MCP 传输specs/transports-v2/mcp.md)和 A2A 传输。在 MCP 里,"需要付款"被表达成一个 isError:true 的工具结果 + PaymentRequired 数据,付款放进 _meta["x402/payment"]——同样三个核心结构,只是换了"信封"。这印证了第 2 章的三层解耦:换传输只动 Representation 层,Types 和 Logic 完全复用

相对传统支付(Stripe),x402 的取舍是:放弃"成熟的法币 + 争议处理 + 商户后台",换来"零账号、机器原生、链无关、按次微支付"。它的目标读者是自主 agent,不是结账的人类购物车。

5.4 代码地图(导航索引)

所有路径相对克隆根 typescript/packages/(合约/规范另注)。符号名优先于行号——行号会漂、符号名能 grep。

主题文件关键符号
核心数据结构core/src/types/payments.tsPaymentRequiredPaymentPayloadPaymentRequirements
三个方案接口core/src/types/mechanisms.tsSchemeNetworkClientSchemeNetworkFacilitatorSchemeNetworkServer
客户端编排器core/src/client/x402Client.tscreatePaymentPayloadselectPaymentRequirementsregisterPolicy
服务器编排器core/src/server/x402ResourceServer.tsverifyPaymentsettlePaymentfindMatchingRequirementsvalidateExtensionsresolveSettlementOverrideAmount
设施方编排器core/src/facilitator/x402Facilitator.tsverifysettlegetSupportedderivePattern
HTTP 报价/付款编码core/src/http/index.tsencodePaymentSignatureHeaderencodePaymentRequiredHeaderencodePaymentResponseHeader
HTTP 资源服务器core/src/http/x402HTTPResourceServer.tsprocessHTTPRequestprocessSettlementextractPaymentisWebBrowser
自动付款 fetchhttp/fetch/src/index.tswrapFetchWithPayment
Express 中间件(缓冲-结算时序)http/express/src/index.tspaymentMiddlewarepaymentMiddlewareFromHTTPServersetSettlementOverrides
exact-EVM 客户端签名mechanisms/evm/src/exact/client/eip3009.tscreateEIP3009PayloadsignEIP3009Authorization
exact-EVM 验证/结算mechanisms/evm/src/exact/facilitator/eip3009.tsverifyEIP3009settleEIP3009
EIP-712 类型常量mechanisms/evm/src/constants.tsauthorizationTypesTransferWithAuthorization
随机 nonce / 链 IDmechanisms/evm/src/utils.tscreateNoncegetEvmChainId
exact-SVM 验证(对比用)mechanisms/svm/src/exact/facilitator/scheme.tsExactSvmSchemeLAYOUT_RECOVERABLE_REASONS
协议规范(权威)specs/x402-specification-v2.md§5 Types、§6 Schemes、§7 Facilitator、§10 Security
方案规范specs/schemes/exact/scheme_exact_evm.mdupto/scheme_upto.md
传输规范specs/transports-v2/http.mdmcp.mda2a.md

给 agent 的跳转建议: 改协议字段 → payments.ts + specs/x402-specification-v2.md。加新链 → 照 mechanisms/evm/src/exact/ 三件套(client/server/facilitator)写一份。调试"付款验过却结算失败" → 看 verifyEIP3009 的 6 道关卡 + settleEIP3009 的 catch 块(它保留原始 revert 文本)。调试"付了钱没拿到货" → 看 Express 中间件的缓冲-回放逻辑(http/express/src/index.ts:286 起)。