Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
集成与开发阅读约 11 分钟

加密货币网关:架构、集成与验证

一份技术指南,介绍加密货币支付网关在底层如何运作、如何安全地集成网关,以及如何根据链上数据验证结算与对账。

TL;DR

加密货币网关是位于商家结账系统与公共区块链之间的服务层:它创建支付意图、监控地址以接收入账转账、应用确认与风险规则,并以加密货币或法币向商家结算价值。本文解释该流程背后的架构,展示如何通过 API 和 webhook 集成网关,并提供可复现的流程来验证所报告的支付确实存在于链上。它将网关的文档化行为与设计建议以及你必须针对自己的提供商和节点运行的测量区分开来。目标是构建一个可审计的结账流程,而不仅仅是能渲染二维码的流程。

加密货币网关的实际作用

加密货币网关是数字资产的支付处理器。在结账时,系统会向客户报出以特定代币或通证计价的价格,通常由法币价格换算而来,并设有较短的有效期。网关分配一个存款地址或支付意图,监控链上是否有匹配的转账,应用确认阈值和风险检查,然后要么将款项记入商家的网关余额,要么触发结算至银行账户或稳定币钱包。

重要的心智模型是:网关并不通过卡组织网络转移资金。价值以普通链上交易的形式转移到网关控制的地址。其他一切——发票、汇率、webhook、账本条目——都是叠加在这些转账之上的记账工作。这一区别很重要,因为它告诉你故障可能发生在哪里:webhook 可能延迟或重复,而链上转账是最终的;网关账本可能有误,而链上记录是正确的。

网关是可选的。商家可以直接接受加密货币到自托管钱包,但那样就需要自行负责地址管理、价格报价、确认策略、会计和退款。网关以费用、托管或结算条款以及对第三方正常运行时间的依赖为代价,免除了大部分运营工作。

  • 支付意图:将订单与金额、资产、地址和有效期关联起来的发票记录。
  • 链上监控器:扫描区块以查找向网关控制地址转账的服务。
  • 确认策略:在支付被视为已结算之前必须经过的区块数或最终性条件。
  • 结算:以加密货币或法币将价值转换并转移给商家。
  • 对账:将网关账本条目与链上交易及你自己的订单记录进行匹配。

集成前的假设与前提条件

本指南假设你已有带服务器端组件的结账或订单系统、可用于存储支付状态的数据库,以及接收 HTTPS 回调的能力。你应当了解打算接受哪些资产和网络,因为一条链上的 USDT 支付与另一条链上的 USDT 并非相同的集成:地址格式、确认行为和费用经济性都不同。

你还需要一种独立于网关读取链上数据的方式。这正是 RPC 提供商的用武之地。网关告诉你它认为发生了什么;RPC 端点让你确认链上实际记录了什么。OnFinality 的多链 RPC 端点可以承担这一验证角色,支持的网络列表告诉你哪些链可用。如果你预计验证流量会持续较高,请查看专用节点选项,而不是假设共享公共容量足够。

最后,在编写代码之前确定你的结算模型。托管式自动转换为法币、稳定币结算和直接加密货币结算会产生不同的账本形态和不同的对账步骤。

从结账到结算的支付流程

典型的网关流程有六个阶段。第一,你的服务器通过网关 API 创建支付或发票,传入订单 ID、金额、货币和回调 URL。第二,网关返回支付标识符、存款地址、确切的加密货币金额、汇率和到期时间。第三,你的结账页面显示这些信息,通常以二维码加可复制的地址和金额的形式呈现。

第四,客户广播转账。第五,网关的链上监控器检测到转账,等待其确认策略,并将支付标记为已确认或部分支付。第六,网关向你的回调 URL 发送签名 webhook 并更新其账本。向你结算按照网关的时间表进行,可能是每笔支付立即结算、批量结算或按需结算。

两个细节导致了大多数集成缺陷。报价的加密货币金额有时间限制,因此在到期后发送的支付相对于新汇率可能不足额。并且金额在考虑网络费用后必须完全匹配,网络费用通常由发送方额外支付;如果客户从转账中扣除费用,就会产生短缺,网关会报告为部分支付。

通过网关 API 创建支付意图

确切的端点和字段名称因提供商而异,因此请将以下内容视为一种形态而非规范。务必对照你提供商当前的 API 参考进行确认。模式是一致的:使用保存在服务器端的 API 密钥进行认证,创建发票,持久化返回的标识符和地址,并且永远不要信任客户端提供的金额。

