refactor(state-machine): zero fee fraction defaults

`initialContext.cashInFeeFraction` / `cashOutFeeFraction` drop from
0.0333 / 0.0777 → 0. The state-machine no longer carries a fee
opinion; callers (the renderer's atm-store) are responsible for
supplying explicit fractions via `createATMMachine(..., options)`.

Why now: aiolabs/lamassu-next#57 makes the operator's Nostr-pushed
fee config the source of truth on the ATM. Keeping non-zero defaults
in the state machine would mean a misconfigured caller could silently
fall back to a 7.77% cash-out fee instead of failing closed into the
"awaiting fee configuration" maintenance screen.

Extracts `ATMMachineOptions` as a named interface (was inline). No
functional change to the option spread.

Updates the `should calculate sats amount from fiat with fee` test
to pass `cashOutFeeFraction: 0.0777` explicitly so it still exercises
the cash-out fee math; the post-refactor zero default would otherwise
land 50,000 sats instead of 53,885.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-06-01 10:53:26 +02:00
commit 6e271d8ce4
3 changed files with 17 additions and 5 deletions

View file

@ -153,7 +153,9 @@ describe('ATM State Machine', () => {
})
it('should calculate sats amount from fiat with fee', async () => {
const machine = createATMMachine(mockServices)
// Fee fractions default to 0 post-aiolabs/lamassu-next#57; pass
// explicit values to exercise the cash-out fee math.
const machine = createATMMachine(mockServices, { cashOutFeeFraction: 0.0777 })
const actor = createActor(machine)
actor.start()

View file

@ -18,9 +18,15 @@ import {
/**
* Create the ATM state machine with injected services
*/
export interface ATMMachineOptions {
currency?: string
cashInFeeFraction?: number
cashOutFeeFraction?: number
}
export function createATMMachine(
services: Partial<ATMServices> = {},
options?: { currency?: string; cashInFeeFraction?: number; cashOutFeeFraction?: number }
options?: ATMMachineOptions
) {
return setup({
types: {

View file

@ -163,9 +163,13 @@ export const initialContext: ATMContext = {
satsAmount: 0,
currency: 'USD',
exchangeRate: 0,
feeFraction: 0.0333,
cashInFeeFraction: 0.0333,
cashOutFeeFraction: 0.0777,
// Zero defaults — operator's Nostr-pushed fee config is the source of
// truth (aiolabs/lamassu-next#57). The atm-store gates production boot
// on a persisted config existing; no transaction reaches this context
// until the operator's publish has been received.
feeFraction: 0,
cashInFeeFraction: 0,
cashOutFeeFraction: 0,
availableBalance: 0,
invoice: null,
clinkOffer: null,