Most payment systems assume one currency. You store an amount, you attach a currency code somewhere in a config file, and you move on. Then you try to build for Zimbabwe and the assumption collapses on day one.
Here, a single user holds two wallets that are legal tender at the same time — US dollars and the gold-backed ZiG (Zimbabwe Gold) — trading against each other at a rate that moves. A price tag in a shop is quoted in both. A refund can come back in a different currency than the payment went out. An exchange rate captured at checkout is not the same rate that clears at settlement. None of this is edge-case handling bolted onto a single-currency core. In Zimbabwe, duality is the core, and if you don't design for it from the first schema, you rebuild the whole thing later.
This is a guide to building for that reality: how the country ended up with two currencies, how local fintech absorbed the split, and — the part most articles skip — how you actually engineer software that treats dual currency as a first-class assumption rather than an afterthought.
How Zimbabwe ended up with two currencies
The short version: hyperinflation destroyed the original Zimbabwe dollar. By 2008, the Reserve Bank was printing Z$10 trillion notes while inflation ran past comprehension. In early 2009 the government abandoned the local unit and legalised a multi-currency basket led by the US dollar and the South African rand, which stabilised prices almost overnight by importing monetary discipline the state couldn't supply itself.
That was supposed to be temporary. It wasn't. Every subsequent attempt to reintroduce a sole local currency ran into the same wall: nobody trusted it. The bond note arrived in 2016 pegged to the dollar and drifted off peg. The RTGS dollar became the official local currency between 2019 and 2020 and then lost most of its value — shedding roughly three-quarters of it in the first months of 2024 alone.
In April 2024 the government tried again, this time with a structured currency. The ZiG (Zimbabwe Gold) launched on 5 April 2024, backed by a basket of foreign reserves and precious metals — mainly gold — held by the Reserve Bank. All existing local-currency balances were converted to ZiG at a starting rate of 1 USD to 13.56 ZiG. The US dollar, which already accounted for the overwhelming majority of transactions, stayed legal tender. The multi-currency system was formally extended to 2030.
So the "dual" in dual currency today is specifically USD and ZiG, and the important part for anyone building software is what stayed constant across every one of those reforms: the dollar never left. Whatever the local unit is called this decade, it lives alongside hard currency, not instead of it. You are not building for a currency transition. You are building for permanent coexistence.
How Zimbabwean fintech absorbed the split
Walk through any part of the financial system and you'll find the duality has been solved the same way — by doubling.
Mobile money. On EcoCash, the dominant platform, a user doesn't have an account. They have a USD wallet and a ZiG wallet, held separately, funded separately, spent separately. Moving value between them isn't a transfer; it's a currency conversion at a rate.
Banks. The same pattern. A single customer holds a USD account (often called an FCA — Foreign Currency Account) and a local ZiG account under one profile. Statements, balances, and limits are tracked per currency.
Capital markets. This is the boldest structural answer. On 23 October 2020, Zimbabwe launched the Victoria Falls Stock Exchange (VFEX) — a separate, entirely USD-denominated exchange to sit alongside the ZiG-denominated Zimbabwe Stock Exchange (ZSE). Rather than force one market to handle two currencies, the country built a second market. Securities on the VFEX are traded and settled solely in US dollars, and so many large firms migrated there for hard-currency stability that local press dubbed it the "Great Trek." By 2026 the VFEX had overtaken the century-old ZSE by market capitalisation.
The pattern underneath all three is the thing to internalise before you write any code: the currency is not an attribute of a transaction bolted on at the end. It is an attribute of the account itself. Value doesn't flow freely between USD and ZiG. It crosses a boundary, and every boundary crossing is a conversion event with a rate, a timestamp, and a margin. Design the boundary well and the system holds. Ignore it and every balance you display is quietly wrong.
Engineering a dual-currency system
Here's what actually changes in your architecture when you stop treating currency as a label and start treating it as structure. Seven decisions carry most of the weight.
1. Money is never a float, and never bare
This is universal advice, but dual currency makes violating it twice as expensive. Store money as integer minor units (cents), never as a floating-point number — 0.1 + 0.2 != 0.3 is not a currency you want to run a business on. And an amount is meaningless without its currency welded to it. The atomic unit of money in your system is the pair { amount_minor, currency }, always travelling together.
// Wrong — loses precision, and 500 of what?
const balance = 5.0;
// Right — integer minor units, currency inseparable
interface Money {
amountMinor: bigint; // 500 = $5.00 or ZiG 5.00
currency: "USD" | "ZWG";
}
ZWG is the ISO 4217 code for the ZiG; USD you know. Use the ISO codes everywhere in code and storage — never the symbol, never a display string.
2. Currency lives on the account, not just the transaction
Because value can't move freely between USD and ZiG, a wallet is single-currency by definition. A user is a collection of single-currency accounts. This mirrors exactly what EcoCash and the banks already do — and it's what makes balances trustworthy.
Schema — Account & Ledger Structure
The rule the schema enforces: a LEDGER_ENTRY's currency must equal its ACCOUNT's currency. There is no such thing as a mixed-currency account. If value needs to cross currencies, it does so through a CONVERSION that debits one single-currency account and credits another — two clean entries, one explicit FX event linking them.
3. The exchange rate is a first-class, versioned entity
The single biggest mistake is treating the rate as a number you fetch when you need it. In a floating dual-currency economy the rate moves during the life of a transaction, and you will be asked — by a customer, an auditor, or the central bank — which rate you used and when you captured it.
Store rates as immutable, timestamped records. Never mutate; only append. Capture the rate at the moment of the customer-facing action and carry that captured rate through to settlement, so the amount quoted and the amount cleared reconcile.
Rate Capture & Settlement Flow
Store the rate as an integer too — parts-per-million or a fixed decimal scale — not a float. And keep a source field: an official RBZ rate, an interbank rate, and your own applied rate (interbank plus your spread) are three different numbers, and conflating them is how you lose money or lose trust.
4. Conversion is an explicit transaction, never an implicit cast
When a user moves ZiG to USD, that is not an update to one balance. It is: debit the ZiG account, credit the USD account, record the rate used, record the spread you took, and link all of it under one conversion ID. Double-entry, always balancing, fully auditable.
Atomic Conversion — Sequence Diagram
If any leg fails, the whole thing rolls back. A conversion that half-completes is a corrupted ledger, and in a two-currency system you can't eyeball a corrupted ledger back into balance — the currencies don't sum.
5. Every balance query answers "in which currency?"
There is no single "total balance." A user has a USD balance and a ZiG balance, and they are not addable without a conversion — which means without a rate, which means at a point in time. If your UI shows a combined figure, it must show the rate and timestamp used to compute it, because that number is only true for that instant. Treating "total net worth in USD" as a stored field rather than a rate-dependent computation is a bug waiting to be filed.
6. Currency is immutable once set; the boundary is where you enforce rules
An account's currency never changes after creation. A ledger entry's currency never changes. This immutability is what lets you trust historical data years later. All the interesting business logic — spreads, limits, compliance holds, KYC thresholds that differ by currency — lives at the conversion boundary, the one place where the two worlds touch.
Dual-Currency Architecture — Two Worlds, One Boundary
Keep the two worlds clean and put all the mess at the boundary. It's far easier to reason about, audit, and change your commercial terms when every FX decision routes through a single, well-instrumented chokepoint.
7. Test with the rate moving, not frozen
Single-currency tests assume a stable unit. Yours can't. Write tests where the rate changes between quote and settlement and assert the system uses the captured rate, not the live one. Test refunds that cross currencies. Test a conversion that fails mid-flight and assert the ledger still balances. Test rounding at conversion — because rounding thousands of ZiG-to-USD conversions in the wrong direction is a slow, silent leak that only shows up when your ledger and your bank statement disagree.
Key Takeaways
- If you build one thing correctly, make it the money type: integer minor units with currency inseparably attached, everywhere. Everything else follows from taking that seriously.
- Currency is an account property, not a transaction label. Model single-currency wallets and a user who holds several — the way EcoCash and the banks already do.
- The exchange rate is a versioned, timestamped, append-only entity. Capture it at the customer-facing moment and carry that same rate to settlement.
- Every currency crossing is an explicit double-entry conversion with a rate, a spread, and an audit trail — never an implicit balance update.
- There is no single total balance. Any combined figure is a computation that depends on a rate at a point in time, and must be shown as such.
- Put all FX logic at one boundary and keep the two currency worlds clean on either side.
Zimbabwe didn't choose dual currency as a design goal — it arrived at it through two decades of monetary crisis. But the engineering discipline it forces on you is genuinely good practice anywhere multiple currencies coexist. Build for the duality from the schema up, and the USD/ZiG reality stops being a source of bugs and becomes just the shape of the system.
References
- BBC News — Zimbabwe launches new gold-backed currency (ZiG)
- Reuters — Zimbabwe extends multi-currency system to 2030
- Institute of Development Studies — Currency reforms in Zimbabwe: an analysis of possible currency regimes
- Investopedia — ZWD (Zimbabwe Dollar)
- VOA Africa — Zimbabwe to maintain multi-currency system
- Xinhua — Zimbabwe unveils new gold-backed currency ZiG (5 April 2024)
- Pindula — Victoria Falls Stock Exchange (VFEX)