nonce-manager

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Nonce Manager

Nonce管理器

Centralized nonce oracle for all Stacks blockchain transactions. Prevents mempool collisions when multiple skills send transactions concurrently or in rapid succession.
为所有Stacks区块链交易提供集中式随机数预言机。当多个skill同时或连续快速发送交易时,可防止内存池冲突。

Problem

问题

Each skill independently fetches nonce from Hiro API. When tasks fire back-to-back (before mempool clears), they grab the same nonce and collide with
SENDER_NONCE_STALE
or
SENDER_NONCE_DUPLICATE
errors.
每个skill独立从Hiro API获取nonce。当任务接连触发(内存池未清空时),它们会获取相同的nonce,进而触发
SENDER_NONCE_STALE
SENDER_NONCE_DUPLICATE
错误导致冲突。

Solution

解决方案

Single file-locked nonce state at
~/.aibtc/nonce-state.json
. Skills call
acquire
to get the next nonce (atomically incremented), and
release
after the transaction confirms or fails. If state is stale (>5 min), auto-resyncs from Hiro.
~/.aibtc/nonce-state.json
文件中存储单文件锁定的nonce状态。Skill调用
acquire
获取下一个nonce(自动原子递增),并在交易确认或失败后调用
release
。如果状态过期(超过5分钟),会自动从Hiro重新同步。

Subcommands

子命令

acquire

获取

Get the next nonce for a Stacks address. Atomically increments the stored value. Auto-syncs from Hiro if state is missing or stale (>5 min).
bun run nonce-manager/nonce-manager.ts acquire --address SP...
Output:
json
{ "nonce": 42, "address": "SP...", "source": "local" }
获取指定Stacks地址的下一个nonce。自动对存储值进行原子递增。如果状态缺失或过期(超过5分钟),会自动从Hiro同步。
bun run nonce-manager/nonce-manager.ts acquire --address SP...
输出:
json
{ "nonce": 42, "address": "SP...", "source": "local" }

release

释放

Mark a nonce as confirmed or failed after transaction outcome is known.
bun run nonce-manager/nonce-manager.ts release --address SP... --nonce 42
bun run nonce-manager/nonce-manager.ts release --address SP... --nonce 42 --failed
bun run nonce-manager/nonce-manager.ts release --address SP... --nonce 42 --failed --rejected
Failure kinds (critical distinction):
  • --rejected
    — tx never reached mempool (signing error, relay 409 nonce rejection). Nonce NOT consumed, safe to roll back and reuse.
  • --broadcast
    (default when
    --failed
    ) — tx reached mempool. Nonce IS consumed even if the tx fails on-chain. Do NOT roll back.
Only
--failed --rejected
triggers a rollback. Default
--failed
assumes broadcast (safer).
Output:
json
{ "address": "SP...", "nonce": 42, "action": "confirmed" }
在得知交易结果后,标记某个nonce为已确认或失败。
bun run nonce-manager/nonce-manager.ts release --address SP... --nonce 42
bun run nonce-manager/nonce-manager.ts release --address SP... --nonce 42 --failed
bun run nonce-manager/nonce-manager.ts release --address SP... --nonce 42 --failed --rejected
失败类型(关键区别):
  • --rejected
    — 交易从未进入内存池(签名错误、中继409 nonce拒绝)。该nonce未被消耗,可安全回滚并复用。
  • --broadcast
    --failed
    的默认值)— 交易已进入内存池。即使交易在链上失败,该nonce仍会被消耗。请勿回滚。
--failed --rejected
会触发回滚。默认的
--failed
假设交易已广播(更安全)。
输出:
json
{ "address": "SP...", "nonce": 42, "action": "confirmed" }

sync

同步

Force re-sync nonce state from Hiro API. Use after manual intervention or mempool clearance.
bun run nonce-manager/nonce-manager.ts sync --address SP...
Output:
json
{ "nonce": 42, "address": "SP...", "mempoolPending": 3, "lastExecuted": 41, "detectedMissing": [] }
强制从Hiro API重新同步nonce状态。在手动干预或内存池清空后使用。
bun run nonce-manager/nonce-manager.ts sync --address SP...
输出:
json
{ "nonce": 42, "address": "SP...", "mempoolPending": 3, "lastExecuted": 41, "detectedMissing": [] }

status

状态

Show current nonce state for one or all tracked addresses.
bun run nonce-manager/nonce-manager.ts status
bun run nonce-manager/nonce-manager.ts status --address SP...
显示一个或所有已追踪地址的当前nonce状态。
bun run nonce-manager/nonce-manager.ts status
bun run nonce-manager/nonce-manager.ts status --address SP...

Library Import

库导入

Skills running in the same process can import directly:
typescript
import { acquireNonce, releaseNonce, syncNonce } from "../nonce-manager/nonce-store.js";

const { nonce } = await acquireNonce("SP...");
// ... send transaction ...
await releaseNonce("SP...", nonce, true); // true = success
同一进程中运行的skill可直接导入:
typescript
import { acquireNonce, releaseNonce, syncNonce } from "../nonce-manager/nonce-store.js";

const { nonce } = await acquireNonce("SP...");
// ... 发送交易 ...
await releaseNonce("SP...", nonce, true); // true = 成功

Nonce Strategy

Nonce策略

  1. Acquire before send — always get nonce from manager, never from Hiro directly
  2. Release after confirm/fail — keeps state accurate for next caller
  3. Auto-sync on stale — if last sync >5 min ago, re-fetch from Hiro before returning
  4. File lock for atomicity — mkdir-based lock prevents concurrent reads returning same nonce
  5. Distinguish broadcast vs rejected — only rejected nonces can be rolled back
  1. 发送前获取 — 始终从管理器获取nonce,切勿直接从Hiro获取
  2. 确认/失败后释放 — 保持状态准确,供下一个调用者使用
  3. 过期自动同步 — 如果上次同步超过5分钟,返回前重新从Hiro获取
  4. 文件锁保证原子性 — 基于mkdir的锁可防止并发读取返回相同nonce
  5. 区分已广播与被拒绝 — 仅被拒绝的nonce可回滚

Integration with x402 Error Codes

与x402错误码的集成

Per landing-page#522, map relay error codes to release actions:
Relay ResponseRelease Action
201
(success or pending)
release --address ... --nonce N
(success)
409 SENDER_NONCE_DUPLICATE
release --address ... --nonce N --failed --broadcast
(nonce in mempool)
409 SENDER_NONCE_STALE
release --address ... --nonce N --failed --rejected
+ re-sync
409 SENDER_NONCE_GAP
release --address ... --nonce N --failed --rejected
+ re-sync
409 NONCE_CONFLICT
release --address ... --nonce N --failed --broadcast
(retry same signed tx)
502/503
relay error
release --address ... --nonce N --failed --rejected
(never broadcast)
根据landing-page#522,将中继错误码映射到释放操作:
中继响应释放操作
201
(成功或待处理)
release --address ... --nonce N
(成功)
409 SENDER_NONCE_DUPLICATE
release --address ... --nonce N --failed --broadcast
(nonce已在内存池)
409 SENDER_NONCE_STALE
release --address ... --nonce N --failed --rejected
+ 重新同步
409 SENDER_NONCE_GAP
release --address ... --nonce N --failed --rejected
+ 重新同步
409 NONCE_CONFLICT
release --address ... --nonce N --failed --broadcast
(重试同一签名交易)
502/503
中继错误
release --address ... --nonce N --failed --rejected
(从未广播)