跳转到主要内容

概述

x402x-fetch 扩展原生 fetch,当遇到 HTTP 402 (Payment Required) 时,自动解析服务端返回的支付要求、创建签名(Permit / EIP-3009 / Permit2),并携带 X-Payment 头重试原请求。

核心特性

  • ✅ 无缝集成:兼容原生 fetch API
  • 🔐 多种授权:EIP-3009 / EIP-2612 Permit / Permit2
  • 🌐 多链支持:内置常见 EVM 链,支持自定义
  • 🛡️ 安全保护:最大金额上限、签名校验

安装与依赖

npm i x402x-fetch viem
依赖(版本示例):
{
  "viem": "^2.21.26",
  "zod": "^3.24.2",
  "x402x": "workspace:^"
}

快速开始

一行包装

import { wrapFetchWithPayment } from "x402x-fetch";
const fetchWithPay = wrapFetchWithPayment(fetch, walletClient, "1000000");

完整示例

import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { wrapFetchWithPayment } from "x402x-fetch";
import { bscTestnet } from "viem/chains";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const client = createWalletClient({ account, transport: http(), chain: bscTestnet });

// 最多支付 10 USDC(6 位小数)
const fetchWithPay = wrapFetchWithPayment(fetch, client, "10000000");

const response = await fetchWithPay("https://api.example.com/premium", { method: "GET" });
const data = await response.json();
console.log("✅", data);

参数说明

  • walletClient:用于签名
  • maxValue:最大允许支付金额(强烈建议设置)
  • paymentRequirementsSelector:多选项时自定义选择

工作流程

1) 请求付费资源
2) 收到 402 响应(包含 x402Version 与 accepts 列表)
3) 选择/校验支付要求(金额 ≤ maxValue)
4) 生成 X-Payment 头(签名)
5) 携带支付头自动重试原请求
6) 返回 200 与数据(服务端校验并结算)

典型用途

  • 访问付费 API / 内容
  • 多端一致体验(浏览器 / Node)

API 参考(精简)

function wrapFetchWithPayment(
  fetch: typeof globalThis.fetch,
  walletClient: WalletClient,
  maxValue?: string,
  paymentRequirementsSelector?: (response: Response402) => PaymentRequirements
): typeof globalThis.fetch
支持的 paymentTypeeip3009 | permit | permit2

多链支持

你可以直接使用链名称 / viem Chain 对象 / 自定义配置来创建签名器:
import { createEvmSigner, wrapFetchWithPayment } from "x402x-fetch";
import { polygon } from "viem/chains";

// 链名称
const signer1 = createEvmSigner("bsc-testnet", "0xYourPrivateKey");

// viem Chain
const signer2 = createEvmSigner(polygon, "0xYourPrivateKey");

// 自定义
const signer3 = createEvmSigner({ chainId: 56, name: "BSC", rpcUrl: "https://rpc" }, "0xKey");

const fetchWithPay = wrapFetchWithPayment(fetch, signer1);

使用示例

GET

const res = await fetchWithPay("https://api.example.com/premium-data");
const data = await res.json();

POST(带 body)

const res = await fetchWithPay("https://api.example.com/compute", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ complexity: 10 }),
});

自定义 Headers

await fetchWithPay("https://api.example.com/data", {
  headers: {
    Authorization: "Bearer token",
    "X-Custom": "value",
  },
});

错误处理与金额保护

const fetchPay = wrapFetchWithPayment(fetch, client, "1000000");
try {
  const res = await fetchPay("https://api.example.com/data");
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();
} catch (e) {
  if (e instanceof Error && e.message.includes("exceeds maximum")) {
    // 服务器要求金额超过上限
  }
}

读取支付响应头

const res = await fetchWithPay("https://api.example.com/premium");
const header = res.headers.get("X-Payment-Response");
if (header) {
  const info = JSON.parse(Buffer.from(header, "base64").toString());
  console.log(info.transactionHash, info.payer);
}

最佳实践

  • 为生产设置合理的 maxValue
  • 统一封装日志与错误分类,便于排障
  • 浏览器环境请走钱包连接(不要暴露私钥)

相关资源

  • 源代码:https://github.com/WTFLabs-WTF/x402x/tree/main/typescript/packages/x402x-fetch
  • 问题反馈:https://github.com/WTFLabs-WTF/x402x/issues