Currency Handling for Inexperienced Devs
Modern fintech and crypto apps handle currency in multiple forms: local fiat (NGN, KES, etc.), stablecoins (USDT, USDC), or volatile crypto assets (BTC, ETH). Mistakes in how you store, convert, or display these values can lead to real financial losses, user confusion, or major accounting errors. This guide covers the fundamentals.
Store Amounts in Smallest Units
Why It Matters
Floating-point arithmetic (like float or double in many languages) can introduce rounding errors. This is especially risky when dealing with money. It’s safer to keep all amounts in integer form, representing the smallest unit.
This prevents weird decimals like 12.3455999999 from creeping in.
Convert Only at the Edges
Principle
Keep internal logic in a single currency unit. Convert to a display-friendly format (like NGN, USD, or BTC) at the last possible moment.
Rounding Rules and User Display
Rounding
Decide how to round or truncate for user-facing balances. For example, if you do a swap that results in 0.999876 BTC:
For display, you might show 0.9999 BTC
Under the hood, you store the integer satoshi value (99,987,600 sats)
User Display
Label currencies clearly, especially if you handle both fiat and crypto.
For fiat, prefix or suffix with “₦” or “$.”
For crypto, suffix with “BTC” or “USDT.”
Handling exchange
Principle
Keep internal logic in a single currency unit. Convert to a display-friendly format (like NGN, USD, or BTC) at the last possible moment.
Rounding Rules and User Display
Rounding
Decide how to round or truncate for user-facing balances. For example, if you do a swap that results in 0.999876 BTC:
Fetch or lock in an exchange rate at a specific moment (e.g. the user requests a quote).
Store that rate in your records, so you can prove how you derived the final amount.
Apply the rate to the user’s input or your stored amounts in the smallest unit.
Perform integer math if possible (like satoshis → kobo).
If you must do decimal conversion, use a fixed-precision or big decimal library to avoid floating-point errors.
Use a library like bigdecimal.js or Python’s decimal module to avoid floating inaccuracies.
Different Crypto Chains, Different Multipliers
Why
USDT has many variants (TRC20, ERC20, BEP20, etc.). Some have 6 decimals, some 18 decimals. Always consult the chain specs or your API docs to confirm the correct smallest unit or multiplier.
Keep chain-based metadata in your code or config.
Watch Out for Fees and Gas
On-chain Fees
If you’re doing a transaction on a blockchain, the user’s final amount received might be reduced by network fees or gas. Communicate these fees clearly and either subtract them from the user’s total or collect them separately.
Lightning or Service Fees
Lightning or additional service fees might apply. Always confirm how these fees are deducted before finalizing a user’s transaction.
Multi-Currency Flows
Single Currency
Easiest path. For instance, store everything in NGN (for a local-only app) or in BTC (for a pure-BTC app).
Multi-Currency
If you’re bridging stablecoins, BTC, and fiat:
Keep each currency’s balance in separate fields or columns.
Convert only when necessary.
Use references to tie multiple conversions into one transaction record.
Cross-Border Remittance
Check local regulators on which currency to display at each stage. You might show an estimate in the user’s home currency but store the final conversion in the recipient’s currency.
Example Flow: Accept BTC, Pay in NGN
Get user’s BTC amount in satoshis.
Use an exchange rate to find NGN kobo equivalent.
Add fees if any.
Store the result in your DB as an integer of kobo.
Display “₦2000.00” to the user.
This avoids floating conversion issues and ensures each step is trackable.
Thorough Testing
Test tiny amounts like 1 sat or 1 kobo.
Test large amounts near your max limit.
Test rounding edge cases (e.g. 0.9999 crossing into 1.0000)
Test different locales for currency formatting if you have a diverse user base.
Library and Tool Recommendations
Big.js or decimal.js for JavaScript
decimal or in Python
BigDecimal in Java/Kotlin
Always store as integers where feasible, especially for ledger amounts
Summary of Best Practices
Store amounts in smallest integer unit to avoid floating bugs
Convert to user-friendly format only at display time
Lock and record your exchange rates for each conversion
Be mindful of different decimals for stablecoins across chains
Include fees in your math logic
Test extreme amounts and rounding scenarios
A little planning on currency handling saves you major headaches in production. It ensures your users see consistent numbers, your audits match your records, and you maintain trust by never “losing” or “gaining” money due to floating-point errors.