A wallet that can hold KES, UGX, TZS and other currencies at once sounds like a UI feature. It is actually a ledger-design problem, and it's the part of Zuma's architecture that took the most iteration to get right.
The naive approach — a running balance per currency, updated directly whenever a transaction happens — works fine until two transactions hit the same balance at nearly the same moment, or until a mobile money callback arrives out of order relative to the app's own record of the transaction. At scale, that naive approach produces balances that quietly drift from reality, and nobody notices until a support ticket says "my money is missing."
The wallet instead runs as an append-only ledger: every top-up, spend, refund and transfer is a discrete, immutable entry, and the "balance" shown to a user is a computed sum, not a stored field that gets directly edited. Reconciliation against each payment rail's own settlement report becomes a matter of comparing ledger entries to rail statements line by line, rather than trying to explain a single mutable number. This is the exact pattern I recommend to any hosting or billing client asking "why doesn't our account balance match what the client actually paid" — the fix is almost never a bug hunt, it's replacing a mutable balance with an immutable ledger.
