尧图精选

x402 erc20ApprovalGasSponsoring 扩展详解:面向 exact EVM 方案的 ERC-20 无 Gas 审批与原子结算

🕒 发布时间:2026/9/17 4:47:43 📁 来源:尧图网络
x402 erc20ApprovalGasSponsoring 扩展详解面向 exact EVM 方案的 ERC-20 无 Gas 审批与原子结算【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402本文围绕 x402 协议规范中的erc20ApprovalGasSponsoring扩展讲解如何在 HTTP 402 支付流程中实现 ERC-20 代币的无 Gas审批Client 如何离线签名一笔approve(Permit2, amount)交易、Facilitator 如何校验并垫付 Gas 完成结算以及该扩展在 Python 与 Go SDK 中的具体实现交易构造、字段校验、原子批量执行接口。读完本文你将能够理解该扩展的完整消息格式、校验与结算逻辑并能在 specs/schemes/exact/scheme_exact_evm.md 方案之上为不支持 EIP-2612 的 ERC-20 代币接入无 Gas 审批能力。为什么需要这个扩展exact 方案下的审批难题在 scheme_exactEVM 链方案中当extra.assetTransferMethod为permit2时付款方需要先把代币授权给 Canonical Permit2 合约Facilitator 才能代表用户调用 x402Permit2Proxy 完成结算其 Solidity 实现见 contracts/evm/src/x402BasePermit2Proxy.sol、contracts/evm/src/x402UptoPermit2Proxy.sol。问题在于支持 EIP-2612 的代币可以用一条链下permit签名替代链上审批这是另一个扩展 eip2612_gas_sponsoring.md 覆盖的场景但大量 ERC-20 代币并不实现 EIP-2612用户必须先发起一笔消耗原生 Gas 的approve交易。对于纯钱包地址EOA或移动端轻客户端来说要求用户先充值 Gas 再付 API 费用会直接打断支付体验。erc20ApprovalGasSponsoring扩展正是为此设计它让Client 签好但不上链的审批交易随PaymentPayload一起提交由Facilitator负责垫付 Gas、转发交易并完成结算。按 Go SDK 包注释的表述go/extensions/erc20approvalgassponsor/types.go这是面向不实现 EIP-2612的 ERC-20 代币的无 Gas 审批扩展。与链下签名不同Client 创建一笔已签名但未广播的approve(Permit2, MaxUint256)交易Facilitator 在调用 settle() 之前将其广播。核心流程三方职责与原子性要求规范specs/extensions/erc20_gas_sponsoring.md定义的分工如下角色职责Client构造并离线签名的普通 EVM 交易调用token.approve(Permit2, amount)Facilitator1) 若 Client 原生 Gas 余额不足向其钱包补足足够的原生代币2)广播Client 签好名的审批交易3) 审批确认后立即通过x402Permit2Proxy完成结算其中有一个关键的安全约束整个流程必须使用**原子批量交易atomic batch transaction**执行。原因在于时序风险——从 Facilitator 向用户打 Gas 到最终结算之间存在时间窗口恶意行为者可能抢跑front-run并在两者之间截走资金原子化打包消除了这个窗口。声明支持402 Payment Required 响应中的 extensions 条目Facilitator 通过在402 Payment Required响应的extensions对象中包含erc20ApprovalGasSponsoring条目来声明支持该扩展。规范给出的完整声明示例如下{ x402Version: 2, accepts: [ { scheme: exact, network: eip155:84532, amount: 10000, payTo: 0x209693Bc6afc0C5328bA36FaF03C514EF312287C, maxTimeoutSeconds: 60, asset: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, extra: { assetTransferMethod: permit2, name: USDC, version: 2 } } ], extensions: { erc20ApprovalGasSponsoring: { info: { description: The facilitator accepts a raw signed approval transaction and will sponsor the gas fees., version: 1 // 这里没有其它字段因为其余字段全部由 Client 填写 }, schema: { $schema: https://json-schema.org/draft/2020-12/schema, type: object, properties: { from: { type: string, pattern: ^0x[a-fA-F0-9]{40}$, description: The address of the sender. }, asset: { type: string, pattern: ^0x[a-fA-F0-9]{40}$, description: The ERC-20 token contract address to approve. }, spender: { type: string, pattern: ^0x[a-fA-F0-9]{40}$, description: The address of the spender (Canonical Permit2). }, amount: { type: string, pattern: ^[0-9]$, description: Approval amount (uint256). Typically MaxUint. }, signedTransaction: { type: string, pattern: ^0x[a-fA-F0-9]$, description: RLP-encoded signed transaction calling ERC20.approve(). }, version: { type: string, pattern: ^[0-9](\\.[0-9])*$, description: Schema version identifier. } }, required: [ from, asset, spender, amount, signedTransaction, version ] } } } }各字段的语义与约束与 SDK 中的 JSON Schema 实现一一对应见 python/x402/extensions/erc20_approval_gas_sponsoring/schema.py字段类型/约束说明from^0x[a-fA-F0-9]{40}$发送方地址代币持有者asset^0x[a-fA-F0-9]{40}$被审批的 ERC-20 代币合约地址spender^0x[a-fA-F0-9]{40}$被授权地址必须是 Canonical Permit2amount^[0-9]$审批额度uint256 十进制字符串通常为 MaxUint256signedTransaction^0x[a-fA-F0-9]$RLP 编码的已签名approve交易 hexversion^[0-9](\.[0-9])*$Schema 版本标识如 1、1.0、1.2.3注意info与schema的分工info在 402 响应中只携带description和version其余字段全部由 Client 填写而 Client 实际提交的PaymentPayload.extensions.erc20ApprovalGasSponsoring对象中info就是按上述 schema 填满的六字段对象。Go SDK 的声明函数 go/extensions/erc20approvalgassponsor/declare.go 返回的就是该结构其描述文本为 The facilitator accepts a pre-signed ERC-20 approve(Permit2, MaxUint256) transaction for tokens without EIP-2612并附Version: 1常量go/extensions/erc20approvalgassponsor/types.go。Client 侧流程构造、签名并挂载审批交易规范规定的 Client 侧步骤构造一笔普通的以太坊交易调用token.approve(Permit2, amount)在链下对该交易签名将原始签名交易的 hex放入PaymentPayload的extensions.erc20ApprovalGasSponsoringClient 实现要点规范明确要求 Client 保证两点否则签名交易将无效maxFee与maxPriorityFee必须与当前网络价格匹配EIP-1559 费率nonce必须等于该钱包当前链上 nonce。Python SDK 中的参考实现 python/x402/extensions/erc20_approval_gas_sponsoring/client.py 完整展示了这一步。sign_erc20_approval_transaction(signer, token_address, chain_id)的关键行为client.py#L17-L87calldata用 ERC-20approveABI 编码approve(PERMIT2_ADDRESS, MAX_UINT256)其中MAX_UINT256 2**256 - 1即规范所说通常为 MaxUint若运行环境没有 Web3则回退到手工拼接——approve 函数选择器095ea7b3加 32 字节补齐的 Permit2 地址与 MaxUint256client.py#L50-L53nonce实时读取signer.get_transaction_count(signer.address)费率优先调用 signer 的estimate_fees_per_gas()获取网络当前价格若不可用回退到保守默认值maxFeePerGas 1_000_000_000wei1 Gwei、maxPriorityFeePerGas 100_000_000wei0.1 Gweiclient.py#L57-L65交易类型固定为type: 2EIP-1559 动态费率交易gas取常量ERC20_APPROVE_GAS_LIMIT定义于 python/x402/mechanisms/evm/constants.pysigner 契约signer 需提供address、sign_transaction(tx_dict) - hex、get_transaction_count(address) - int可选estimate_fees_per_gas()返回值是Erc20ApprovalGasSponsoringInfo数据类python/x402/extensions/erc20_approval_gas_sponsoring/types.py#L11-L41to_dict()输出的键名恰好就是 schema 要求的from / asset / spender / amount / signedTransaction / versionspender固定为 Canonical Permit2 地址amount为 MaxUint256 的十进制字符串。PaymentPayload 示例规范给出的完整PaymentPayload示例注意payload.permit2Authorization走的是常规 permit2 授权路径而extensions.erc20ApprovalGasSponsoring携带的是那笔已签名的approve交易两者同包提交{ x402Version: 2, accepts: [ { scheme: exact, network: eip155:84532, amount: 10000, payTo: 0x209693Bc6afc0C5328bA36FaF03C514EF312287C, maxTimeoutSeconds: 60, asset: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, extra: { assetTransferMethod: permit2, name: USDC, version: 2 } } ], payload: { signature: 0x2d6a7588d6acca505cbf0d9a4a227e0c52c6c34008c8e8986a1283259764173608a2ce6496642e377d6da8dbbf5836e9bd15092f9ecab05ded3d6293af148b571c, permit2Authorization: { permitted: { token: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, amount: 10000 }, from: 0x857b06519E91e3A54538791bDbb0E22373e36b66, spender: 0x402085c248EeA27D92E8b30b2C58ed07f9E20001, nonce: 33247007178036348590600198031289925668252061821958005840077069883511451257277, deadline: 1740672154, witness: { to: 0x209693Bc6afc0C5328bA36FaF03C514EF312287C, validAfter: 1740672089 } } }, extensions: { erc20ApprovalGasSponsoring: { info: { from: 0x857b06519E91e3A54538791bDbb0E22373e36b66, asset: 0x036CbD53842c5426634e7929541eC2318f3dCF7e, spender: 0x000000000022D473030F116dDEE9F6B43aC78BA3, amount: 115792089237316195423570985008687907853269984665640564039457584007913129639935, signedTransaction: 0x505cbf0d9a4a227e0c52c6c2d6a7588d6acca34008c8e8986a12832597641d6293af148b571c73608a2ce6496642e377d6da8dbbf5836e9bd15092f9ecab05ded3, version: 1 } } } }示例中amount即 MaxUint2562^256 - 1的十进制表示spender为 Canonical Permit2 合约地址其权威地址见 specs/schemes/exact/scheme_exact_evm.md 的 Canonical Permit2 一节。Facilitator 校验逻辑四步验证规范规定收到携带erc20ApprovalGasSponsoring的PaymentPayload后Facilitator 必须执行以下验证1. 解码原始签名交易对signedTransaction执行 RLP 解码。2. 校验交易字段恢复出的签名者必须与from一致to地址必须等于asset代币合约calldata必须对应approve(spender, amount)调用关键Facilitator必须验证扩展数据中的spender与解码交易中 calldata 里的 spender 一致且等于期望合约Canonical Permit2nonce必须等于用户当前链上 noncemaxFee / maxPriorityFee必须与当前网络价格匹配。Python SDK 的校验实现 python/x402/extensions/erc20_approval_gas_sponsoring/facilitator.py 将上述逻辑落成了一条清晰的错误码链可作为 Facilitator 实现的参照validate_erc20_approval_for_paymentfacilitator.py#L60-L90依次检查schema 格式六个字段正则→ 失败返回invalid_erc20_approval_extension_formatinfo.from与本次付款人payer一致 →erc20_approval_from_mismatchinfo.asset与本次支付使用的代币地址一致 →erc20_approval_asset_mismatchinfo.spender等于PERMIT2_ADDRESS常量定义在 python/x402/mechanisms/evm/constants.py→erc20_approval_spender_not_permit2。_validate_signed_approval_txfacilitator.py#L93-L154进一步解码交易用Account.recover_transaction恢复签名者与 payer 比对 →erc20_approval_tx_signer_mismatch用TypedTransaction.from_bytes解析 typed 交易确认to指向代币合约 →erc20_approval_tx_wrong_target确认 calldata 以 approve 选择器095ea7b3开头 →erc20_approval_tx_wrong_selector从 calldata 中解析第 32–72 个 hex 字符即 bytes 4..36 的 32 字节补齐地址作为 spender与 Permit2 地址比对 →erc20_approval_tx_wrong_spender解析失败则返回erc20_approval_tx_parse_failed/erc20_approval_tx_invalid_signature。Go SDK 提供了同层的格式提取与校验ExtractInfo从PaymentPayload的extensions中取出六字段并检查完整性go/extensions/erc20approvalgassponsor/extract.go#L21-L60ValidateInfo执行与 JSON Schema 一致的正则校验extract.go#L62-L70测试覆盖见 extract_test.go。3. 检查用户 Gas 余额检查from地址是否有足够的原生代币覆盖这笔审批交易的成本余额充足 →跳过打款步骤余额不足 → Facilitator计算缺口并垫付差额。4. 模拟完整执行序列Facilitator 必须在单个原子批量交易中模拟Funding向用户发送原生 Gas 代币仅在需要时Approval Relay广播用户签好名的审批交易Settlement调用x402Permit2Proxy.settle。结算逻辑Facilitator 的原子打包规范最后定义的结算逻辑即 Facilitator 构造的原子 bundle的三个有序操作Gas Funding若用户原生 Gas 不足向用户from发送足以支付审批交易 Gas 的原生代币Broadcast Approval广播 Client 提供的signedTransaction调用ERC20.approve(Permit2, amount)x402Permit2Proxy Settlement调用x402Permit2Proxy.settle()完成结算把代币划转给payTo。从源码结构看SDK 把如何保证原子性留给了 Facilitator 的 signer 实现。Go SDK 定义了专门的多交易执行接口go/extensions/erc20approvalgassponsor/types.go#L62-L95TransactionRequest单个执行单元Serialized为已签名的 raw 交易 hex直接sendRawTransaction转发或Call未签名的合约写调用由 signer 签名执行——前者对应转发用户的审批交易后者对应打款与 settle 调用Erc20ApprovalGasSponsoringSigner在FacilitatorEvmSigner基础上扩展SendTransactions(ctx, []TransactionRequest) ([]string, error)注释明确signer 拥有执行策略顺序执行、批量执行或通过 Flashbots、multicall、智能合约账户批处理实现原子打包Erc20ApprovalGasSponsoringSimulator可选的SimulateTransactions能力对应规范中模拟完整执行序列这一步Erc20ApprovalFacilitatorExtension持有 signer 并注册到 Facilitator支持SignerForNetwork按网络选择不同结算 signer优先于默认 signer该优先级行为有单测覆盖resolve_signer_test.go。Python SDK 的接口与之对应python/x402/extensions/erc20_approval_gas_sponsoring/types.py#L57-L104Erc20ApprovalGasSponsoringSigner协议要求send_transactions(list[TransactionRequest]) - list[str]发送一批交易元素可以是已签名 raw hex 或WriteContractCall返回逐笔交易哈希以及wait_for_transaction_receiptErc20ApprovalFacilitatorExtension以key erc20ApprovalGasSponsoring标识自身并支持signer_for_network解析器resolve_signer(network)优先使用按网络的解析结果。仓库中的实现与验证入口围绕该规范仓库中可直接深入阅读的对应物内容路径扩展规范本文主体specs/extensions/erc20_gas_sponsoring.md所依赖的 exact EVM 方案与 Canonical Permit2specs/schemes/exact/scheme_exact_evm.md姊妹扩展EIP-2612 permit 场景specs/extensions/eip2612_gas_sponsoring.mdPython 实现类型/客户端签名/Facilitator 校验/Schema/声明python/x402/extensions/erc20_approval_gas_sponsoring/Go 实现声明/提取/校验/Signer 接口go/extensions/erc20approvalgassponsor/settle 的链上实现Permit2 代理合约族contracts/evm/src/x402BasePermit2Proxy.sol、contracts/evm/src/x402ExactPermit2Proxy.sol适用前提与限制该扩展仅服务于assetTransferMethod: permit2的 exact EVM 方案accepts条目中必须能匹配该 scheme/network/asset若代币支持 EIP-2612规范建议优先考虑 eip2612_gas_sponsoring.md 扩展的纯链下签名路径spender被硬校验为 Canonical Permit2Python 实现直接比对PERMIT2_ADDRESS常量不是任意 spenderClient 的maxFee/maxPriorityFee与nonce若与链上状态脱节签名交易将直接作废——这是 Client 侧必须实时获取网络价格与 nonce 的根本原因原子性是安全边界而非优化项规范明确以原子批量交易来对抗打款与结算之间被抢跑截资的风险Facilitator 若无法提供批量/打包执行能力Go 接口中的SendTransactions/SimulateTransactions则不应声明支持该扩展。【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →