Real Exchange Rates & Currency Conversion
๐ Overview
The fintech system uses a robust, production-ready exchange rate provider setup:
- ExchangeRateAPIProvider (
infra/provider/exchangerate_api.go
): Fetches real-time rates from exchangerate-api.com, with caching and health checks. - exchange.Service (
pkg/service/exchange/service.go
): Orchestrates provider selection, caching, and fallback logic.
Example:
// The exchange service is created in the factory
exchangeService, err := exchange.New(exchange.Config{
Registry: providerRegistry,
Cache: rateCache,
Logger: logger,
})
// In the application, you can then use the service to convert money
convertedMoney, err := exchangeService.Convert(ctx, originalMoney, "USD")
Why this matters
This setup ensures reliable, up-to-date currency conversion with robust fallback and caching.
Conversion Flow
- The service layer requests a conversion (e.g., deposit/withdraw in a different currency).
- The domain layer performs the conversion using the latest exchange rate (via the real provider).
- The result is rounded to the correct number of decimals for the target currency using big.Rat.
- The value is stored in the smallest unit (e.g., cents for USD) as an integer (BIGINT in the DB).
- Conversion details (original amount, rate, etc.) are stored as DECIMAL(30,15) for full float64 compatibility.
๐๏ธ Database Schema
- All money values are stored as BIGINT (smallest unit, e.g., cents).
- Conversion fields (original_amount, conversion_rate) in the transactions table are stored as DECIMAL(30,15) to support any float64 value.
๐ Best Practices
- Always pass raw float64 values to the domain layer; do not round in the service or API layers.
- The domain will round and validate as needed.
- All conversion and rounding logic is centralized for consistency and safety.
๐งช Example
- Deposit 1,000,000,000 JPY to a USD account:
- The system fetches the exchange rate, converts, and rounds to 2 decimals for USD.
- The result is stored as an integer (cents) in the DB.
- The original amount, rate, and conversion details are stored as DECIMAL(30,15).
๐ Recent Improvements
- Domain-driven rounding and validation using big.Rat
- Full float64 compatibility for conversion fields
- DB schema updated for DECIMAL(30,15) on conversion fields
- All overflow and decimal errors are now handled before DB writes