Operator-account pubkey ↔ ATM-npub collision detection #32
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
If an LNbits operator's
accounts.pubkeyhappens to equal a registered ATM'sdca_machines.machine_npub, the lnbits nostr-transport handler will route inbound kind-21000 invoices from the ATM to the operator's wallet by collision — not by design. This silently "works" until the collision breaks (e.g. operator's pubkey rotates, account is re-provisioned, or a fresh ATM is onboarded against the operator's existing npub) at which point invoices start landing on auto-created accounts instead.The failure mode is invisible from the operator's perspective: cash gets dispensed by the ATM (which trusts the Lightning payment notification regardless of which wallet was credited), but no
dca_settlementsrow appears, no DCA distribution runs. The operator eats the loss.Real instance surfaced 2026-05-30 (coord-log archive
2026-05-31-pre-rotation.md,17:55Zentry, carry-over item 4): Greg'saccounts.pubkeywas seeded as the same value as Sintra'smachine_npub(522a4538…) during manual setup. The collision masked the routing problem for days. When Greg's pubkey was refreshed during the bunker migration the collision broke, auto-account-from-npub fired, and $20 cash-out from Sintra silently dropped on the satmachineadmin side (21:33Zthread).The defensive listener fallback (filed separately as
#31) catches the symptom but doesn't surface the underlying drift. This issue addresses the root cause.What this issue covers
One-time safety check (immediately runnable)
Bitspire suggested in
17:55Zcarry-over #4:Any row returned is a collision. Run on every LNbits instance with satmachineadmin installed; document the result + remediation in this issue's comments.
Ongoing detection (code change)
Add a guard at machine-creation time (
crud.create_machine/views_api.api_create_machine):Wire into
api_create_machinebeforecreate_machineis called.Reverse direction — detect at account-creation too
If an account is being created (or has its pubkey rotated) with a pubkey that matches a registered ATM's
machine_npub, similar concern. This requires hooking into the LNbits account-create path, which is upstream territory — file asaiolabs/lnbitsfollow-up after this satmachineadmin-side guard lands.Acceptance
api_create_machinerejects with 400 + clear error message whenmachine_npubmatches any existingaccounts.pubkey. Test with a controlled collision.CLAUDE.md(or wherever the operator-onboarding doc lives) explaining the no-collision invariant and pointing at this issue for context.aiolabs/lnbitsfor the reverse-direction account-creation guard.Out of scope
#20) — this is one of several guards that together close the auto-account-from-npub gap.#31. Together with this issue they form the two layers of defence: this issue prevents the dependency from existing;#31catches the symptom when it breaks.Sequencing
Standalone. Ship-able today. ~1-2 hours.
Cross-references
2026-05-31-pre-rotation.md17:55Zcarry-over item 4 — bitspire's flag.aiolabs/satmachineadmin#20— S6 / lnbits-side proper fix this complements.aiolabs/satmachineadmin#31— defensive listener fallback (symptom-side mitigation pair).aiolabs/satmachineadmin#13— epic context (security pathway hardening).Regtest SQL collision check — 2026-05-31
Per AC item 1, ran the diagnostic SQL against the regtest LNbits + satmachineadmin DBs:
Result
machine_npub522a4538…(Greg's Sintra)a94b564f…(username=None — auto-account signature, created during 2026-05-30T21:33Z silent-drop failure mode). NOT a legitimate operator account.Greg's actual operator account
ac35c9fc…carries pubkey197a4cf4…post-bunker migration; no collision there.Disposition
a94b564f…is operational cleanup (sweep its wallet balance + delete the account row). Separate from this code fix; not blocking PR #33.Implementation + PR
PR #33 (
feat/collision-detection) opens againstv2-bitspire. Implements the_assert_no_pubkey_collisionguard, 7 unit tests, and the CLAUDE.md doc note per AC items 2 and 3.AC item 4 (upstream
aiolabs/lnbitsfollow-up for reverse-direction account-creation guard) deferred — will file once the path-B handoff with lnbits is settled (coord-log2026-05-31T15:25Zthread).