Skip to content

Audit hardening: payout correctness, self-custody payouts, bech32, AI batching#26

Merged
comwanga merged 2 commits into
mainfrom
fix/payout-correctness
Jun 20, 2026
Merged

Audit hardening: payout correctness, self-custody payouts, bech32, AI batching#26
comwanga merged 2 commits into
mainfrom
fix/payout-correctness

Conversation

@comwanga

@comwanga comwanga commented Jun 20, 2026

Copy link
Copy Markdown
Owner

End-to-end audit hardening. Each fix is its own commit, developed under TDD. Backend 156 passed; frontend 58 passed + typecheck + lint + production build green.

Bitcoin / Lightning — correctness

  • Preimage verification — items were marked paid for any preimage the wallet returned. New bolt11.py (validated against the canonical BOLT#11 spec vector) checks sha256(preimage) == payment_hash; an unverifiable preimage is terminal unverified.
  • Idempotencycreate_payout made a fresh payout every call, so a double-click / timeout-retry paid winners twice. Unique (allocation_id, team_label) constraint (migration 0008) + 409 + IntegrityError race backstop.
  • Spend ceilingtotal_sats was bounded only by gt=0; configurable PAYOUT_MAX_SATS enforced pre-flight.

Bitcoin / Lightning — self-custody (architectural)

Design: docs/superpowers/specs/2026-06-20-self-custody-payouts-design.md.

  • The NWC spend credential now never reaches the backend. The browser (lib/lightning.ts) resolves invoices (LUD-16) and performs the NIP-47 pay_invoice over a WebSocket; the server creates pending items and verifies each reported preimage before recording paid.
  • The server-side spend path (and the nwc request field) is removed, so the backend has no way to spend — self-custody is enforced, not opt-in. This also eliminates the old blocking/timeout-prone server-side payment loop.

Nostr

  • bech32 checksum validation (BIP-173) — a mistyped npub decoded to a wrong key and was silently accepted. Also fixed a latent nsec test-vector typo this surfaced.

AI

  • Batched categorization — a single max_tokens=1024 call truncated past ~14 "Other" registrants and silently dropped the whole event to the deterministic fallback. Now batched with per-batch failure isolation, a cacheable system block, and an abstention path. Prompt-build/parse are pure, unit-tested helpers.

Hygiene

  • Removed the unused requests dependency.

Still open (larger, additive — recommend separate PRs)

More native rails (BOLT12 offers / NIP-57 zaps), client-side get_balance preflight, registration rate-limiting, and deeper AI features (the unused tech_stack/interests signals, team rationale, NL results query).

comwanga added 2 commits June 20, 2026 15:49
A payout item was marked "paid" for any non-empty preimage the wallet
returned, with no proof the sats actually moved. A buggy or hostile wallet
could fake settlement.

Add app/services/bolt11.py to extract an invoice's payment hash and check
sha256(preimage) == payment_hash. Items whose preimage does not verify get a
new terminal "unverified" status (not "failed", so retry won't re-send money
that may already have left the wallet). The decoder is validated against the
canonical BOLT#11 spec test vector.
create_payout built a fresh Payout on every call, so a double-click or a
client retry after a timeout paid every winner again.

Add a unique (allocation_id, team_label) constraint plus an explicit 409
pre-check, with an IntegrityError catch on flush as the race backstop (fires
before any sats move). Re-attempts route through the existing retry endpoint.
@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
squadsync Ready Ready Preview, Comment Jun 20, 2026 12:53pm

@comwanga comwanga merged commit 115ee4b into main Jun 20, 2026
6 checks passed
@comwanga comwanga changed the title fix(payout): preimage verification + idempotency for Lightning payouts Audit hardening: payout correctness, bech32, AI batching, spend ceiling Jun 20, 2026
@comwanga comwanga changed the title Audit hardening: payout correctness, bech32, AI batching, spend ceiling Audit hardening: payout correctness, self-custody payouts, bech32, AI batching Jun 20, 2026
comwanga added a commit that referenced this pull request Jun 20, 2026
Self-custody payouts + audit hardening (re-land of #26 remainder)
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