From 8179003a51b3e92bfce0bdad8c030fc000bc6d1b Mon Sep 17 00:00:00 2001 From: mUniKeS Date: Thu, 6 Aug 2026 02:59:12 +0200 Subject: [PATCH] fix: batch CoinGecko token price requests instead of one-per-token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit coingeckoPriceLookup was making one HTTP request per token address in a loop with a 250ms delay, despite CoinGecko's simple/token_price endpoint natively supporting comma-separated contract_addresses in a single call. For a broadcaster running 3 networks with ~6-8 tokens each, this meant ~20 requests per refresh cycle (every ~60s) instead of 3 — burning through the free Demo tier's 10,000 requests/month quota in about 10 hours of uptime. Also lowered batchSize from 50 to 30 to match CoinGecko's documented Demo tier limit of 30 addresses per request (50 would only be safe on paid tiers). --- src/server/api/coingecko/coingecko-price.ts | 36 ++++++++------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/server/api/coingecko/coingecko-price.ts b/src/server/api/coingecko/coingecko-price.ts index 0b609f94..8cd45e78 100644 --- a/src/server/api/coingecko/coingecko-price.ts +++ b/src/server/api/coingecko/coingecko-price.ts @@ -41,28 +41,20 @@ const coingeckoPriceLookup = async ( ): Promise => { const currency = 'usd'; - const paramArr = tokenAddresses.map((address) => { - return { - contract_addresses: address, - vs_currencies: currency, - include_last_updated_at: true, - }; - }); let coingeckoPriceMap: CoingeckoPriceMap = {}; - for (const params of paramArr) { - try { - // eslint-disable-next-line no-await-in-loop - const geckoPriceMap: CoingeckoPriceMap = await getCoingeckoData( - CoingeckoApiEndpoint.PriceLookup, - coingeckoNetworkId, - params, - ); - coingeckoPriceMap = { ...coingeckoPriceMap, ...geckoPriceMap }; - // eslint-disable-next-line no-await-in-loop - await delay(250); - } catch (error) { - console.error(error); - } + try { + const geckoPriceMap: CoingeckoPriceMap = await getCoingeckoData( + CoingeckoApiEndpoint.PriceLookup, + coingeckoNetworkId, + { + contract_addresses: tokenAddresses.join(','), + vs_currencies: currency, + include_last_updated_at: true, + }, + ); + coingeckoPriceMap = { ...coingeckoPriceMap, ...geckoPriceMap }; + } catch (error) { + console.error(error); } const tokenPrices = tokenPriceArrayFromCoingeckoPriceMap( @@ -77,7 +69,7 @@ export const coingeckoUpdatePricesByAddresses = async ( tokenAddresses: string[], updater: TokenPriceUpdater, ): Promise => { - const batchSize = 50; + const batchSize = 30; // CoinGecko Demo API tier limit is 30 addresses per request for (let i = 0; i < tokenAddresses.length; i += batchSize) { const batch = tokenAddresses.slice(i, i + batchSize); // eslint-disable-next-line no-await-in-loop