Skip to content

Commit 1bf30e1

Browse files
authored
Merge pull request #386 from DevSolex/fix/251-getAllRates-batched-coingecko
fix(#251): batch all CoinGecko prices in a single request in getAllRates
2 parents f5f79fb + ffd4e5a commit 1bf30e1

1 file changed

Lines changed: 37 additions & 6 deletions

File tree

backend/src/services/exchangeRate.js

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,48 @@ export async function convert(amount, from, to) {
114114
return parseFloat((amount * rate).toFixed(7));
115115
}
116116

117-
/** Fetch all supported pair rates at once. */
117+
/** Fetch all supported pair rates at once via a single batched CoinGecko request. */
118118
export async function getAllRates() {
119-
const pairs = [];
119+
// Collect assets that have a CoinGecko ID and aren't fully cached yet
120+
const needed = SUPPORTED_ASSETS.filter(a => COINGECKO_IDS[a]);
121+
122+
// Single batched request: all coin IDs vs USD (USDC is pegged 1:1 to USD)
123+
const pricesUsd = {};
124+
try {
125+
const ids = needed.map(a => COINGECKO_IDS[a]).join(',');
126+
const apiKey = process.env.COINGECKO_API_KEY;
127+
const headers = apiKey ? { 'x-cg-demo-api-key': apiKey } : {};
128+
const res = await fetch(
129+
`${COINGECKO_BASE}/simple/price?ids=${ids}&vs_currencies=usd`,
130+
{ headers, signal: AbortSignal.timeout(5_000) }
131+
);
132+
if (res.ok) {
133+
const data = await res.json();
134+
for (const asset of needed) {
135+
const usd = data[COINGECKO_IDS[asset]]?.usd;
136+
if (usd != null) pricesUsd[asset] = usd;
137+
}
138+
lastFetchAt = Date.now();
139+
}
140+
} catch (err) {
141+
logger.warn('exchangeRate.getAllRates.coingecko.failed', { error: err.message });
142+
}
143+
144+
// Derive all pairs from USD prices, fall back to getRate for anything missing
145+
const results = [];
120146
for (const from of SUPPORTED_ASSETS) {
121147
for (const to of SUPPORTED_ASSETS) {
122-
if (from !== to) pairs.push({ from, to });
148+
if (from === to) continue;
149+
let rate = getCached(from, to);
150+
if (rate == null && pricesUsd[from] != null && pricesUsd[to] != null) {
151+
rate = pricesUsd[from] / pricesUsd[to];
152+
setCache(from, to, rate);
153+
notifyIfChanged(from, to, rate);
154+
}
155+
if (rate == null) rate = await getRate(from, to); // fallback (DEX / cache)
156+
results.push({ from, to, rate });
123157
}
124158
}
125-
const results = await Promise.all(pairs.map(async ({ from, to }) => ({
126-
from, to, rate: await getRate(from, to),
127-
})));
128159
return results;
129160
}
130161

0 commit comments

Comments
 (0)