Context
The dfx-wallet app currently calls CoinGecko directly for dynamic token price discovery:
Goal: route this traffic through api.dfx.swiss so we
- avoid leaking client IPs / fingerprints to CoinGecko,
- benefit from the central CoinGecko Pro key + caching,
- protect the app against CoinGecko free-tier rate limits.
Proposal
Add a public, unauthenticated endpoint that mirrors the upstream shape:
GET /v1/pricing/simple-price?ids=<comma-list>&vs_currencies=<comma-list>
Response identical to CoinGecko's simple/price (so the wallet only needs to swap the base URL):
{
"bitcoin": { "usd": 67000, "eur": 62000 },
"ethereum": { "usd": 3500, "eur": 3240 }
}
Implementation notes
- Live next to existing
PricingController (src/subdomains/supporting/pricing/pricing.controller.ts).
- Reuse
CoinGeckoService / CoinGeckoClient — client.simplePrice({ ids, vs_currencies }) already returns the right shape (coin-gecko.service.ts:94).
- Validate inputs: cap
ids at 100 (CoinGecko free-tier URL length limit, also what the wallet already chunks at), whitelist vs_currencies against simpleSupportedCurrencies().
- Cache responses (60s TTL matches the internal
pricing-proxy).
- Alternatively front this with the existing
pricing-proxy service on dfxprd/dfxdev — same cache, same key. Either approach is fine; pass-through via CoinGeckoService is the smaller diff.
Out of scope
/coins/list endpoint (separate issue — also called by the wallet for token discovery validation).
- Contract-based price lookups (existing internal
getRawPrice already covers that path for backend consumers).
Follow-up (wallet side)
Once the endpoint is live, the wallet swaps the constant in coingecko-simple-price.ts to \${DFX_API_URL}/v1/pricing/simple-price and drops the direct CoinGecko call.
Context
The
dfx-walletapp currently calls CoinGecko directly for dynamic token price discovery:https://api.coingecko.com/api/v3/simple/price?ids=...&vs_currencies=...src/services/pricing/coingecko-simple-price.ts:15(COINGECKO_SIMPLE_PRICE)Goal: route this traffic through
api.dfx.swissso weProposal
Add a public, unauthenticated endpoint that mirrors the upstream shape:
Response identical to CoinGecko's
simple/price(so the wallet only needs to swap the base URL):{ "bitcoin": { "usd": 67000, "eur": 62000 }, "ethereum": { "usd": 3500, "eur": 3240 } }Implementation notes
PricingController(src/subdomains/supporting/pricing/pricing.controller.ts).CoinGeckoService/CoinGeckoClient—client.simplePrice({ ids, vs_currencies })already returns the right shape (coin-gecko.service.ts:94).idsat 100 (CoinGecko free-tier URL length limit, also what the wallet already chunks at), whitelistvs_currenciesagainstsimpleSupportedCurrencies().pricing-proxy).pricing-proxyservice on dfxprd/dfxdev — same cache, same key. Either approach is fine; pass-through viaCoinGeckoServiceis the smaller diff.Out of scope
/coins/listendpoint (separate issue — also called by the wallet for token discovery validation).getRawPricealready covers that path for backend consumers).Follow-up (wallet side)
Once the endpoint is live, the wallet swaps the constant in
coingecko-simple-price.tsto\${DFX_API_URL}/v1/pricing/simple-priceand drops the direct CoinGecko call.