2026/9/17 10:02:51

x402 upto EVM 方案:基于 Permit2 Witness 模式的“授权上限、按实结算“支付协议实现

x402 upto EVM 方案:基于 Permit2 Witness 模式的“授权上限、按实结算“支付协议实现 x402 upto EVM 方案基于 Permit2 Witness 模式的授权上限、按实结算支付协议实现【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402本文以 x402 规范文档 scheme_upto_evm.md 为主体完整讲解upto方案在 EVM 链上的设计客户端签名授权一个最大金额资源服务器在实际使用量产生后按真实用量可以低到 0向 Facilitator 发起结算。读完本文你可以理解permitWitnessTransferFrom Witness 模式如何做到金额可变、收款方与 Facilitator 不可篡改、一次性防重放并能对照 x402UptoPermit2Proxy 合约 与 Go SDK 的 upto 机制实现 完成服务端、客户端、Facilitator 三端的接入。1. 核心概念授权一个上限结算一个实际值upto方案面向成本事先不可知的资源LLM token 生成、按字节计费的带宽传输、动态算力等。其核心语义定义于 scheme_upto.md客户端在支付签名时授权一个最大金额permit2Authorization.permitted.amount服务器在请求处理完毕后依据实际资源消耗生成的 token 数、传输的字节数、耗时等决定最终扣款结算金额MUST ≤ 授权上限MAY 0无用量则不收费授权自然过期不产生任何链上交易。upto还强制以下核心属性适用于所有网络实现EVM 以 Permit2 机制落地属性语义EVM 实现方式Single-Use Authorization每个授权最多结算一次结算后即消耗Permit2 的nonce机制保证不可重用Time-Bound Authorization授权有显式生效窗口deadline过期时间 witnessvalidAfter生效时间Recipient Binding资金去向被密码学绑定Facilitator 无法转走Permit2 witness 中的witness.to字段Maximum Amount Enforcement结算额 ≤ 授权上限可为 0x402UptoPermit2Proxy合约settle()入参amount permit.permitted.amount明确不支持的模式需换用其他方案多结算/流式分块结算、周期性自动扣款、无时间边界与单次限制的无限授权。2. 为什么只有 Permit2没有 EIP-3009AssetTransferMethod用例说明Permit2所有 ERC-20 代币客户端签上限、服务器结算实际值使用现有x402Permit2Proxy合约族规范明确指出EIP-3009transferWithAuthorization在upto方案中不受支持因为它在签名时要求锁定精确金额与结算时才确定金额的语义天然冲突。Permit2 的permitWitnessTransferFrom允许 spender 在结算时传入一个不超过授权上限的requestedAmount且通过 witness 数据把收款地址与可调用者绑定正好满足upto的两个约束金额可变、去向与执行者不可篡改。合约层证据见 x402BasePermit2Proxy.sol所有结算最终都汇聚到内部函数_settle其中SignatureTransferDetails{to, requestedAmount}的requestedAmount即结算时的实际金额ISignatureTransfer.SignatureTransferDetails memory transferDetails ISignatureTransfer.SignatureTransferDetails({to: to, requestedAmount: settlementAmount}); PERMIT2.permitWitnessTransferFrom(permit, transferDetails, owner, witnessHash, witnessTypeString, signature);同时_settle在链上前置校验了settlementAmount 0InvalidAmount、validAfter未到PaymentTooEarly、to/owner为零地址等。3. 四阶段完整流程3.1 Phase 1一次性 Gas 授权Permit2 ApprovalPermit2 要求用户先批准 Permit2 合约 可以花费其代币这是一次性设置。规范支持三种方式Option A用户直接 approve标准路径。用户提交一笔标准approve(Permit2)链上交易自己支付 gas。前提用户持有原生 Gas 币。Option BERC20 授权代付 gas扩展erc20ApprovalGasSponsoring。Facilitator 代付 approve 交易的 gas。前提是服务器支持该扩展。流程Facilitator 批量执行from.transfer(gas_amount)-ERC20.approve(Permit2)-settle。Option CEIP-2612 Permit扩展eip2612GasSponsoring。若代币支持 EIP-2612用户直接签名一个 permit 授权 Permit2全程零 gas。流程Facilitator 调用x402Permit2Proxy.settleWithPermit()。在 Go SDK 的 Facilitator 结算代码 中可以清晰看到三条分支的对应关系eip2612Info ! nil时调用settleWithPermiterc20Info ! nil时通过扩展签名者批量发送已签名的 approve 交易 settle 调用否则走标准settle。3.2 Phase 2PAYMENT-SIGNATURE头载荷客户端返回的payload必须包含signaturepermitWitnessTransferFrom的 EIP-712 签名permit2Authorization用于重构待签消息的完整参数。关键逻辑permit2Authorization.permitted.amount是客户端愿意支付的最大金额实际扣款在结算时确定且 ≤ 该上限。CREATE2 地址要求x402Permit2Proxy合约必须通过CREATE2部署到所有支持的 EVM 链上的相同地址保证跨链行为一致、集成简单。Facilitator 地址发现Facilitator 通过/supported端点在每个受支持 scheme 的extra字段中宣告自身地址客户端必须把该facilitatorAddress写进permit2Authorization.witness.facilitator。这使授权绑定到特定 Facilitator防止其他方越权结算。Go SDK 中这一要求是硬性的CreateUptoPermit2Payload 会在requirements.Extra[facilitatorAddress]缺失时直接报错upto scheme requires facilitatorAddress in paymentRequirements.extra而 Facilitator 端由 GetExtra() 从签名地址集合中给出该值。规范给出的PaymentRequired402 响应示例{ x402Version: 2, error: PAYMENT-SIGNATURE header is required, resource: { url: https://api.example.com/llm/generate, description: LLM text generation endpoint, mimeType: application/json }, accepts: [ { scheme: upto, network: eip155:84532, amount: 5000000, asset: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, payTo: 0x209693Bc6afc0C5328bA36FaF03C514EF312287C, maxTimeoutSeconds: 300, extra: { name: USDC, version: 2, facilitatorAddress: 0xFacilitatorAddress1234567890123456789012 } } ] }对应的PaymentPayload客户端请求示例{ x402Version: 2, resource: { url: https://api.example.com/llm/generate, description: LLM text generation endpoint, mimeType: application/json }, accepted: { scheme: upto, network: eip155:84532, amount: 5000000, asset: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, payTo: 0x209693Bc6afc0C5328bA36FaF03C514EF312287C, maxTimeoutSeconds: 300, extra: { name: USDC, version: 2 } }, payload: { signature: 0x2d6a7588d6acca505cbf0d9a4a227e0c52c6c34008c8e8986a1283259764173608a2ce6496642e377d6da8dbbf5836e9bd15092f9ecab05ded3d6293af148b571c, permit2Authorization: { permitted: { token: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, amount: 5000000 }, from: 0x857b06519E91e3A54538791bDbb0E22373e36b66, spender: 0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002, nonce: 0xf3746613c2d920b5fdabc0856f2aeb2d4f88ee6037b8cc5d04a71a4462f13480, deadline: 1740672154, witness: { to: 0x209693Bc6afc0C5328bA36FaF03C514EF312287C, facilitator: 0xFacilitatorAddress1234567890123456789012, validAfter: 1740672089 } } } }注意spender正是x402UptoPermit2Proxy的固定地址0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002见 constants.go而witness.facilitator与 402 响应extra.facilitatorAddress一致——这就是授权绑定 Facilitator在报文层面的体现。从 Go 客户端签名代码 signUptoPermit2Authorization 可以看到 EIP-712 域与消息结构域为name: Permit2、chainId、verifyingContract: 规范 Permit2 地址0x000000000022D473030F116dDEE9F6B43aC78BA3类型名为PermitWitnessTransferFrom消息体为permitted / spender / nonce / deadline / witness其中validAfter取当前时间前 600 秒、deadline取当前时间加maxTimeoutSeconds。3.3 Phase 3验证逻辑按序执行验证器必须按以下顺序执行检查验签payload.signature有效且可恢复为permit2Authorization.from。注意extra字段需转换为 ABI 编码版本参与哈希。Permit2 授权检查若ERC20.allowance(from, Permit2_Address) amount先检查是否走了Sponsored ERC20 Approval扩展再检查是否走了EIP2612 Permit扩展两者皆无返回412 Precondition Failed错误码PERMIT2_ALLOWANCE_REQUIRED提示客户端先完成一次性 Direct Approval 再重试。余额检查client的asset余额足以覆盖amount。金额一致性permit2Authorization.permitted.amount必须等于 requirements 中的amount。时间窗口deadline未过期且witness.validAfter已生效。代币与网络与 requirements 匹配。模拟Simulation标准路径用**全额amount最坏情况**模拟x402Permit2Proxy.settle带 ERC20 授权代付扩展模拟transfer - approve - settle批量交易带 EIP-2612 扩展模拟x402Permit2Proxy.settleWithPermit。Go SDK 的 VerifyUptoPermit2 完整实现了上述顺序scheme/network 校验 →spender必须等于 upto 代理地址 →witness.to必须等于payTo→witness.facilitator 必须属于本 Facilitator 的签名地址集合ErrUptoFacilitatorMismatch→deadline校验附加 6 秒缓冲见Permit2DeadlineBuffer 6→validAfter已生效 →permitted.amount requirements.Amount→token匹配 → EIP-712 验签EOA 直接 recover合约地址走通用签名验证→ 最后按扩展分支执行对应模拟。模拟失败时由DiagnoseUptoPermit2SimulationFailure给出可定位的失败原因。3.4 Phase 4结算逻辑结算由 Facilitator 以实际金额调用x402UptoPermit2Proxy完成实际金额由资源服务器依据请求期间的资源消耗token 数、字节数、耗时决定。结算金额规则结算amountMUST ≤授权上限结算amountMAY 0无用量不扣费结算金额由资源服务器决定而非客户端。结算流程标准结算调用x402Permit2Proxy.settle(permit, actualAmount, owner, witness, signature)其中actualAmount permit.permitted.amount。Sponsored ERC20 Approval扩展Facilitator 构造批量交易将代付的ERC20.approve调用严格排在settle之前执行。EIP-2612 Permit扩展调用x402Permit2Proxy.settleWithPermit。零结算amount 0时不产生任何链上交易授权直接过期作废。Go SDK 的 SettleUptoPermit2 对此有精确落地结算前先以permitted.amount作为amount重新走一遍验证settlementAmount 0时直接返回Success: true, Transaction: , Amount: 0无链上交易随后显式守卫settlementAmount permittedAmount时返回invalid_upto_evm_payload_settlement_exceeds_amount错误。SettlementResponse 示例{ success: true, transaction: 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef, network: eip155:84532, payer: 0x857b06519E91e3A54538791bDbb0E22373e36b66, amount: 2350000 }4. PaymentRequirements Schema 与阶段相关的 amount 语义upto方案使用的PaymentRequirements字段字段类型必填说明schemestring是必须为uptonetworkstring是CAIP-2 格式网络标识如eip155:84532amountstring是阶段相关验证期为最大授权额结算期为实际结算额assetstring是代币合约地址payTostring是收款钱包地址maxTimeoutSecondsnumber是支付完成允许的最大时间extraobject否方案附加信息必须包含name、version、facilitatorAddress阶段相关Phase-Dependent语义x402 中 verify 与 settle 请求共享同一PaymentRequirements类型。在upto中amount对服务器→Facilitator 的通信是阶段相关的验证期amount 客户端授权的最大金额结算期amount实际结算金额MUST ≤ 之前授权的上限。实际结算额由资源服务器通过结算期PaymentRequirements的amount字段传给 Facilitator从而无需额外字段或独立的结算消息类型。这是 scheme_upto.md 定义的第 5 条 MUST 属性——Facilitator 必须校验该金额不超过客户端签名的授权上限。Go SDK 用SettlementOverrides结构承载服务器端的实际用量见 types.go支持三种格式格式示例说明原始原子单位50000精确结算 50,000 原子单位百分比50%结算授权上限的 50%最多两位小数向下取整美元价格$0.05按extra.decimals默认 6换算为原子单位设置为0则完全跳过链上结算客户端不被扣费。5. SettlementResponse Schema 扩展与错误码upto在基础 SettlementResponse 之上扩展了实际结算额字段字段类型必填说明successboolean是结算是否成功errorReasonstring否失败原因成功时省略payerstring否付款钱包地址transactionstring是链上交易哈希$0 结算时为空字符串networkstring是CAIP-2 网络标识amountstring是实际扣款金额原子单位可为 0错误码沿用 x402 规范 定义的标准错误体系另加一个方案专属错误码invalid_upto_evm_payload_settlement_exceeds_amount试图结算超过授权amount的金额。Go SDK 错误常量表 中还包含一系列实现级错误码如upto_facilitator_mismatchwitness.facilitator 不是本 Facilitator、upto_amount_exceeds_permitted合约层AmountExceedsPermitted的映射、upto_unauthorized_facilitator合约层UnauthorizedFacilitator的映射等覆盖了从报文校验到链上 revert 的完整错误路径。6. 合约纵深x402UptoPermit2Proxy 如何强制上限与绑定upto 方案专用合约部署于0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002与 exact 方案使用的x402ExactPermit2Proxy结构相似但有本质差异Witness 结构多出facilitator字段string public constant WITNESS_TYPE_STRING Witness witness)TokenPermissions(address token,uint256 amount)Witness(address to,address facilitator,uint256 validAfter); struct Witness { address to; // 收款地址签名后不可变 address facilitator; // 被授权结算本笔支付的地址必须 msg.sender uint256 validAfter; // 最早可结算时间戳 }settle()的核心守卫源码 L60-L73function settle( ISignatureTransfer.PermitTransferFrom calldata permit, uint256 amount, address owner, Witness calldata witness, bytes calldata signature ) external nonReentrant { if (amount permit.permitted.amount) revert AmountExceedsPermitted(); // 上限强制 if (msg.sender ! witness.facilitator) revert UnauthorizedFacilitator(); // Facilitator 绑定 bytes32 witnessHash keccak256(abi.encode(WITNESS_TYPEHASH, witness.to, witness.facilitator, witness.validAfter)); _settle(permit, amount, owner, witness.to, witness.validAfter, witnessHash, WITNESS_TYPE_STRING, signature); emit Settled(); }两条revert恰好对应规范的两大安全目标AmountExceedsPermitted保证结算额 ≤ 授权上限链上硬约束UnauthorizedFacilitator保证只有客户端在签名时指定的那个 Facilitator 能选择结算金额——其他任何地址包括恶意 Facilitator都无法动用该授权。settleWithPermit()源码 L89-L104EIP-2612 全零 gas 路径。先执行_executePermit内部try/catch即使 permit 因授权已存在或代币不支持 EIP-2612而失败也不回滚仅发出诊断事件再走相同的结算守卫。CREATE2 跨链一致性x402BasePermit2Proxy.sol 的注释解释了原理——Permit2 本身通过确定性 CREATE2 部署器获得全 EVM 链一致的规范地址因此所有链使用相同构造参数canonical Permit2 地址时 initCode 相同代理合约的 CREATE2 地址也就跨链统一。7. Go SDK 实战三端接入以下代码来自仓库 upto EVM 机制说明 与 Gin upto 服务器示例演示从路由声明到按用量结算的完整闭环。客户端注册 upto scheme与 exact 可共存evmSigner, _ : evmsigners.NewClientSignerFromPrivateKey(os.Getenv(EVM_PRIVATE_KEY)) x402Client : x402.Newx402Client(). Register(eip155:*, exactevm.NewExactEvmScheme(evmSigner, nil)). // 固定价格服务 Register(eip155:*, uptoevm.NewUptoEvmScheme(evmSigner, nil)) // 按用量计费服务服务器声明upto路由并在 handler 中覆盖结算额r.Use(ginmw.X402Payment(ginmw.Config{ Routes: x402http.RoutesConfig{ GET /api/generate: { Accepts: x402http.PaymentOptions{ { Scheme: upto, Price: $0.10, // 客户端最多授权 10 美分 Network: eip155:84532, PayTo: 0xYourAddress, }, }, Description: AI text generation - billed by token usage, }, }, Facilitator: facilitatorClient, Schemes: []ginmw.SchemeConfig{ {Network: x402.Network(eip155:84532), Server: uptoevm.NewUptoEvmScheme()}, }, })) // handler 中先做业务再按实际用量结算 r.GET(/api/generate, func(c *gin.Context) { actualUsage : computeActualCost() // 你的计费逻辑 ginmw.SetSettlementOverrides(c, x402.SettlementOverrides{ Amount: fmt.Sprintf(%d, actualUsage), }) c.JSON(http.StatusOK, gin.H{result: ...}) })Facilitatoruptoevm.NewUptoEvmScheme(config)注册后其GetExtra()自动把facilitatorAddress写入/supported响应客户端据此签名。Gas 代付扩展的优先级当两种扩展同时宣告时优先走 EIP-2612若代币Extra中缺少name/version即不支持 EIP-2612客户端自动回退到 ERC-20 授权代付路径。支持的 EIP-155 网络示例Base Mainneteip155:8453、Base Sepoliaeip155:84532前提是 Permit2 与 upto 代理合约已部署。8. 安全考量规范原文五项最大金额授权风险客户端应慎重选择授权的amount。虽然服务器最多只能扣到该金额但客户端承担被全额扣走的风险。服务器信任upto要求客户端信任服务器会按实际用量公平收费——恶意服务器理论上可无视实际用量直接扣到上限。防签名重用Permit2 nonce 机制保证每笔授权只能结算一次。时间约束deadline与validAfter构成显式有效窗口限制未使用授权的暴露时间。零结算允许 $0 结算意味着未使用的授权无需链上交易即可自然过期降低 gas 成本与链上垃圾。9. 相关文档与延伸阅读网络无关的upto方案总纲核心 MUST 属性与范围外模式specs/schemes/upto/scheme_upto.md对照实现exact 方案在 EVM 上的固定金额结算specs/schemes/exact/scheme_exact_evm.md两个 gas 代付扩展规范eip2612_gas_sponsoring.md、erc20_gas_sponsoring.md规范附录指明 Canonical Permit2 合约地址可查 Uniswap 官方部署文档仓库 Go SDK 中固定为0x000000000022D473030F116dDEE9F6B43aC78BA3constants.go合约测试x402UptoPermit2Proxy.t.sol 与 fork 测试 x402UptoPermit2Proxy.fork.t.sol小结uptoon EVM 的设计精髓在于一份签名、两种语义——permitted.amount在验证期是上限、在结算期变成实际扣款而x402UptoPermit2Proxy用AmountExceedsPermitted与UnauthorizedFacilitator两条链上守卫把这个语义转变约束在客户端签名预先授权的范围内。理解 witness 三元组to / facilitator / validAfter与amount的阶段相关含义是正确实现和审计任何upto客户端/服务器/Facilitator 的关键。【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考