diff --git a/packages/state-machine/src/__tests__/machine.test.ts b/packages/state-machine/src/__tests__/machine.test.ts index ff624e3..0d59d12 100644 --- a/packages/state-machine/src/__tests__/machine.test.ts +++ b/packages/state-machine/src/__tests__/machine.test.ts @@ -15,6 +15,7 @@ describe('ATM State Machine', () => { dispensed: true, } satisfies DispenseCashResult), getExchangeRate: vi.fn().mockResolvedValue(2500), // 2500 sats per USD + getAvailableBalance: vi.fn().mockResolvedValue(1_000_000), // 1M sats available // noffer cash-out services (legacy) generateNoffer: vi.fn().mockResolvedValue('noffer1atmtest'), sendOfferResponse: vi.fn().mockResolvedValue(undefined), diff --git a/packages/state-machine/src/machine.ts b/packages/state-machine/src/machine.ts index 4d448b2..3f7e438 100644 --- a/packages/state-machine/src/machine.ts +++ b/packages/state-machine/src/machine.ts @@ -368,7 +368,9 @@ export function createATMMachine( hasOfferRequest: ({ context }) => context.pendingOfferRequest !== null, billWithinBalance: ({ context, event }) => { if (event.type !== 'BILL_INSERTED') return false - if (context.availableBalance <= 0 || context.exchangeRate === 0) return true + // Reject bills if balance or rate is unknown — don't risk accepting + // cash we can't cover with sats + if (context.availableBalance <= 0 || context.exchangeRate === 0) return false const newFiatCents = context.fiatCents + event.denomination * 100 const grossSats = Math.floor((newFiatCents / 100) * context.exchangeRate) const fee = Math.floor(grossSats * context.feePercent)