Overview / Ledger / money
ADR 0031
Balances are per-currency wallet accounts; available balance subtracts reservations at compute time
AcceptedLedger / money
Context
The platform holds balances for merchants (and for itself, as the fee collector — ADR 0022). Two things had to be decided: where a balance lives, and how "money you can actually withdraw" differs from the raw ledger balance when some funds are reserved — a payout in flight, or funds held against an open dispute.
Decision
Model balances as wallet accounts (financial_accounts) and compute available balance by subtracting reservations from the ledger running balance — reservations are never ledger entries.
- Wallets are accounts. An internal wallet (
inkress_wallet) is provisioned per merchant at the merchant's default currency; its running balance lives in the ledger projection (ADR 0029). Currency separation is enforced in the ledger (a balance per currency), and a posting to a currency the merchant has no wallet for raises rather than silently creating one. A merchant's payout wallet and the platform's fee-collector wallet (ADR 0022) are the same kind of account — the ledger is uniform. - Available is computed, not stored.
available = ledger running balance − pending payouts − Σ open dispute holds − recent not-yet-settled credits(the last term is a settlement-lag cutoff). The reservations (pending payouts, dispute holds) are compute-time overlays that write no ledger entry and never touchrunning_balance— so contested or in-flight funds cannot be withdrawn, without polluting the immutable ledger with reversible bookkeeping.
Consequences
- Positive: the ledger stays a clean record of settled movements, while "spendable" correctly excludes reserved funds; holds and pending payouts appear/disappear without reversing entries.
- Neutral / to revisit: available-balance correctness depends on the formula enumerating every reservation source. A new kind of reservation must be added to the computation or funds could be double-committed — the safety lives in one formula, so that formula is load-bearing. A settlement-lag cutoff also applies to what counts as available.
- Neutral / to revisit: a fast per-account balance cache backs lookups (ADR 0029); it must be kept in step with the projection (integrity fields exist for that check).
Alternatives considered
- Write reservations as ledger entries (hold/release pairs): rejected — it clutters the immutable ledger with reversible entries that must be perfectly unwound; a compute-time overlay keeps holds out of the permanent record.
- A single mutable balance column: rejected — no history or auditability; the ledger running balance plus a cache gives both O(1) reads and a full trail.
- One wallet spanning all currencies: rejected — see ADR 0032; currencies are hard-partitioned.