feat(machine): limit bill insertion to available balance

Add billWithinBalance guard to state machine that rejects bills
exceeding the ATM's available sats. UI disables denomination buttons
and shows informational message when limit is reached.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-02-16 17:21:45 -05:00
commit 16159334a4
2 changed files with 45 additions and 2 deletions

View file

@ -331,6 +331,14 @@ export function createATMMachine(services: Partial<ATMServices> = {}) {
canRetry: ({ context }) => context.retryCount < 3,
hasUserNpub: ({ context }) => context.userNpub !== null,
hasOfferRequest: ({ context }) => context.pendingOfferRequest !== null,
billWithinBalance: ({ context, event }) => {
if (event.type !== 'BILL_INSERTED') return false
if (context.availableBalance <= 0 || context.exchangeRate === 0) return true
const newFiatCents = context.fiatAmount + event.denomination * 100
const grossSats = Math.floor((newFiatCents / 100) * context.exchangeRate)
const fee = Math.floor(grossSats * context.feePercent)
return grossSats - fee <= context.availableBalance
},
// Cash-out guards
hasSelectedAmount: ({ context }) => context.cashOutSelection.length > 0,
canAddDenomination: ({ context, event }) => {
@ -392,6 +400,7 @@ export function createATMMachine(services: Partial<ATMServices> = {}) {
insertingBills: {
on: {
BILL_INSERTED: {
guard: 'billWithinBalance',
actions: ['addBill', 'calculateSats'],
},
BILL_REJECTED: {