Skip to content

fix(x402): exclude stacked STX from balance checks; check inbox and news payments - #436

Merged
biwasxyz merged 1 commit into
mainfrom
fix/x402-balance-followups
Oct 8, 2026
Merged

biwasxyz merged 1 commit into
mainfrom
fix/x402-balance-followups

Conversation

@biwasxyz

Copy link
Copy Markdown
Contributor

Why

Follow-ups from #435, plus two bugs found while getting the full test suite to finish.

What

  • Stacked STX. Hiro's stx.balance includes STX locked in stacking, which a transfer cannot move. New spendableStx() subtracts locked; the sponsored check (fix(x402): refuse sponsored payments the wallet cannot cover before signing #435) and the direct-mode gas/price check both use it. Before this, a wallet with mostly stacked STX passed the check and failed at settlement.
  • Inbox and news payments. inbox send and aibtc-news file-signal build their own sponsored sBTC transfers outside the engine. Both now call checkSponsoredPaymentBalance before signing.
  • Bug: aibtc-news file-signal could not pay. It imported getAccount from wallet-manager, which does not export it, so the paid path threw getAccount is not a function. It went unnoticed because tsc only covers src/. Now imported from x402.service, like inbox does.
  • Bug: Bun connection errors were treated as ambiguous. Bun's fetch-backed axios adapter reports a refused connection and a failed DNS lookup as ConnectionRefused, not ECONNREFUSED/ENOTFOUND. requestWasNeverSent did not recognise it, so in direct mode a paid request that never left the machine was reported as "Settlement is ambiguous", and the duplicate guard and spend entry were kept, refusing an immediate retry for up to 15 minutes. Added ConnectionRefused to the not-sent set; verified the codes Bun 1.1.43 actually produces (TLS errors already use Node's codes).
  • Test harness: the x402 test file never finished. After the paid: hang test, server.close() waited forever on the held connection (closeAllConnections() does not drop it under Bun). The fake now tracks sockets and destroys them on close. This is why bun test src/lib appeared to hang; CI does not run the tests, so nobody saw it.

Verification

  • bun run typecheck, bun run validate (204/204) pass; inbox/inbox.ts and aibtc-news/aibtc-news.ts also typecheck clean on their own (the news file had one error before: the getAccount import).
  • bun test src/lib: 167 pass, 0 fail, 16 s (previously hung). New tests: spendableStx, sponsored STX price with locked STX (refused), direct gas with locked STX (refused). The existing "never reaches the server" test was failing under Bun and now passes.
  • Skill tests (hodlmm-flow, inscription-queue-watcher, launkr, signing, stacks-alpha-engine): 49 pass, 1 fail. The failure is pre-existing: stacks-alpha-engine imports tiny-secp256k1, which is not in package.json.
  • Not exercised: a live mainnet payment, or a live inbox or news payment.

Follow-up worth considering

CI runs typecheck/validate but not bun test, and tsc only covers src/, which is how both bugs above shipped. Adding bun test src/lib to CI and widening the typecheck would catch them.

🤖 Generated with Claude Code

…ews payments

- spendableStx(): Hiro's stx.balance includes STX locked in stacking, which a
  transfer cannot move; direct and sponsored balance checks now subtract it
- inbox send and aibtc-news file-signal sign their own sponsored sBTC
  payments; run checkSponsoredPaymentBalance before signing there too
- aibtc-news imported getAccount from wallet-manager, which does not export
  it, so the paid file-signal path threw at runtime; import it from x402.service
- requestWasNeverSent: Bun reports a refused connection and a failed name
  lookup as "ConnectionRefused", so direct mode called them ambiguous and kept
  the duplicate guard and spend entry, refusing an immediate retry
- test fake: destroy sockets on close so a held response cannot hang
  server.close() (the x402 test file never finished under Bun)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@biwasxyz
biwasxyz force-pushed the fix/x402-balance-followups branch from 0426f48 to 77d7734 Compare October 8, 2026 11:39
@biwasxyz

biwasxyz commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

Review: rebased onto main (after #437/#438). Signatures verified for both new call sites; old aibtc-news getAccount import confirmed broken. Typecheck clean; bun test src/lib 174/174 in 17s (no longer hangs). LGTM.

@biwasxyz
biwasxyz merged commit 702ff4b into main Oct 8, 2026
5 checks passed
@biwasxyz
biwasxyz deleted the fix/x402-balance-followups branch October 8, 2026 11:41
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