@@ -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 . */
118118export 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