x402 Go SDK Solana V1 支付机制:为旧版客户端与 Facilitator 提供的向后兼容层
【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402
本文基于 go/mechanisms/svm/exact/v1/README.md 展开,讲解 x402 Go SDK 中 Solana(SVM)网络 x402 协议 V1 支付机制的定位、与 V2 的关键差异、V1 客户端与 Facilitator 的真实注册方式与调用链,并结合 client/scheme.go、facilitator/scheme.go 等源码说明交易构造、校验与结算的完整实现。读完后你能够:正确注册 V1 的 Client/Facilitator 方案、理解 V1 网络标识到 CAIP-2 的内部映射,并评估将存量 V1 服务迁移到 V2 的改动点。
一、V1 机制的定位与能力边界
go/mechanisms/svm/exact/v1/包提供的唯一目的是向后兼容:让已经使用 x402 协议第 1 版的存量客户端和 Facilitator 继续与新生态互通。README 明确提示:新实现应直接使用父目录中的 V2 机制(即 go/mechanisms/svm/exact/client 与 go/mechanisms/svm/exact/facilitator)。
能力覆盖上,V1 包按角色划分如下:
| 角色 | 是否提供 | 说明 |
|---|---|---|
| Client | ✅ | 创建 V1 格式的支付载荷(PaymentPayloadV1) |
| Facilitator | ✅ | 校验并结算 V1 支付 |
| Server | ❌ | 不提供——新资源服务器应使用 V2 |
从源码结构看,V1 的实现"复用 V2 大部分逻辑",只做三处适配:V1 网络命名约定、V1 载荷结构(scheme 位于 payload 顶层而非 Accepted 内)、V1 金额字段(MaxAmountRequired而非Amount)。交易结构、校验逻辑和结算流程与 V2 保持同一套,这一点可以直接从 client/scheme.go 与 facilitator/scheme.go 大量引用共享包svm(go/mechanisms/svm)的工具函数得到印证。
二、V1 与 V2 的三大关键差异
2.1 网络标识符
- V1 使用简单名称:
"solana"、"solana-devnet"、"solana-testnet" - V2 使用 CAIP-2 格式:
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"
SDK 内部维护了一张显式的映射表 V1ToV2NetworkMap,将 V1 名称自动归一化为 CAIP-2 标识,因此 V1 代码可以复用按 CAIP-2 组织的网络配置:
| V1 网络名称 | 内部映射的 CAIP-2 标识符 | 默认 RPC |
|---|---|---|
solana(Mainnet) | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | https://api.mainnet-beta.solana.com |
solana-devnet(Devnet) | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 | https://api.devnet.solana.com |
solana-testnet(Testnet) | solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z | https://api.testnet.solana.com |
网络名称常量定义在 constants.go(SolanaMainnetV1、SolanaDevnetV1、SolanaTestnetV1),建议代码中直接引用这些常量而不是硬编码字符串。
2.2 金额字段
- V1 支付要求使用
MaxAmountRequired字段(字符串形式,以最小代币单位计) - V2 使用
Amount字段
这一点在客户端与 Facilitator 两端都有对应处理:客户端在 CreatePaymentPayload 中读取requirements.MaxAmountRequired;Facilitator 在 verifyTransferInstruction 中用同一字段作为最低转账金额的校验基准。
2.3 协议版本
- V1 机制只支持 x402 版本 1(客户端返回的载荷固定为
X402Version: 1) - V2 机制只支持 x402 版本 2
两者通过版本字段隔离,互不混用。
三、V1 Client:创建 V1 支付载荷
3.1 构造与注册
V1 客户端方案的构造函数为 NewExactSvmSchemeV1,接受一个svm.ClientSvmSigner和可选的*svm.ClientConfig(用于覆盖默认 RPC 地址)。仓库集成测试 go/test/integration/svm_test.go 展示了完整的真实用法:
import ( x402 "github.com/x402-foundation/x402/go" "github.com/x402-foundation/x402/go/mechanisms/svm" svmv1client "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1/client" ) // 构造 V1 客户端方案,可传入自定义 RPC 配置 clientSigner, _ := newRealClientSvmSigner(privateKey) svmv1Client := svmv1client.NewExactSvmSchemeV1(clientSigner, &svm.ClientConfig{ RPCURL: "https://api.devnet.solana.com", }) client := x402.Newx402Client() // V1 使用简单网络名注册 client.RegisterV1(svm.SolanaDevnetV1, svmv1Client)注意两个细节:
- 注册接口是
RegisterV1,网络参数传 V1 简单名(svm.SolanaDevnetV1即"solana-devnet"),而不是 CAIP-2 字符串; ClientConfig.RPCURL为可选参数——不传时使用 NetworkConfigs 中按网络内置的默认 RPC,传了则覆盖(见 CreatePaymentPayload 的取值逻辑)。
3.2 CreatePaymentPayload 的构造流程
结合 client/scheme.go 的源码,一次CreatePaymentPayload调用会依次完成:
- 网络校验:
svm.IsValidNetwork检查网络名,随后取对应网络配置与 RPC URL; - 代币账户检查:用
requirements.Asset(USDC mint 地址,base58)查询 mint 账户,取其 Owner 判断是标准 Token Program 还是 Token-2022 Program,二者之外直接报ErrUnknownTokenProgram; - ATA 推导:分别用签名者地址(付款人)和
requirements.PayTo(收款人)推导源/目的 Associated Token Address; - 金额解析:解析
requirements.MaxAmountRequired(V1 特有字段); - feePayer 提取:从
requirements.Extra(JSON)中读取feePayer地址——这是必填项,缺失即报ErrFeePayerRequired;该地址来自 Facilitator 的/supported扩展字段(见下文 Facilitator 的GetExtra); - 构造交易指令序列:
SetComputeUnitLimit(默认 20000 CU)+SetComputeUnitPrice(默认 1 microlamport)+TransferChecked(金额 + mint 的 decimals)+ Memo 指令。Memo 优先使用卖家在extra.memo中定义的内容(上限 256 字节),未提供则生成 16 字节随机 nonce 的十六进制串以保证交易唯一性; - 版本化交易:显式设置
MessageVersionV0,使交易成为版本化交易,保证 TypeScript、Python、Go 各语言 Facilitator 都能正确补签; - 部分签名 + 编码:客户端签名后 base64 编码,封装进
svm.ExactSvmPayload,最终返回顶层携带X402Version: 1、Scheme、Network的PaymentPayloadV1。
客户端所有失败分支都有稳定的错误码常量(如invalid_exact_solana_client_invalid_amount、invalid_exact_solana_client_fee_payer_required等),集中定义在 client/errors.go,便于调用方做程序化分支处理。
四、V1 Facilitator:校验与结算
4.1 构造与注册
V1 Facilitator 方案构造函数为 NewExactSvmSchemeV1,接受svm.FacilitatorSvmSigner和可选的*svm.SettlementCache。集成测试中的注册方式(svm_test.go):
svmv1Facilitator := svmv1facilitator.NewExactSvmSchemeV1(facilitatorSigner) facilitator := x402.Newx402Facilitator() facilitator.RegisterV1([]x402.Network{svm.SolanaDevnetV1}, svmv1Facilitator)此外,方案实现了CaipFamily()返回"solana:*",即从 CAIP 家族层面声明支持所有 Solana 链(见 facilitator/scheme.go)。
4.2 GetExtra:feePayer 的发现机制
SVM 网络的交易费用(rent 与提交费)由 Facilitator 侧承担,因此卖家/客户端需要知道"该让谁来付"。GetExtra(facilitator/scheme.go)从签名器可用地址中随机选取一个 feePayer放入 supported kinds 的扩展字段,起到多签名钱包间负载均衡的作用;GetSigners则返回该网络下全部可用地址。
4.3 Verify 的六步校验链
Verify 按以下顺序执行,任一环节失败都会返回带稳定错误码的VerifyError:
- 要求级校验:scheme 必须为
exact,payload 顶层 Network 与 requirements.Network 一致(V1 的 scheme/network 在顶层,不像 V2 在 Accepted 中);解析extra.feePayer并确认其属于本 Facilitator 管理的签名器地址(ErrFeePayerNotManaged拦截外部地址); - 交易解码:base64 → 交易对象;指令数量必须在3~6之间(基础 3 条,加 Lighthouse/Memo 可选指令,最多 6 条);
- Compute Budget 校验:第 1 条必须是
SetComputeUnitLimit(判别子 2),第 2 条必须是SetComputeUnitPrice(判别子 3),且单价不得超过 MaxComputeUnitPriceMicrolamports = 5,000,000 microlamports(即 5 lamports/CU); - Transfer 指令校验(verifyTransferInstruction),这是安全核心:
- 程序必须是 Token 或 Token-2022,指令必须是
TransferChecked; - 防自付检查:转账授权人(authority)不得是 Facilitator 自己的签名器地址,防止 Facilitator 签署转走自己资金的交易(
ErrFeePayerTransferringFunds); - mint 必须等于
requirements.Asset;目的 ATA 必须等于按PayTo + Asset推导的 ATA; - 转账金额必须 ≥
MaxAmountRequired;
- 程序必须是 Token 或 Token-2022,指令必须是
- 可选指令白名单:第 4~6 条指令只允许 Lighthouse(Phantom/Solflare 钱包注资保护,Phantom 注入 1 条、Solflare 注入 2 条)或 Memo 程序;若 requirements 带了
extra.memo,则要求恰好一条 Memo 指令且内容严格一致(ErrMemoCount/ErrMemoMismatch); - 补签 + 模拟:用 feePayer 对应签名器补签完整交易,并调用
SimulateTransaction模拟执行——这一步能提前暴露余额不足、账户无效等问题,避免 settle 阶段才失败。
4.4 Settle:结算与防重复保护
Settle 的流程:先完整跑一遍Verify(失败时把VerifyError转成SettleError)→ 解析 payload →重复结算检查→ 解码交易 → 校验交易内实际 feePayer(消息中第一个账户)与 requirements 声明一致(ErrFeePayerMismatch)→ 补签 →SendTransaction上链 →ConfirmTransaction等待确认,最终返回链上交易签名。
其中重复结算检查依赖 SVM 机制包内置的SettlementCache(go/mechanisms/svm/settlement_cache.go),用于缓解 Solana 上"同一交易在链上确认前被多次提交 /settle"的竞态:RPC 对重复提交返回 success,恶意客户端可能借此只付一次钱却解锁多份资源。缓存对相同交易载荷的后续请求返回duplicate_settlement错误(常量见 facilitator/errors.go),条目 120 秒后自动驱逐(约两倍 blockhash 寿命,见 SettlementTTL)。
生产环境的关键实践是把同一个缓存实例同时传给 V1 与 V2 方案,从而启用跨版本去重(FACILITATOR.md 与 SVM README 均给出了该用法):
import svm "github.com/x402-foundation/x402/go/mechanisms/svm" cache := svm.NewSettlementCache() v2Scheme := facilitator.NewExactSvmScheme(signer, cache) // V2 v1Scheme := v1facilitator.NewExactSvmSchemeV1(signer, cache) // V1若不传缓存,构造函数会自动创建一个独立实例(见 NewExactSvmSchemeV1),这意味着 V1/V2 各自为政、跨版本去重失效——存量服务升级时应注意补上这一行。该行为有专项测试覆盖:duplicate_tx_test.go。
五、从 V1 迁移到 V2
对仍在使用 V1 的服务,官方给出的迁移路径非常简洁——改动点集中在导入路径与网络标识两处:
Before(V1):
import "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1/client" svmv1Client := client.NewExactSvmSchemeV1(signer) client.RegisterV1(svm.SolanaDevnetV1, svmv1Client)After(V2):
import "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" svmClient := client.NewExactSvmScheme(signer) client.Register(svm.SolanaDevnetCAIP2, svmClient)迁移时需要同步调整的地方:
- 网络字符串从简单名换成 CAIP-2 标识符(映射关系见第二节表格,可直接引用
go/mechanisms/svm包中的SolanaMainnetCAIP2等常量); - 金额字段从
MaxAmountRequired切换到Amount; - 注册接口从
RegisterV1换成普通的Register; - 若与 V1 方案共存,务必共享同一个
SettlementCache实例。
六、测试与验证入口
- 重复结算单元测试:go/mechanisms/svm/exact/v1/facilitator/duplicate_tx_test.go 验证缓存对相同交易载荷的拦截行为;
- 端到端集成测试:go/test/integration/svm_test.go 在真实 Devnet 上跑通 V1 全流程(x402Client + V1 方案 → x402Facilitator + V1 方案 → 资源服务器 + V2 方案)。注意其中资源服务器注册的是V2 CAIP-2 网络,印证了"Server 不提供 V1、只走 V2"的能力边界;该测试需要设置
SVM_CLIENT_PRIVATE_KEY、SVM_FACILITATOR_PRIVATE_KEY、SVM_FACILITATOR_ADDRESS、SVM_RESOURCE_SERVER_ADDRESS环境变量,否则自动跳过。
七、相关文档与规格
- SVM 机制总览(V2 客户端/Facilitator/Server 导出说明)
- Exact SVM 方案规格(含重复结算竞态与缓解策略的详细讨论)
- Exact 方案通用规格目录
- x402 协议规格(v1/v2 双版本规范)
- Facilitator 开发指南(含生产环境注意事项)
适用前提小结:本文所有结论均基于当前仓库代码——V1 包仅包含 client 与 facilitator 两个子包,网络映射、默认 CU 参数、错误码与缓存 TTL 均取自 go/mechanisms/svm/constants.go;V1 机制面向存量兼容场景,新项目应直接使用同目录下的 V2 实现。
【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考