diff --git a/apps/machine/src/stores/atm.ts b/apps/machine/src/stores/atm.ts index 7955f9f..f6c9380 100644 --- a/apps/machine/src/stores/atm.ts +++ b/apps/machine/src/stores/atm.ts @@ -28,13 +28,16 @@ const isElectron = typeof window !== 'undefined' && window.electronAPI !== undef /** * Compute fee in sats from context. - * Cash-in: customer gets net (gross - fee). Cash-out: customer pays gross + fee. + * + * principalSats = market-rate sats for the fiat amount (fiat × exchangeRate, no commission). + * Cash-in: on-wire satsAmount = principalSats - feeSats (customer receives less than principal) + * Cash-out: on-wire satsAmount = principalSats + feeSats (customer pays more than principal) */ function computeFeeSats(ctx: ATMContext, isCashIn: boolean): number { - const grossSats = ctx.exchangeRate > 0 ? Math.floor((ctx.fiatCents / 100) * ctx.exchangeRate) : 0 + const principalSats = ctx.exchangeRate > 0 ? Math.floor((ctx.fiatCents / 100) * ctx.exchangeRate) : 0 const feeSats = isCashIn - ? grossSats - ctx.satsAmount // cash-in: customer gets net - : ctx.satsAmount - grossSats // cash-out: customer pays gross + fee + ? principalSats - ctx.satsAmount // cash-in: customer receives less than principal + : ctx.satsAmount - principalSats // cash-out: customer pays more than principal return Math.max(0, feeSats) } @@ -850,9 +853,9 @@ export const useAtmStore = defineStore('atm', () => { // Calculate what the new sats amount would be const newFiatCents = ctx.fiatCents + denomination * 100 const newFiatUnits = newFiatCents / 100 - const grossSats = Math.floor(newFiatUnits * ctx.exchangeRate) - const fee = Math.floor(grossSats * ctx.feePercent) - const newSatsAmount = grossSats - fee + const principalSats = Math.floor(newFiatUnits * ctx.exchangeRate) + const fee = Math.floor(principalSats * ctx.feePercent) + const newSatsAmount = principalSats - fee // Check against available balance if (newSatsAmount > ctx.availableBalance) { @@ -1106,9 +1109,9 @@ export const useAtmStore = defineStore('atm', () => { // Calculate if this bill would exceed available balance const newFiatCents = ctx.fiatCents + denomination * 100 const newFiatUnits = newFiatCents / 100 - const grossSats = Math.floor(newFiatUnits * ctx.exchangeRate) - const fee = Math.floor(grossSats * ctx.feePercent) - const newSatsAmount = grossSats - fee + const principalSats = Math.floor(newFiatUnits * ctx.exchangeRate) + const fee = Math.floor(principalSats * ctx.feePercent) + const newSatsAmount = principalSats - fee if (newSatsAmount > ctx.availableBalance) { console.log( diff --git a/apps/machine/src/views/CashInView.vue b/apps/machine/src/views/CashInView.vue index 7956ca7..2a150b2 100644 --- a/apps/machine/src/views/CashInView.vue +++ b/apps/machine/src/views/CashInView.vue @@ -120,9 +120,9 @@ function canAcceptBill(denomination: number): boolean { if (!ctx) return false if (ctx.availableBalance <= 0 || ctx.exchangeRate === 0) return true const newFiatCents = ctx.fiatCents + denomination * 100 - const grossSats = Math.floor((newFiatCents / 100) * ctx.exchangeRate) - const fee = Math.floor(grossSats * ctx.feePercent) - return grossSats - fee <= ctx.availableBalance + const principalSats = Math.floor((newFiatCents / 100) * ctx.exchangeRate) + const fee = Math.floor(principalSats * ctx.feePercent) + return principalSats - fee <= ctx.availableBalance } const balanceLimitReached = computed(() => { diff --git a/packages/state-machine/src/machine.ts b/packages/state-machine/src/machine.ts index ebb3916..828eb39 100644 --- a/packages/state-machine/src/machine.ts +++ b/packages/state-machine/src/machine.ts @@ -189,9 +189,9 @@ export function createATMMachine( satsAmount: ({ context }) => { if (context.exchangeRate === 0) return 0 const fiatDollars = context.fiatCents / 100 - const grossSats = Math.floor(fiatDollars * context.exchangeRate) - const fee = Math.floor(grossSats * context.feePercent) - return grossSats - fee + const principalSats = Math.floor(fiatDollars * context.exchangeRate) + const fee = Math.floor(principalSats * context.feePercent) + return principalSats - fee }, }), calculateDispenseAmounts: assign({ @@ -324,10 +324,10 @@ export function createATMMachine( satsAmount: ({ context }) => { if (context.exchangeRate === 0) return 0 const fiatDollars = context.fiatCents / 100 - const grossSats = Math.floor(fiatDollars * context.exchangeRate) + const principalSats = Math.floor(fiatDollars * context.exchangeRate) // For cash-out, user pays the sats, so fee is added - const fee = Math.floor(grossSats * context.feePercent) - return grossSats + fee + const fee = Math.floor(principalSats * context.feePercent) + return principalSats + fee }, }), calculateDispenseFromSelection: assign({ @@ -372,9 +372,9 @@ export function createATMMachine( // 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) - return grossSats - fee <= context.availableBalance + const principalSats = Math.floor((newFiatCents / 100) * context.exchangeRate) + const fee = Math.floor(principalSats * context.feePercent) + return principalSats - fee <= context.availableBalance }, // Cash-out guards hasSelectedAmount: ({ context }) => context.cashOutSelection.length > 0,