Problem
Every page in the dApp that shows vault balances, deposit amounts, or settlement previews needs to display a fiat-equivalent value (USD, NGN, GHS, KES). Right now none of this is wired — the frontend either shows raw USDC amounts with no conversion or hardcodes a mock exchange rate. This becomes especially critical for the offramp flow where the user needs to see exactly how much local currency they will receive before confirming.
What's Needed
A lightweight exchange rate service baked into the Go API that can convert between the assets Nester uses (USDC, XLM) and the fiat currencies supported by the offramp (NGN, GHS, KES, USD).
Suggested Data Sources (in priority order)
- Stellar DEX / AMM — on-chain USDC/XLM rate via Horizon's
/order_book endpoint. Most accurate for Stellar-native assets, no third-party dependency.
- DeFiLlama prices API — free, no key required. Good fallback.
- CoinGecko — secondary fallback. Rate-limited on free tier.
For fiat rates (XLM/NGN, USDC/NGN etc.), these should chain through USD as an intermediate: USDC → USD (effectively 1:1) and USD → NGN via a forex API (e.g. ExchangeRate-API, Open Exchange Rates, or a Central Bank API for NGN).
Implementation Plan
New package: apps/api/internal/oracle/
oracle/
rate.go // ExchangeRate type, Provider interface
stellar.go // Horizon order book source
defillama.go // DeFiLlama fallback
fiat.go // Forex feed for NGN/GHS/KES
cache.go // In-memory TTL cache (30s for crypto, 5min for fiat)
service.go // Aggregates sources with fallback logic
New endpoint:
GET /api/v1/rates?base=USDC"e=NGN
GET /api/v1/rates?base=XLM"e=USD
Response:
{
"success": true,
"data": {
"base": "USDC",
"quote": "NGN",
"rate": 1647.50,
"source": "horizon+forex",
"fetched_at": "2026-04-02T12:00:00Z",
"expires_at": "2026-04-02T12:05:00Z"
}
}
Wire into existing flows:
- Settlement service: include
estimated_local_amount in settlement creation response
- Vault handler: include
usd_value on vault balance responses
Caching Strategy
- Crypto rates: 30-second TTL (stale-while-revalidate acceptable)
- Fiat rates: 5-minute TTL
- On source failure: serve stale + set
stale: true flag in response, never error the whole request
Acceptance Criteria
Problem
Every page in the dApp that shows vault balances, deposit amounts, or settlement previews needs to display a fiat-equivalent value (USD, NGN, GHS, KES). Right now none of this is wired — the frontend either shows raw USDC amounts with no conversion or hardcodes a mock exchange rate. This becomes especially critical for the offramp flow where the user needs to see exactly how much local currency they will receive before confirming.
What's Needed
A lightweight exchange rate service baked into the Go API that can convert between the assets Nester uses (USDC, XLM) and the fiat currencies supported by the offramp (NGN, GHS, KES, USD).
Suggested Data Sources (in priority order)
/order_bookendpoint. Most accurate for Stellar-native assets, no third-party dependency.For fiat rates (XLM/NGN, USDC/NGN etc.), these should chain through USD as an intermediate:
USDC → USD(effectively 1:1) andUSD → NGNvia a forex API (e.g. ExchangeRate-API, Open Exchange Rates, or a Central Bank API for NGN).Implementation Plan
New package:
apps/api/internal/oracle/New endpoint:
Response:
{ "success": true, "data": { "base": "USDC", "quote": "NGN", "rate": 1647.50, "source": "horizon+forex", "fetched_at": "2026-04-02T12:00:00Z", "expires_at": "2026-04-02T12:05:00Z" } }Wire into existing flows:
estimated_local_amountin settlement creation responseusd_valueon vault balance responsesCaching Strategy
stale: trueflag in response, never error the whole requestAcceptance Criteria
GET /api/v1/ratesreturns conversion rate for any supported pairestimated_local_amountpre-calculated