From 6e271d8ce4edfa8afcd8cbbc471cf371acfeb98b Mon Sep 17 00:00:00 2001 From: Padreug Date: Mon, 1 Jun 2026 10:53:26 +0200 Subject: [PATCH] refactor(state-machine): zero fee fraction defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `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 --- packages/state-machine/src/__tests__/machine.test.ts | 4 +++- packages/state-machine/src/machine.ts | 8 +++++++- packages/state-machine/src/types.ts | 10 +++++++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/state-machine/src/__tests__/machine.test.ts b/packages/state-machine/src/__tests__/machine.test.ts index 0d59d12..4d50ad2 100644 --- a/packages/state-machine/src/__tests__/machine.test.ts +++ b/packages/state-machine/src/__tests__/machine.test.ts @@ -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() diff --git a/packages/state-machine/src/machine.ts b/packages/state-machine/src/machine.ts index b7dbce1..fc87fca 100644 --- a/packages/state-machine/src/machine.ts +++ b/packages/state-machine/src/machine.ts @@ -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 = {}, - options?: { currency?: string; cashInFeeFraction?: number; cashOutFeeFraction?: number } + options?: ATMMachineOptions ) { return setup({ types: { diff --git a/packages/state-machine/src/types.ts b/packages/state-machine/src/types.ts index 2fc6fde..b99c78b 100644 --- a/packages/state-machine/src/types.ts +++ b/packages/state-machine/src/types.ts @@ -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,