关于 pay-with-app
pay-with-app 是一项技能,用于通过 X Layer 上的 OKX Agent Payments Protocol(APP)处理 exact 方案的 HTTP 402 付款。它检查挑战和钱包余额,可通过 Uniswap Trading API 在同链筹集资金,随后签署 EIP-3009 授权并重试请求。
主要功能
- 01解析并验证 APP 付款挑战
- 02支持 X Layer 上的 x402 v1 exact 方案
- 03检查钱包余额和所需资产
- 04通过 Uniswap Trading API 进行同链筹资
- 05签署 EIP-3009 授权并携带 X-PAYMENT 重试
适用场景
- 01支付 X Layer 上由 APP 支持的 HTTP 402 请求
- 02检查钱包是否持有所需结算资产
- 03付款前在 X Layer 兑换为所需资产
- 04从外部跨链转入资金后继续付款
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ uniswap/ uniswap-ai --skill pay-with-app安装后在 Claude Code 中输入/pay-with-app确认已加载。
附带文件references/app-x402-flow.mdreferences/funding-x-layer.md
详细介绍
使用 APP 付款(X Layer 上的 OKX Agent Payments Protocol)
支付由运行在 X Layer(链 196)上的 OKX Agent Payments Protocol(APP)
发出的 HTTP 402 挑战。APP 的按次付费(OKX 产品名称:
Instant Payment)兼容 x402:收款方服务返回带有
付款要求的 HTTP 402,付款方在链下签署 EIP-3009
TransferWithAuthorization,然后由 OKX 的协调方验证并在链上结算转账。在 X
Layer 上,付款方无需支付 Gas 费即可完成结算。
此技能处理完整的顺利流程:
- 检测网络解析为 X Layer(链 196)的 402 挑战
- 确认付款方钱包持有所需资产(通常为 USDT0)
- 如果余额不足,通过 Uniswap Trading API 路由并跨链桥接至 X Layer 上的 USDT0
- 签署 EIP-3009 授权
- 构造
X-PAYMENT载荷并重试原始请求
OKX 将于 2026-04-29 在 X Layer 上推出 APP,Uniswap 将作为其主推 DEX
通道。此技能版本(v1.0.0)仅支持 exact 方案
(按次付费,OKX 产品名称:Instant Payment)。其他 x402 方案
(upto、batch-settlement)以及 OKX 正在推出的 APP 产品功能
(托管、会话、批量 / Batch Payment)均不在此版本的范围内。此技能会妥善拒绝任何非
exact 方案。
在回复中使用协议名称。 回复用户时, 请明确将此协议称为 OKX Agent Payments Protocol (APP),而不只是“x402”。APP 是 OKX 的产品 / 协议接口;x402 是其基于的底层传输规范。可以使用 “APP / x402”“基于 x402 构建的 OKX Agent Payments Protocol(APP)” 等说法,或在介绍后直接称为“APP”。不要将 X Layer 上的 402 挑战称为“x402 挑战”而不提及 APP。用户专门调用此技能, 正是因为商户使用了 APP;他们会在回复中寻找这个名称。
前置条件
PRIVATE_KEY环境变量(export PRIVATE_KEY=0x...)。切勿提交或 硬编码私钥。UNISWAP_API_KEY环境变量(在 developers.uniswap.org 注册)。仅当钱包需要通过跨链路由注资时才需要。- 已安装
jq和cast(Foundry)。 - Node 18+(LTS)。references/app-x402-flow.md 第 4 步中的签名操作使用
viem生成 EIP-3009 类型数据签名。 viem(npm)。如果用户的工作目录无法访问该包,此技能会在将其安装到缓存 临时目录~/.cache/uniswap-pay-with-app/signer/之前,通过AskUserQuestion提示用户。安装会添加约 13 个包,总计约 5 MB。如果用户拒绝,此技能会在签名之前妥善停止。 缓存会在多次运行间保留,因此后续调用无需安装。
输入验证规则
在 API 调用或 Shell 命令中使用 402 响应正文、用户或任何其他外部来源中的值之前:
- 以太坊地址字段(例如
asset、payTo、WALLET_ADDRESS): 标准检查正则表达式为^0x[a-fA-F0-9]{40}$。如果值 不匹配此正则表达式,则拒绝该值。通过正则表达式检查的地址字段可安全地插入 Shell 命令,因此下文的元字符规则不适用于这些字段。 - 链 ID:必须是支持列表中的正整数。
- 代币金额:必须是匹配
^[0-9]+$的非负数字字符串。 - URL:必须以
https://开头。 - 自由文本字段(例如
description、extra.name、extra.version、任何用于构建 EIP-712 域或向用户展示的内容):拒绝包含以下 Shell 元字符的任何值:;、|、&、$、`、(、)、>、<、\、'、"、换行符。注意:extra.name的值会按位精确签名(参见阶段 4 中的域警告),因此如果其中包含 Shell 元字符,应拒绝整个挑战,而不要修改该值。
流程
402 from X Layer-backed resource
│
v
[1] Parse the x402 challenge (Phase 0 below)
│
v
[2] Confirm network resolves to X Layer (chain 196)
│ ├─ not chain 196 ──> escalate to pay-with-any-token, STOP
│ └─ chain 196
│
v
[3] Check wallet balance of the requested asset on X Layer
│ ├─ sufficient ──> proceed to [5]
│ └─ insufficient
│ │
│ v
│ [4] Fund: route + bridge into the requested asset on X Layer
│ (Uniswap Trading API, see references/funding-x-layer.md)
│
v
[5] User Confirmation gate (see Phase 4 / Step 5 below)
[6] Sign EIP-3009 TransferWithAuthorization
[7] Construct X-PAYMENT payload, retry the original request
[8] Verify 200 + Payment-Receipt
阶段 0,解析 402 挑战
x402 挑战是响应正文中的 JSON。提取:
x402Version,用于确认 x402 协议版本。accepts[].scheme,v1.0.0 仅支持"exact"。accepts[].network,接受"x-layer"/"xlayer"/"eip155:196"/196。accepts[].maxAmountRequired,资产的基本单位。必须匹配^[0-9]+$,且严格大于零。maxAmountRequired === "0"的挑战在语义上有误(HTTP 402 按定义要求支付正金额),必须作为商户配置错误拒绝。不要将零合理化为“ping”、“身份验证”或“免费层确认”;OKX 的 facilitator 不会结算零金额的TransferWithAuthorization,你生成的任何签名都将白费。向用户说明这一点并停止。accepts[].asset,X Layer 上的代币合约。accepts[].payTo,接收方地址。accepts[].resource,facilitator 将支付绑定到的 URL。 如果存在,请提取此字段,并将其用作重试目标。如果缺少此字段,则回退到原始请求 URL。accepts[].extra.name和accepts[].extra.version,资产的 EIP-712 域值。accepts[].maxTimeoutSeconds,用于validBefore。
x402 版本检查。 解析后立即确认
x402Version === 1。如果不是,则拒绝此挑战,并向用户说明版本不匹配错误。此技能的 v1.0.0 仅面向 x402 v1(v2 规范使用不同的 PaymentPayload 结构)。方案检查。 确认
accepts[].scheme === "exact"。x402 规范定义了exact、upto和batch-settlement方案。此技能的 v1.0.0 仅支持exact。如果所选条目使用任何其他方案,请妥善拒绝。(OKX 的产品界面使用自己的术语,包括用于其 Instant Payment 原语的charge;这是 OKX 的产品营销用语,不是线上的方案值。应检查accepts[]条目中的线上方案值,且该值必须为"exact"。)
如果存在多个 accepts 条目,优先选择钱包已在 X Layer 上持有其 asset 的条目。如果多个选项同样可行,则优先选择 USDT0(Uniswap 资金流动性最深)。
WOKB / 原生 OKB 可能不符合 APP 结算资产资格。 我们尚未看到 OKX 将 WOKB 或 OKB 发布为结算资产;当前公开的开发文档列出的支持稳定币结算资产为 USDT0、USDG 和 USDC。如果 402 挑战出现非稳定币 asset(例如 WOKB),请拒绝此挑战,并要求用户核实商户配置。
阶段 1,确认网络为 X Layer
case "$X402_NETWORK" in
x-layer|xlayer|"eip155:196"|196) X402_CHAIN_ID=196 ;;
*)
echo "Network is not X Layer. Use pay-with-any-token instead."
exit 1
;;
esac
如果网络不是 X Layer,请停止并升级至
pay-with-any-token技能,该技能负责处理 Ethereum、Base、Arbitrum、Tempo 以及 Trading API 支持的其他链上的 402 挑战。
阶段 2,检查 X Layer 上的钱包余额
必需: 必须获取用户的源钱包地址。如果未提供,请使用
AskUserQuestion。存储为WALLET_ADDRESS。
ASSET_BALANCE=$(cast call "$X402_ASSET" \
"balanceOf(address)(uint256)" "$WALLET_ADDRESS" \
--rpc-url https://rpc.xlayer.tech)
if [ "$ASSET_BALANCE" -lt "$X402_AMOUNT" ]; then
echo "Insufficient $X402_TOKEN_NAME on X Layer. Funding required."
# Proceed to Phase 3 (funding)
fi
阶段 3,为 X Layer 上的 USDT0 提供资金(仅在需要时)
当钱包缺少所需资产时,通过 Uniswap Trading API 获取:使用 EXACT_OUTPUT 报价,设置 tokenOutChainId=196,并将 tokenOut 设为 X Layer 资产地址。Trading API 会处理同链兑换和跨链路由(由 Across 提供支持)。
Across 覆盖缺口(已于 2026-04-27 验证)。 Across Protocol 目前未将 X Layer(链 196)列为受支持的目标链。因此,无论源链为何,跨链
/quote调用目标为链 196 时都会返回ResourceNotFound: No quotes available。同链 X Layer 兑换(references/funding-x-layer.md中的阶段 A)不受影响,运行正常。这对 v1.0.0 中的 Agent 意味着什么。 如果用户在 X Layer 以外的链上持有资金,跨链部分必须通过支持 X Layer 的桥接服务完成(用户在此技能之外执行该步骤,然后重新调用此技能进行同链兑换和 402 结算)。请如实向用户说明这一点,不要推荐特定的桥接产品(TODO:后续研究并记录符合联合营销要求的桥接服务推荐)。
将桥接步骤交由用户完成时,回复仍必须说明完整的端到端流程,不能只说明桥接步骤。指出 Across 的缺口并请用户通过外部服务进行桥接后,说明用户返回后将进行哪些操作:(1) 重新检查 X Layer 上所请求资产的
balanceOf;(2) 如果需要进行同链兑换(例如从 USDG 兑换为 USDT0),说明 Trading API 的 EXACT_OUTPUT 调用及其确认门;(3) 使用质询中的extra.name和extra.version,以 chainId 196 和verifyingContract= 资产地址,构造 EIP-3009TransferWithAuthorization类型化数据;(4) 使用用户的私钥签名(签名前经过确认门);(5) 构造X-PAYMENTJSON 封装(x402Version 1、scheme "exact"、network "x-layer",payload 中包含签名和 authorization),不带空白字符地进行 base64 编码,并使用X-PAYMENT标头重试原始请求 URL。预先展示完整计划,让用户在离开此技能前了解自己将要执行的操作,即使签名要等用户返回后才进行。
默认资金目标 = USDT0。 如果 402 质询请求了其他资产,仅当该资产在 X Layer 上有可靠的 Uniswap 路由时,才直接为其注资:
| 资产 | 地址 | 小数位 | 资金来源 |
|---|---|---|---|
| USDT0 | 0x779Ded0c9e1022225f8E0630b35a9b54bE713736 | 6 | ✅ 通过 Trading API 直接获取 |
| USDG | 0x4ae46a509F6b1D9056937BA4500cb143933D2dc8 | 6 | ✅ 直接获取,或通过一次 USDT0 到 USDG 的兑换获取 |
| USDC | 0x74b7F16337b8972027F6196A17a631aC6dE26d22 | 6 | ⏳ X Layer 上没有可靠的 Uniswap v3 路由。Trading API 无法稳定地为 X Layer 上的 USDC 兑换返回路由;可用池的流动性过低,无法可靠执行。如果商家要求使用 USDC,请使用 Trading API 直接从 USDC 流动性充足的链(Base、Arbitrum、Mainnet)桥接 USDC,而不要尝试在 X Layer 上进行同链兑换。 |
详细脚本和参数:请参阅 references/funding-x-layer.md。
桥接缓冲。 增加 0.5% 的缓冲,以应对桥接费用。 报价约 60 秒后过期;如果广播前有延迟,请重新获取报价。
最低桥接金额建议。 如果资金缺口小于 $5,请补足至 $5,以分摊源链上的桥接 Gas 费用。
Gas 和路由注意事项
在继续充值前向用户说明以下事项;如果有任何一项适用,请先调用
AskUserQuestion(而不是显示 bash 提示)再进行操作:
- 用于同链兑换的 X Layer 上的 OKB。 OKX 只为中介方的结算转账提供 Gas 赞助。签名前在 X Layer 上进行的授权、兑换及其他链上操作,均由用户支付费用(在 X Layer 上使用 OKB,或在桥接环节使用源链的原生资产)。如果用户在 X Layer 上没有 OKB,且充值流程需要在 X Layer 上进行同链兑换,请向用户说明并先征求同意。在 OKX 确认更广泛的 Gas 赞助政策之前,请假设只有最终结算转账可获得赞助。
- 桥接目标代币。 如果资金流程的轮询循环结束后,钱包仍缺少
$X402_ASSET,请向用户提供源链交易哈希和 Across 浏览器链接。桥接可能交付了 X Layer 上的另一种代币变体(当前 Across 路径中较为罕见),也可能失败。v1.0.0 不会自动检测其他代币的到账情况;用户必须在链上核实。
第 4 阶段:EIP-3009 签名和 X-PAYMENT 提交
OKX 的 APP 即时支付使用 x402 的 "exact" 方案:付款方针对代币自身的 EIP-712 域,对
TransferWithAuthorization 类型数据消息进行签名。重试时,签名后的授权会通过
X-PAYMENT 标头传递;OKX 的促成方会在链上结算转账
(付款方在 X Layer 上无需支付 Gas)。
第 5 步:用户确认
本技能涉及的每一笔交易都必须单独通过
AskUserQuestion 关卡,资金筹措环节也不例外。
“资金筹措”并非单笔交易,而是由多笔交易组成,每一笔都
必须单独通过关卡。所需关卡及其通常触发的顺序如下:
- 源链上的 ERC-20 授权,授权给 Permit2 / Universal Router(仅当
tokenIn不是原生代币且授权额度不足时)。 - 源链上的同链兑换(例如,在 Ethereum 上将 UNI 兑换为 USDC),如果资金计划包含源链环节。
- 向跨链通道提交桥接(Across、OKX bridge 等)。如果桥接步骤由用户在本技能之外发起,则关卡问题改为:“你准备好离开本技能、执行桥接,并在资金到账 X Layer 后重新调用了吗?”。
- X Layer 上的同链兑换(例如,将 USDG 兑换为 USDT0),如果资金 计划包含目标链环节。
- 对 402 结算进行 EIP-3009
TransferWithAuthorization签名。
每个关卡都使用 AskUserQuestion Agent 工具(不要使用 read -p、
不要向 bash 提示符执行 echo,也不要在回复中打印“(是/否)”),并且在继续之前
等待用户回复。每个关卡向用户展示的摘要必须包含:
- 操作(授权、兑换、桥接、签署 EIP-3009 授权)。
- 金额和代币(兑换和桥接的输入和输出金额)。
- 源链和目标链(两者不同时)。
- 接收方(EIP-3009 步骤中的
payTo)。 - 支付所绑定的资源 URL。
- 预估 Gas(如适用)。
常见失败模式。 在回复中描述多步骤资金计划时,不要把多笔交易合并成一个确认问题,例如“是否继续进行资金筹措和付款?”每笔交易都必须在即将执行时单独通过关卡。事先一次性确认“是”并不代表用户同意之后的交易;这些交易执行时,用户还没有看到实际金额、Gas 和接收方。
每个关卡都必须获得明确确认。每个关卡彼此独立。 绝不要自动提交,即使用户之前已预先授权此会话、 调用或钱包。流程中较早时的“是”不能沿用;对多步骤计划回答“是”,也不代表对其中 每笔单独交易都回答了“是”。
响应中正确的确认门应是什么样子。 无论你是在实时执行此技能,还是以文本描述计划,每个交易步骤都必须以独立的、带标签的“确认门”区块呈现,并包含结构化摘要和明确的
AskUserQuestion调用。每个确认门都要照原样使用此模板。不要将确认门压缩成一行。不要用被动语态描述确认门(例如“我们将在签署前确认”)。应将确认门展示为一个独立操作。模板(每个确认门都要使用,即使只有一个):
### Confirmation Gate N: <Action name> | Field | Value | | ------------ | ---------------------------------------- | | Action | <approve / swap / bridge / sign EIP-3009>| | Amount in | <amount + symbol on source chain> | | Amount out | <amount + symbol on destination chain> | | Source chain | <chain name + id> | | Dest chain | <chain name + id> | | Recipient | <address> | | Resource URL | <url the payment is bound to> | | Est. gas | <amount + token> | Then call AskUserQuestion("Proceed with <action>?") and BLOCK on the user's reply. If anything other than an explicit "yes", stop and report.如果响应只列出字段,却没有
AskUserQuestion("Proceed?") + block步骤,就不算确认门,即使内容看起来很完整。将每个确认门命名为独立步骤,并在继续前等待用户回复。
哪些情况不算确认门。 输出一个 bash 脚本,在标准输出中打印
"⚠️ CONFIRMATION REQUIRED"和"(yes/no)",然后继续执行echo "Signing...",这不算确认门,因为无论用户输入什么,脚本都会继续执行。正确的确认门应使用AskUserQuestion工具(或者,若用户明确选择仅使用 shell 的模式,则使用实际阻塞的read -p,并在脚本中明确设置yes/no分支)。如有疑问,优先使用AskUserQuestion。
共享钱包的竞态问题。 如果钱包是共享的(例如,多个 Agent 同时使用同一密钥),余额可能会在检查余额与提交之间被耗尽。确认时也要重新检查
balanceOf。
步骤 6,签署并提交
关于域构造、nonce 生成、使用 viem 签署、载荷组装和重试的详细步骤,请参阅
references/app-x402-flow.md。重试时,如果质询中存在 accepts[].resource,则将其对应的 URL 作为目标;否则使用原始请求 URL。
域警告。
verifyingContract是代币合约,不是单独的验证器。使用质询extra字段中的name和version,不要假定默认值。不同代币的域值各不相同。域不正确会导致签名被 facilitator 拒绝,并再次返回 402。
extra.name的 UTF-8 必须逐字节精确匹配。 EIP-712 域哈希要求字节完全一致。extra中的name字段必须原样传递质询中的字节。不要对其进行规范化,不要将其转换为小写,不要用 ASCIIT(U+0054)替换 Unicode₮(U+20AE),也不要合并 Unicode 形式(NFC 与 NFD)。例如,质询返回"USD₮0"时,签名时必须使用"USD₮0";若将其读取为"USDT0",生成的签名将被 facilitator 拒绝,并再次返回 402。将extra.name的原始字节直接传入 EIP-712 域。
错误处理
| 情况 | 操作 |
|---|---|
402 挑战中没有 network 字段 | 检查挑战正文;如果 chainId 对应 196,则使用此技能;否则转交给 pay-with-any-token |
| 网络不是链 196 | 转交给 pay-with-any-token |
x402Version !== 1 | 明确拒绝;提示版本不匹配错误。此技能的 v1.0.0 仅针对 x402 v1。 |
accepts[].scheme !== "exact" | 明确拒绝;v1.0.0 仅支持 exact 方案。其他 x402 方案(upto、batch-settlement)不在支持范围内。 |
accepts[].maxAmountRequired === "0" | 明确拒绝,并指出商户配置错误。HTTP 402 要求正数付款;OKX 的 facilitator 不会结算零金额转账。不要签名,也不要将零金额解释为 ping、身份验证检查或免费套餐。 |
| APP 请求在 X Layer 上使用 USDC | 明确说明注意事项:USDC 在 X Layer 上没有可靠的 Uniswap v3 路由。建议直接从流动性充足的链(Base、Arbitrum、Mainnet)跨链转入 USDC,或询问 USDT0。 |
| X Layer 上资产不足 | 触发资金充值流程(阶段 3) |
| Trading API 返回 400 | 记录请求和响应;检查金额格式及地址校验和 |
| Trading API 返回 429 | 退避并使用指数延迟重试 |
| 报价已过期 | 重新获取报价;不要重复使用旧的 permitData |
| 跨链桥超时 | 检查 Across 跨链桥浏览器;不要重新提交 |
| EIP-3009 签名被拒(重试时返回 402) | 根据 extra 验证域的 name / version(逐字节精确匹配,包括任何非 ASCII 字符),检查 validBefore 是否仍有效,并确认 nonce 尚未使用 |
| 重试时金额不匹配 | 使用实际资产链上的 decimals() 重新计算基本单位;不要假定为 6 |
链上结算回滚(transferFrom 失败) | 在重试时重新检查 balanceOf;签名与提交之间余额可能已被转走(共享钱包、并发 Agent 或手动转账)。重试前向用户说明情况。 |
用户询问托管 / 会话 / 批处理 / upto | 说明此版本的技能仅涵盖即时付款(exact 方案)。其他功能不在 v1.0.0 的支持范围内;OKX 发布相关功能后,将在后续 v1.x 版本中跟进。 |
关键地址和参考资料
X Layer(链 196)
- 链 ID:
196 - 公共 RPC:
https://rpc.xlayer.tech - USDT0:
0x779Ded0c9e1022225f8E0630b35a9b54bE713736(精度 6) - USDG:
0x4ae46a509F6b1D9056937BA4500cb143933D2dc8(精度 6) - USDC:
0x74b7F16337b8972027F6196A17a631aC6dE26d22(精度 6,在 X Layer 上没有可靠的 Uniswap 路由; 请从流动性充足的链桥接) - WOKB(包装原生代币):
0xe538905cf8410324e03A5A23C1c177a474D59b2b(精度 18) - Uniswap V3 工厂合约:
0x4B2ab38DBF28D31D467aA8993f6c2585981D6804 - SwapRouter02:
0x4f0C28f5926AFDA16bf2506D5D9e57Ea190f9bcA - Universal Router 2.1:
0xDa00aE15d3A71466517129255255db7c0c0956d3 - QuoterV2:
0xD1b797D92d87B688193A2B976eFc8D577D204343 - Permit2:
0x000000000022D473030F116dDEE9F6B43aC78BA3 - USDT0/USDG 池:
0x0cBe0dBE1400e57f371a38BD3b9bC80F7C3676dA - USDT0/WOKB 池:
0x63d62734847E55A266FCa4219A9aD0a02D5F6e02
Uniswap Trading API
- 基础 URL:
https://trade-api.gateway.uniswap.org/v1 - 请求头:
x-api-key: $UNISWAP_API_KEY - 请求头:
x-universal-router-version: 2.1.1 - 支持的链包括 1、8453、42161、10、137、130、196 等 (请参阅 Trading API 支持链文档)。
X Layer 上的链上 Universal Router 合约标记为 2.1 (部署地址为上文的
0xDa00aE15d3A71466517129255255db7c0c0956d3)。Trading API 要求请求头的值为2.1.1,这是 API 内部使用的版本字符串,用于指向同一个 Universal Router 2.1 合约的路由路径。这两个版本字符串分别指代相关但不同的内容; 请勿用其中一个替换另一个。
OKX APP
- APP 概览 / 开发文档:
https://web3.okx.com/onchainos/dev-docs/payments/x402-introduction - OKX onchainos-skills 仓库:
https://github.com/okx/onchainos-skills - x402 规范:
https://github.com/coinbase/x402
相关技能
- pay-with-any-token,用于处理 X Layer 以外链上的 HTTP 402 挑战的同级技能(Ethereum、Base、 Arbitrum、Tempo 等)。对于非 X Layer 挑战,请使用该技能。
- swap-integration,完整的 Uniswap 兑换集成参考(Trading API、Universal Router、Permit2)。