StableOps
概念

Confirmations

detected / confirmed / finalized / reverted 的语义。

链上确认(confirmation)是交易逐步变得不可逆的过程。StableOps 把支付追踪划分成四个 阶段,在速度与安全之间做平衡。

总览

链上发起一笔支付后,它会经过几个阶段才算最终化:

DETECTED → CONFIRMED → FINALIZED
   ↓           ↓
REVERTED    REVERTED

每个阶段代表不同的可靠度:

  • DETECTED:在链上看到交易(0 确认)
  • CONFIRMED:达到该链所需的确认数
  • FINALIZED:达到 finality,不可逆
  • REVERTED:因重组或失败被回滚

为什么需要确认

区块链是分布式系统,多个节点竞争出块,这导致:

  • 链重组(reorg):竞争链超过当前链,最近的区块被替换
  • 交易失败:合约执行失败、Gas 不足等
  • 双花尝试:恶意方试图回滚交易

「确认」就是把交易埋到足够深,使反转在算力上几乎不可能。

各确认阶段

DETECTED(0 确认)

交易已经广播,要么在 mempool 中,要么进了最新一个区块。

可靠度:低(5–10%)

风险

  • 交易可能被 RBF 替换
  • 区块可能在重组中被孤立
  • 合约执行可能失败

做什么

  • UI 切到「已收到,确认中…」
  • 订单标记为「待确认」
  • 此时不要履约

示例

// Webhook: payment.detected
{
  "type": "payment.detected",
  "data": {
    "payment_order_id": "po_abc123",
    "from_status": "created",
    "to_status": "detected",
    "reason": "deposit_detected",
    "normalized_event_id": "evt_abc123",
    "amount": "10.00",
    "settlement_asset": "USDC",
    "metadata": {}
  }
}

CONFIRMED(达到链特定确认数)

交易已经达到该链所需确认数。

可靠度:高(95–99%)

各链确认数要求

确认数时间说明
Base2 块~4 秒OP rollup,回滚风险低
Ethereum6 块~1.2 分钟交易所标准
Arbitrum1 块~0.3 秒OP rollup
Polygon20 块~40 秒重组风险较高
TRON1 块~3 秒DPOS

风险

  • 理论上仍可能深度重组
  • 实际极罕见(< 0.01%)

适用

  • 小额(< $100)
  • 数字商品交付
  • 账户积分
  • 对时延敏感的履约

示例

// Webhook: payment.confirmed
{
  "type": "payment.confirmed",
  "data": {
    "payment_order_id": "po_abc123",
    "from_status": "detected",
    "to_status": "confirmed",
    "reason": "confirmations_reached",
    "normalized_event_id": "evt_abc123",
    "amount": "10.00",
    "settlement_asset": "USDC",
    "metadata": {}
  }
}

FINALIZED(达到 finality)

达到 finality,任何情况都不可逆。

可靠度:绝对(100%)

各链 finality 要求

finality时间机制
Base18 块~36 秒L1 finality
Ethereum64 块~13 分钟Casper FFG
Arbitrum20 块~5 秒L1 finality
Polygon128 块~4.3 分钟Checkpoint finality
TRON19 块~1 分钟DPOS finality

风险:无

适用

  • 大额(> $100)
  • 实物发货
  • 不可逆操作(账户升级、订阅)
  • 生产环境所有履约推荐用 finalized

示例

// Webhook: payment.finalized
{
  "type": "payment.finalized",
  "data": {
    "payment_order_id": "po_abc123",
    "from_status": "confirmed",
    "to_status": "finalized",
    "reason": "finality_reached",
    "normalized_event_id": "evt_abc123",
    "amount": "10.00",
    "settlement_asset": "USDC",
    "metadata": {}
  }
}

REVERTED(交易回滚)

交易被回滚,可能因为链重组或执行失败。

原因

  • 链重组:竞争链变长
  • 执行失败:合约执行失败
  • Gas 不足:交易耗尽 Gas
  • Receipt 丢失:交易从链上消失

频率:极罕见(< 0.01%)

发生后

  1. StableOps 检测到重组或失败
  2. 订单状态变为 REVERTED
  3. 派发 payment.reverted
  4. 地址释放回地址池(变回 AVAILABLE 供复用)

示例

// Webhook: payment.reverted
{
  "type": "payment.reverted",
  "data": {
    "payment_order_id": "po_abc123",
    "from_status": "confirmed",
    "to_status": "reverted",
    "reason": "blockchain_reorg",
    "normalized_event_id": "evt_abc123",
    "amount": "10.00",
    "settlement_asset": "USDC",
    "metadata": {}
  }
}

处理方式

app.post('/webhooks/stableops', async (req, res) => {
  const event = req.body

  if (event.type === 'payment.reverted') {
    const orderId = event.data.payment_order_id

    // 1. 冲销已经做的履约
    await reverseOrderFulfillment(orderId)

    // 2. 通知客户
    await sendEmail(customer, '支付失败,请重试')

    // 3. 更新数据库
    await db.orders.update({
      id: orderId,
      status: 'payment_failed',
      reason: event.data.reason
    })

    // 4. 可选:创建新订单
    const newOrder = await stableops.paymentOrders.create({
      merchantOrderId: `${orderId}_retry`,
      amount: originalAmount,
      // ...
    })
  }

  res.sendStatus(200)
})

选择合适的确认级别

决策矩阵

金额类型推荐阶段原因
< $10数字商品CONFIRMED快、风险低
$10 – $100数字商品CONFIRMED平衡速度与安全
$100 – $1,000数字商品FINALIZED需要更高安全
> $1,000任意FINALIZED最高安全
任意实物FINALIZED发货不可逆
任意账户升级FINALIZED操作不可逆
任意订阅FINALIZED周期性扣费

风险偏好

低容忍(金融服务、高价值商品):

  • 一律等 FINALIZED
  • 绝不在 DETECTED 履约
  • 额外加风控

中等容忍(电商、SaaS):

  • $100 等 FINALIZED

  • < $100 用 CONFIRMED
  • DETECTED 只用于刷新 UI

高容忍(游戏、低价值数字商品):

  • 大多数交易用 CONFIRMED
  • 账户变更用 FINALIZED
  • 接受偶发回滚

监控确认数

实时推送

StableOps 持续监听链上,确认数每次跨阈值都会推送 Webhook:

// 一笔支付的事件时间线
12:00:00 - payment.detected
12:00:12 - payment.confirmed
12:13:00 - payment.finalized

轮询替代方案

如果你倾向轮询:

const checkPaymentStatus = async (orderId: string) => {
  const order = await stableops.paymentOrders.retrieve(orderId)

  switch (order.status) {
    case 'detected':
      console.log('已收到,等待确认...')
      break
    case 'confirmed':
      console.log('已确认,等待 finality...')
      break
    case 'finalized':
      console.log('已 finalize,可安全履约')
      await fulfillOrder(order)
      break
    case 'reverted':
      console.log('已回滚,处理失败流程')
      await handleRevert(order)
      break
  }
}

// 每 5 秒轮询
const interval = setInterval(() => checkPaymentStatus(orderId), 5000)

链重组

什么是重组

竞争链超过当前链,导致最近的区块被替换:

重组前:
Block 100 → Block 101 → Block 102 (你的交易)
                     ↘ Block 102' (竞争链)

重组后:
Block 100 → Block 101 → Block 102' → Block 103'
                     ✗ Block 102 (被孤立)

各链重组频率

重组深度频率备注
Ethereum1–2 块每天通常无害
Ethereum> 3 块罕见需要调查
Base1 块偶发L2 重组少
Polygon1–5 块较常见重组风险高
TRON1 块罕见DPOS

