Skip to content

fix: allow null txHash in SettleResult for already-settled retries#165

Merged
badjer merged 1 commit intomainfrom
fix/settle-result-nullable-txhash
Apr 16, 2026
Merged

fix: allow null txHash in SettleResult for already-settled retries#165
badjer merged 1 commit intomainfrom
fix/settle-result-nullable-txhash

Conversation

@badjer
Copy link
Copy Markdown
Contributor

@badjer badjer commented Apr 16, 2026

Summary

Loosens SettleResult.txHash from string to string | null, adds an optional alreadySettled flag, and updates the two log interpolations that reference txHash to render <already-settled> when it's null.

Why

A companion auth PR (circuitandchisel/auth#new) adds a carve-out on POST /settle/x402 that returns 200 OK with { alreadySettled: true, txHash: null, ... } when the CDP facilitator reports duplicate transaction on a retry of an already-settled payload. Today SettleResult.txHash is typed as non-nullable string, which would be a lie the moment that auth change ships.

Nothing in the SDK reads txHash beyond two logger.info template-string interpolations (protocol.ts:233, atxpExpress.ts:153), so runtime behavior is unchanged on the happy path. This PR just tells the truth at the type layer and makes the log line render nicely when it's null.

What changed

  • packages/atxp-server/src/protocol.tsSettleResult.txHash: stringstring | null, add optional alreadySettled?: boolean, and update log interpolation to ${result.txHash ?? '<already-settled>'}.
  • packages/atxp-express/src/atxpExpress.ts — same log-interpolation nil-coalesce on the middleware's txHash=... log line.
  • packages/atxp-server/src/protocol.test.ts — one new test: auth returns { txHash: null, alreadySettled: true, ... }, SDK surfaces it as-is without crashing.

Ordering / deploy safety

  • SDK-first deploy (this PR first, auth second): SDK types allow null but auth never returns null yet — safe.
  • Auth-first deploy (auth PR first, SDK still on 0.11.8): auth returns txHash: null, SDK's old type casts as SettleResult — JS runtime is fine (${null} renders as "null", ugly but no crash), the only consumers are log lines. Also safe.
  • Either order works; no coordinated release needed.

Test plan

  • npx vitest run src/protocol.test.ts (atxp-server) — 26 passed (25 original + 1 new)
  • npx vitest run (atxp-express) — 45 passed
  • Typecheck clean in main checkout for both packages
  • Lint clean on changed files
  • Full CI green

🤖 Generated with Claude Code

Auth is adding a carve-out on /settle/x402 that returns 200 with
{ alreadySettled: true, txHash: null, ... } when the CDP facilitator
rejects a retry with "duplicate transaction" (see auth PR for details).
The SDK's SettleResult.txHash was typed as string (non-nullable), which
would be a lie the moment that auth change ships.

Loosen the type to string | null, add an optional alreadySettled flag,
and update the two log interpolations in protocol.ts and atxpExpress.ts
to render "<already-settled>" when txHash is null instead of the word
"null". Behavior on the happy path (txHash: string) is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@badjer badjer merged commit 3ac565a into main Apr 16, 2026
1 check passed
@badjer badjer deleted the fix/settle-result-nullable-txhash branch April 16, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant