Lock deposit currency to machine.fiat_code (and prepare balance-summary for the multi-currency future) #26
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptom
Surfaced during a 2026-05-16 end-to-end test against the local Sintra
(
fiat_code=EUR). Jordan had been recorded with two deposits at thesame EUR machine:
After 50 EUR of DCA payouts cleared his nominal balance, the next
40 EUR cash-out distributed 15 EUR worth of sats to him on the strength
of that 15 USD deposit — the balance summary is currency-blind:
SUM(amount)mixes 50 + 15 → 65 "units" regardless that one is EUR andone is USD. With a real EUR/USD rate of ~0.92, Jordan's actual
USD-equivalent claim was ~€13.8; the system paid him €15 worth of sats.
Today's product reality (single currency per machine) shields us from
this in practice — but only if the operator entered the right currency
in the first place.
Root cause
dca_deposits.currencyis a free-formTEXTcolumn the operatoredits via the "Record deposit" dialog. Today's UI gives them an
unconstrained text input. The machine the deposit is recorded against
already has a
fiat_code; the deposit's currency is fullydetermined by the machine and shouldn't be operator-choosable.
Fix (now): lock deposit currency to the machine's fiat_code
Current invariant: a
dca_clientsrow is(machine, LP); anLP-at-this-machine's enrolments are scoped to that machine's currency.
So:
api_create_deposit(andapi_update_deposit),override
data.currencywith the resolved machine'sfiat_coderather than trusting the request body. The body field becomes
optional / ignored.
display of the machine's
fiat_codefor the selected LP/client.Operator can see it but can't change it. Saves a class of typo.
rewrites every
dca_deposits.currencyrow to matchdca_machines.fiat_codejoined on the deposit'smachine_id. Withthe current dev data, that converts Jordan's
15 USDrow to15 EUR— which is the right answer at today's invariant.a non-matching currency (in case a programmatic client tries to
bypass the UI lock).
Future (when machines handle more than one currency)
Some hardware reads multiple denominations across currencies (a USD
note next to a EUR note in different cassettes; multi-currency cash
recyclers). When that happens:
dca_machinesgains either:fiat_codes: TEXT[](set of supported currencies), ordca_machine_currenciesjoin table.dca_deposits.currencybecomes operator-choosable again, butconstrained to the machine's supported set (dropdown of the
declared currencies, not free text).
dca_clientsmay need a currency dimension too — an LP enrolled ata multi-currency machine could have separate balances per currency,
or a single combined balance with the operator selecting which
pile to credit per deposit.
get_client_balance_summarybecomes currency-aware: returns aper-currency breakdown, distribution math runs once per currency.
dca_lp.dca_wallet_ideither stays single-wallet (LP accumulatesin one wallet regardless of source currency, like today) or gains
a per-currency mapping (LP wants USD deposits → USD-pegged LN
service, EUR deposits → another).
Open product questions for that phase; not blocking the near-term fix.
Acceptance criteria (for the near-term fix only)
api_create_depositignoresdata.currencyand writes themachine's
fiat_codeon the row.api_update_depositrejects attempts to changecurrency(orsilently overwrites with the machine's
fiat_code, equivalenteffect).
derived from the selected client's machine. No text input.
dca_deposits.currencyto matchits machine's
fiat_code.behaviour on
api_create_deposit.Out of scope
get_client_balance_summary(only needed once amachine actually supports >1 currency).
References
EUR deposit at an EUR Sintra; settlement
7cyB2EmLdj4BUBLNkJQtBA.views_api.api_create_deposit(~/api/v1/dca/deposits)views_api.api_update_depositcrud.create_deposit/update_deposit(SQL writes)crud.get_client_balance_summary(currency-blind summation)static/js/index.jsdeposit dialog data +_cleanDepositCreatetemplates/satmachineadmin/index.htmldeposit dialog UIClosing — shipped at commit
d2e6827 feat(v2): lock deposit currency to machine.fiat_code (closes #26). Forgejo didn't auto-close from the commit message; closing manually.Backend override + UI lock + backfill migration all landed per the acceptance criteria. The multi-currency future scope stays open as a "when product needs it" item, not blocking.
padreug referenced this issue2026-05-30 07:57:04 +00:00