跳转到主要内容

你需要做什么

  1. 获取收款地址(EIP-7702)
  2. 创建 PaymentRequirements
  3. 解析客户端 X-Payment,验证并结算
  4. 根据结果返回资源或标准 402

前置准备

  • Seller 接收地址:前往 app.x402x.ai 创建并获取(EIP-7702 部署地址)
  • Token 使用:
    • USD1(BSC):0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d
  • 安装依赖(服务端):
bun add x402x-server@beta x402x-facilitator@beta express viem

核心流程(服务端)

  • 常规
  • Express 中间件
  • Hono 中间件
创建 server.ts,核心逻辑如下:
const client = createPublicClient({ chain: bsc, transport: http() });

const facilitator = new Facilitator({
  recipientAddress: RECIPIENT_ADDRESS,
  waitUntil: "confirmed",
});

const server = new X402Server({ client, facilitator });

await server.initialize(["0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d"]);

const requirements = await server.createRequirements({
  asset: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", // USD1
  maxAmountRequired: parseEther("0.01").toString(),    // 0.01 USD1 (18 decimals)
  description: "Premium API",
  resource: req.url,
});

const result = await server.process(req.headers["x-payment"] as string, requirements);
if (!result.success) {
  // 解析/验证失败:返回标准 402;其他错误按需处理
  return res.status(result.status).json(result.response);
}

return res.json({ data, payer: result.data.payer, txHash: result.data.txHash });
import express from "express";
import { config } from "dotenv";
import { X402Server } from "x402x-server";
import { Facilitator } from "x402x-facilitator";
import { createPublicClient, http } from "viem";
import { parseEther } from "viem";
import { bsc } from "viem/chains";

config();

const app = express();
app.use(express.json());

const PORT = 3939;
const RECIPIENT_ADDRESS=0xSellerRecipientAddress;


async function main() {
  // 创建 viem client
  const client = createPublicClient({
    chain: bsc,
    transport: http(),
  });

  // 创建 facilitator
  const facilitator = new Facilitator({
    recipientAddress: RECIPIENT_ADDRESS,
    waitUntil: "confirmed",
  });

  // 创建 server
  const server = new X402Server({ client, facilitator });

  // 预检测当前 token 所支持的支付方案
  await server.initialize(["0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d"]);

  // 付费 API
  app.post("/api/data", async (req, res) => {
    try {
      // 创建支付要求(可根据业务动态调整金额/描述/资源等)
      const requirements = await server.createRequirements({
        asset: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d", // USD1
        maxAmountRequired: parseEther("0.01").toString(),    // 0.01 USD1
        description: "API access",
        resource: `http://localhost:${PORT}/api/data`,
      });

      // 处理支付
      const result = await server.process(
        req.headers["x-payment"] as string,
        requirements
      );

      if (!result.success) {
        return res.status(result.status).json(result.response);
      }

      // 支付成功,返回数据并可记录对账信息
      res.json({
        message: "Success!",
        data: "This is premium content",
        payer: result.data.payer,
        txHash: result.data.txHash,
      });
    } catch (error) {
      console.error("Error:", error);
      res.status(500).json({
        error: "Internal server error",
        message: error instanceof Error ? error.message : "Unknown error",
      });
    }
  });

  app.listen(PORT, () => {
    console.log(`✅ Server running on http://localhost:${PORT}`);
  });
}

main();

推荐做法

  • 预热检测缓存:启动时调用 server.initialize(tokens),缩短首次请求耗时
  • 快速模式:已知支付类型时可关闭自动检测(autoDetect: false
  • 固定价格复用:对定价接口缓存 requirements 并复用,减少创建开销
  • 错误分层:parse/verify → 返回 402;settle → 返回 500 并记录日志

常见集成模式

  • 固定价格 API:在应用启动时创建并缓存 requirements,请求时直接复用
  • 动态计价 API:按请求上下文计算 maxAmountRequireddescription
// 固定价格复用示例(启动时)
const cachedRequirements = await server.createRequirements({
  asset: "0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d",
  maxAmountRequired: parseEther("1").toString(),
  description: "Premium API (fixed price)",
  resource: "http://localhost:3000/api/data",
  mimeType: "application/json",
  maxTimeoutSeconds: 3600,
  network: "bsc",
});

// 请求时直接使用 cachedRequirements
const result = await server.process(req.headers["x-payment"] as string, cachedRequirements);

错误处理与返回

  • 解析/验证失败:直接返回标准 402(result.statusresult.response
  • 结算失败或内部异常:返回 500,并记录详细日志(含 payer/txHash 如有)

相关