下面的 curl 示例使用网关基础 URL 和凭据的占位符。请从服务器环境而非浏览器运行它,并将响应体与你的订单 ID 一起记录,以便日后对账。

curl -X POST "$GATEWAY_BASE_URL/v1/payments" \
  -H "Authorization: Bearer $GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "order_1042",
    "price_amount": 49.00,
    "price_currency": "USD",
    "pay_currency": "USDT",
    "network": "ETH",
    "callback_url": "https://merchant.example.com/webhooks/gateway",
    "success_url": "https://merchant.example.com/checkout/success"
  }'

幂等地处理 webhook

Webhook 是网关的通知渠道,但它们不保证只到达一次、按顺序到达或一定到达。你的处理程序必须验证签名,通过网关标识符查找支付,并且仅在状态向前推进时才应用状态转换。存储原始负载及其哈希,以便检测重复投递。

下面的 JavaScript 草图展示了关键防护:验证、去重、然后转换。它故意不包含提供商特定的签名逻辑,因为这取决于网关文档化的方案。

import crypto from "node:crypto";

// Verify signature per your gateway's documented scheme.
function verify(rawBody, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

async function handleWebhook(req, res) {
  const raw = req.rawBody; // preserve the unparsed body
  if (!verify(raw, req.headers["x-gateway-signature"], process.env.GATEWAY_WEBHOOK_SECRET)) {
    return res.status(401).end();
  }
  const event = JSON.parse(raw);
  const payment = await db.payments.findByGatewayId(event.payment_id);
  if (!payment) return res.status(404).end();

  const seen = await db.webhookEvents.exists(event.event_id);
  if (seen) return res.status(200).end();

  await db.transaction(async (tx) => {
    await tx.webhookEvents.insert({ id: event.event_id, payload: raw });
    if (event.status === "confirmed" && payment.status !== "paid") {
      await tx.payments.markPaid(payment.id, event.txid);
    }
  });
  return res.status(200).end();
}

根据链上数据验证所报告的支付

Webhook 是一种声明。在发货或释放超过风险阈值的资金之前,请根据你控制的 RPC 端点确认该声明。流程是:按哈希获取交易,检查交易是否成功,检查接收方是否与存款地址匹配,检查转账金额和资产,并检查确认深度。

下面的 Python 示例通过 HTTP 使用 JSON-RPC,并带有占位符 RPC_URL。它针对 EVM 风格链和原生价值转账编写;代币转账需要解码日志或改为调用代币合约的 transfer 事件。请根据你接受的链调整资产检查。

import os, requests

RPC_URL = os.environ["RPC_URL"]

def rpc(method, params):
    r = requests.post(RPC_URL, json={"jsonrpc":"2.0","id":1,"method":method,"params":params}, timeout=10)
    r.raise_for_status()
    body = r.json()
    if "error" in body:
        raise RuntimeError(body["error"])
    return body["result"]

def verify_payment(tx_hash, expected_to, expected_wei, min_confirmations):
    tx = rpc("eth_getTransactionByHash", [tx_hash])
    receipt = rpc("eth_getTransactionReceipt", [tx_hash])
    if tx is None or receipt is None:
        return {"ok": False, "reason": "not_found"}
    if receipt["status"] != "0x1":
        return {"ok": False, "reason": "reverted"}
    if tx["to"].lower() != expected_to.lower():
        return {"ok": False, "reason": "wrong_recipient"}
    if int(tx["value"], 16) < expected_wei:
        return {"ok": False, "reason": "underpaid"}
    head = int(rpc("eth_blockNumber", []), 16)
    depth = head - int(receipt["blockNumber"], 16) + 1
    return {"ok": depth >= min_confirmations, "depth": depth}

测量确认延迟与 webhook 延迟

网关仪表板很少发布你实际会遇到的延迟,因为它取决于你的链、你的确认策略以及当时的网络状况。请自行测量。对于每笔测试支付,记录四个时间戳:发票创建时间、交易首次出现在区块中的时间、网关将其标记为已确认的时间,以及你的 webhook 处理程序收到事件的时间。

针对你计划接受的每种资产和网络,至少运行二十笔测试支付,分散在一天中的不同时段。计算链上包含时间和 webhook 延迟的中位数和第 95 百分位数。不要发布或依赖来自其他商家环境的数字;出块时间和提供商行为会变化。

将结果记录在如下表格中,填入你自己的测量值。列结构是交付物;数值由你生成。

  • 列:资产、网络、确认阈值、包含时间中位数、包含时间 p95、webhook 延迟中位数、webhook 延迟 p95、样本量。
  • 排除从未广播或费用不足的测试支付。
  • 在网关套餐变更、链升级或确认策略变更后重新运行测量。

排查常见的集成故障

大多数故障属于少数几类,每类都有诊断路径。从链向外排查:确认转账存在,然后确认网关看到了它,再确认你的系统记录了它。

如果客户声称已付款但发票显示待处理,请索取交易哈希并根据你的 RPC 端点验证。向错误地址的转账、在错误网络上的转账或错误资产的转账将不会入账。如果交易正确且已确认但网关未更新,问题在网关侧或其确认策略中;检查其状态页面和支持渠道。

如果网关显示已确认但你的订单未支付,webhook 很可能未通过签名验证、到达了返回错误的端点或被丢弃。通过按计划轮询网关的支付状态端点来对账未结发票,并将轮询视为后备手段而非 webhook 的替代品。

  • 不足额支付:客户扣除了网络费用或在报价过期后发送。
  • 错误网络:不同链上的相同资产符号,没有网关支持则无法恢复。
  • 重复入账:webhook 处理程序非幂等,或重试被应用了两次。
  • 签名不匹配:原始负载在验证前被框架的 JSON 解析器修改。
  • 卡在待处理:未达到确认阈值,或链重组回滚了区块。

结算模型及其权衡

托管式自动转换在网关处将每笔支付结算为法币或稳定币,消除了价格风险,但增加了交易对手和监管依赖。网关短暂持有资金,应用其转换率,并按计划支付。你的账本记录法币金额,对账将网关对账单与银行或稳定币收款进行比较。

稳定币结算将价值保持在链上锚定美元的资产中,适合已经在加密货币中运营但仍希望避免波动性的企业。直接加密货币结算以收到的资产向你支付,这意味着你承担支付与转换之间的价格风险,并且必须管理自己的资金。

自托管接受方式,即你自己生成地址并监控链,提供最大控制权且无网关费用,但需要你运行或租用可靠的基础设施、实施确认策略并手动处理退款。对于有工程能力的高交易量商家来说,这是一个合理的选择;对于大多数其他商家,网关加上独立的链上验证是务实的中间路线。

局限性、合规以及上线前需要验证的事项

网关在因司法管辖区而异的许可制度下运营,其支持的资产、结算货币和 KYC 要求也相应不同。确认你的提供商获得许可为你客户和你自己的司法管辖区提供服务,并且其条款允许你的业务类别。本文不提供法律建议;将许可视为一个采购问题,需有书面答案。

从技术上讲,没有网关能消除链上风险。重组、区块空间拥堵和费用飙升都会影响确认时间。你的确认阈值应反映风险价值:小额数字购买可能只需一次确认,而大额转账可能需要更深的阈值或具有最终性的链。

上线前,端到端验证四件事:成功的支付恰好入账订单一次;失败或回滚的交易不入账;重复的 webhook 不会重复入账;存在你的支持团队可以执行的退款路径。这些中的每一项都应该是你暂存环境中的可重复测试。

生产就绪集成的后续步骤

首先在网关集成的同时构建验证层,而不是之后。一个接收交易哈希并返回验证状态的小型服务,由你控制的 RPC 端点支持,为你提供独立的真相来源,用于支持、对账和欺诈审查。OnFinality 的 RPC API 服务和网络覆盖是起点;查看 RPC 定价以估算验证流量,如果你需要可预测的吞吐量,请考虑专用节点。

如果你仍在为验证层选择端点或提供商,RPC Assistant 的 RPC 端点指南解释了权衡,多链 RPC 端点指南涵盖了跨多条链的运营。对于构建更广泛 Web3 基础设施的团队,Web3 项目最佳 RPC 提供商比较是一个有用的补充。

然后对流程进行埋点:使用共享关联 ID 记录每次发票创建、webhook 接收和验证结果。运行上述延迟测量,为每种资产设置确认阈值,并安排每季度在网关对账单、链上记录和你自己的账本之间进行对账。这种组合——用于支付体验的网关和你自己的链上读取作为真相——正是使加密货币网关集成可审计的关键。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始