StableOps 如何处理重组

  1. 持续监听:每次确认都比对 blockHash
  2. 检测重组blockHash 不一致 → 视为重组
  3. 状态更新:订单切到 REVERTED
  4. 派发 Webhook:发送 payment.reverted
  5. 释放地址:地址释放回地址池(变回 AVAILABLE

重组防护

StableOps 多层防护:

  • Block hash 校验:比对存储的 blockHash 与当前链
  • Receipt 校验:确认 receipt 仍然存在
  • 确认数计数:只统计 canonical chain
  • finality 追踪:等到各链的 finality 保证

最佳实践

1. 关键履约用 FINALIZED

// ✅ 正确 —— 等 finality
app.post('/webhooks/stableops', async (req, res) => {
  const event = req.body

  if (event.type === 'payment.finalized') {
    await fulfillOrder(event.data.payment_order_id)
  }

  res.sendStatus(200)
})

// ❌ 错误 —— 在 detected 就履约
app.post('/webhooks/stableops', async (req, res) => {
  const event = req.body

  if (event.type === 'payment.detected') {
    await fulfillOrder(event.data.payment_order_id)  // 危险!
  }

  res.sendStatus(200)
})

2. 处理所有状态

const handlePaymentWebhook = async (event: WebhookEvent) => {
  switch (event.type) {
    case 'payment.detected':
      await updateUI('已收到,确认中…')
      break
    case 'payment.confirmed':
      await updateUI('已确认,最终化中…')
      break
    case 'payment.finalized':
      await fulfillOrder(event.data.payment_order_id)
      break
    case 'payment.reverted':
      await handleRevert(event.data.payment_order_id)
      break
  }
}

3. 向用户展示进度

const PaymentStatus = ({ order }) => {
  switch (order.status) {
    case 'detected':
      return (
        <div>
          <Spinner />
          <p>已收到,确认中…</p>
        </div>
      )
    case 'confirmed':
      return (
        <div>
          <Spinner />
          <p>已确认,最终化中…</p>
        </div>
      )
    case 'finalized':
      return (
        <div>
          <CheckIcon />
          <p>支付完成!订单正在处理。</p>
        </div>
      )
  }
}

4. 详尽日志

app.post('/webhooks/stableops', async (req, res) => {
  const event = req.body

  await db.webhookLogs.create({
    type: event.type,
    orderId: event.data.payment_order_id,
    fromStatus: event.data.from_status,
    toStatus: event.data.to_status,
    timestamp: new Date(),
  })

  // 业务处理...

  res.sendStatus(200)
})

5. 测试重组场景

describe('支付重组处理', () => {
  it('应在重组时冲销履约', async () => {
    // 1. 创建订单
    const order = await createOrder()

    // 2. 模拟 detected
    await handleWebhook({ type: 'payment.detected', data: order })

    // 3. 模拟 confirmed
    await handleWebhook({ type: 'payment.confirmed', data: order })

    // 4. 模拟回滚
    await handleWebhook({ type: 'payment.reverted', data: order })

    // 5. 验证已冲销
    const dbOrder = await db.orders.findOne({ id: order.id })
    expect(dbOrder.status).toBe('payment_failed')
  })
})

常见模式

分级履约

不同确认阶段提供不同权益:

app.post('/webhooks/stableops', async (req, res) => {
  const event = req.body
  const orderId = event.data.payment_order_id

  switch (event.type) {
    case 'payment.confirmed':
      // 临时权益
      await grantTrialAccess(orderId)
      break

    case 'payment.finalized':
      // 完整权益
      await grantFullAccess(orderId)
      break

    case 'payment.reverted':
      // 全部撤销
      await revokeAccess(orderId)
      break
  }

  res.sendStatus(200)
})

按金额条件履约

不同金额取不同确认级别:

const shouldFulfill = (order: PaymentOrder): boolean => {
  const amount = parseFloat(order.amount)

  if (amount < 100) {
    // 小额:confirmed 即可
    return order.status === 'confirmed' || order.status === 'finalized'
  } else {
    // 大额:等 finalized
    return order.status === 'finalized'
  }
}

下一步

本页内容