@@ -140,14 +140,23 @@ async function loadExchangeRateCache(): Promise<ExchangeRateCacheFile> {
140140 const { cryptoPairs, fiatPairs, rates } = asExchangeRateCacheFile ( json )
141141
142142 // Keep un-expired asset pairs:
143+ const cryptoPairsMap = new Map < string , CryptoFiatPair > ( )
143144 for ( const pair of cryptoPairs ) {
144145 if ( pair . expiration < now ) continue
145- out . cryptoPairs . push ( pair )
146+ const tokenIdStr =
147+ pair . asset . tokenId != null ? `_${ pair . asset . tokenId } ` : ''
148+ const key = `${ pair . asset . pluginId } ${ tokenIdStr } _${ pair . targetFiat } `
149+ cryptoPairsMap . set ( key , { ...pair , isoDate : undefined } )
146150 }
151+ out . cryptoPairs = Array . from ( cryptoPairsMap . values ( ) )
152+
153+ const fiatPairsMap = new Map < string , FiatFiatPair > ( )
147154 for ( const pair of fiatPairs ) {
148155 if ( pair . expiration < now ) continue
149- out . fiatPairs . push ( pair )
156+ const key = `${ pair . fiatCode } _${ pair . targetFiat } `
157+ fiatPairsMap . set ( key , { ...pair , isoDate : undefined } )
150158 }
159+ out . fiatPairs = Array . from ( fiatPairsMap . values ( ) )
151160
152161 // Keep un-expired rates:
153162 for ( const [ pluginId , tokenObj ] of Object . entries ( rates . crypto ) ) {
@@ -309,112 +318,163 @@ async function fetchExchangeRates(
309318 }
310319
311320 const requests = convertToRatesParams ( cryptoPairMap , fiatPairMap )
312- for ( const query of requests ) {
313- for ( let attempt = 0 ; attempt < 5 ; ++ attempt ) {
314- const options = {
315- method : 'POST' ,
316- headers : { 'Content-Type' : 'application/json' } ,
317- body : JSON . stringify ( query )
318- }
319- try {
320- const response = await fetchRates ( 'v3/rates' , options )
321- if ( response . ok ) {
322- const json = await response . json ( )
323- const cleanedRates = asRatesParams ( json )
324- const targetFiat = fixFiatCurrencyCode ( cleanedRates . targetFiat )
325-
326- for ( const cryptoRate of cleanedRates . crypto ) {
327- const { asset, isoDate, rate } = cryptoRate
328- if ( rate == null ) continue
329-
330- const { pluginId, tokenId } = asset
331- const safeTokenId = tokenId ?? ''
332-
333- rates . crypto [ pluginId ] ??= { }
334- rates . crypto [ pluginId ] [ safeTokenId ] ??= { }
335- rates . crypto [ pluginId ] [ safeTokenId ] [ targetFiat ] ??= {
336- current : 0 ,
337- yesterday : 0 ,
338- yesterdayTimestamp : 0 ,
339- expiration : 0
340- }
321+ const promises = requests . map ( async query => {
322+ const options = {
323+ method : 'POST' ,
324+ headers : { 'Content-Type' : 'application/json' } ,
325+ body : JSON . stringify ( query )
326+ }
327+ try {
328+ const response = await fetchRates ( 'v3/rates' , options )
329+ if ( response . ok ) {
330+ const json = await response . json ( )
331+ const cleanedRates = asRatesParams ( json )
332+ const targetFiat = fixFiatCurrencyCode ( cleanedRates . targetFiat )
333+
334+ for ( const cryptoRate of cleanedRates . crypto ) {
335+ const { asset, isoDate, rate } = cryptoRate
336+ if ( rate == null ) continue
337+
338+ const { pluginId, tokenId } = asset
339+ const safeTokenId = tokenId ?? ''
340+
341+ rates . crypto [ pluginId ] ??= { }
342+ rates . crypto [ pluginId ] [ safeTokenId ] ??= { }
343+ rates . crypto [ pluginId ] [ safeTokenId ] [ targetFiat ] ??= {
344+ current : 0 ,
345+ yesterday : 0 ,
346+ yesterdayTimestamp : 0 ,
347+ expiration : 0
348+ }
341349
342- const rateObj = rates . crypto [ pluginId ] [ safeTokenId ] [ targetFiat ]
343-
344- const isHistorical =
345- isoDate != null && isoDate . getTime ( ) < now - ONE_HOUR
346- if ( isHistorical ) {
347- const dateTimestamp = isoDate . getTime ( )
348- const yesterdayTargetTimestamp = Date . parse ( yesterday )
349- const yesterdayRateTimestamp = rateObj . yesterdayTimestamp
350-
351- // update yesterday rate if we find one closer than we have
352- if (
353- Math . abs ( yesterdayTargetTimestamp - dateTimestamp ) <
354- Math . abs ( yesterdayTargetTimestamp - yesterdayRateTimestamp )
355- ) {
356- rates . crypto [ pluginId ] [ safeTokenId ] [
357- targetFiat
358- ] . yesterdayTimestamp = yesterdayTimestamp
359- rateObj . yesterday = rate
360- }
361- } else {
362- rateObj . current = rate
350+ const rateObj = rates . crypto [ pluginId ] [ safeTokenId ] [ targetFiat ]
351+
352+ const isHistorical =
353+ isoDate != null && isoDate . getTime ( ) < now - ONE_HOUR
354+ if ( isHistorical ) {
355+ const dateTimestamp = isoDate . getTime ( )
356+ const yesterdayTargetTimestamp = Date . parse ( yesterday )
357+ const yesterdayRateTimestamp = rateObj . yesterdayTimestamp
358+
359+ // update yesterday rate if we find one closer than we have
360+ if (
361+ Math . abs ( yesterdayTargetTimestamp - dateTimestamp ) <
362+ Math . abs ( yesterdayTargetTimestamp - yesterdayRateTimestamp )
363+ ) {
364+ rates . crypto [ pluginId ] [ safeTokenId ] [
365+ targetFiat
366+ ] . yesterdayTimestamp = yesterdayTimestamp
367+ rateObj . yesterday = rate
363368 }
369+ } else {
370+ rateObj . current = rate
371+ }
364372
365- rateObj . expiration = rateExpiration
373+ rateObj . expiration = rateExpiration
374+ }
375+ for ( const fiatRate of cleanedRates . fiat ) {
376+ const { isoDate, rate } = fiatRate
377+ const fiatCode = fixFiatCurrencyCode ( fiatRate . fiatCode )
378+ if ( rate == null ) continue
379+
380+ rates . fiat [ fiatCode ] ??= { }
381+ rates . fiat [ fiatCode ] [ targetFiat ] ??= {
382+ current : 0 ,
383+ yesterday : 0 ,
384+ yesterdayTimestamp : 0 ,
385+ expiration : 0
366386 }
367- for ( const fiatRate of cleanedRates . fiat ) {
368- const { isoDate, rate } = fiatRate
369- const fiatCode = fixFiatCurrencyCode ( fiatRate . fiatCode )
370- if ( rate == null ) continue
371-
372- rates . fiat [ fiatCode ] ??= { }
373- rates . fiat [ fiatCode ] [ targetFiat ] ??= {
374- current : 0 ,
375- yesterday : 0 ,
376- yesterdayTimestamp : 0 ,
377- expiration : 0
378- }
379- const rateObj = rates . fiat [ fiatCode ] [ targetFiat ]
380-
381- const isHistorical =
382- isoDate != null && isoDate . getTime ( ) < now - ONE_HOUR
383- if ( isHistorical ) {
384- const dateTimestamp = isoDate . getTime ( )
385- const yesterdayTargetTimestamp = Date . parse ( yesterday )
386- const yesterdayRateTimestamp = rateObj . yesterdayTimestamp
387-
388- // update yesterday rate if we find one closer than we have
389- if (
390- Math . abs ( yesterdayTargetTimestamp - dateTimestamp ) <
391- Math . abs ( yesterdayTargetTimestamp - yesterdayRateTimestamp )
392- ) {
393- rates . fiat [ fiatCode ] [ targetFiat ] . yesterdayTimestamp =
394- yesterdayTimestamp
395- rateObj . yesterday = rate
396- }
397- } else {
398- rateObj . current = rate
387+ const rateObj = rates . fiat [ fiatCode ] [ targetFiat ]
388+
389+ const isHistorical =
390+ isoDate != null && isoDate . getTime ( ) < now - ONE_HOUR
391+ if ( isHistorical ) {
392+ const dateTimestamp = isoDate . getTime ( )
393+ const yesterdayTargetTimestamp = Date . parse ( yesterday )
394+ const yesterdayRateTimestamp = rateObj . yesterdayTimestamp
395+
396+ // update yesterday rate if we find one closer than we have
397+ if (
398+ Math . abs ( yesterdayTargetTimestamp - dateTimestamp ) <
399+ Math . abs ( yesterdayTargetTimestamp - yesterdayRateTimestamp )
400+ ) {
401+ rates . fiat [ fiatCode ] [ targetFiat ] . yesterdayTimestamp =
402+ yesterdayTimestamp
403+ rateObj . yesterday = rate
399404 }
400-
401- rateObj . expiration = rateExpiration
405+ } else {
406+ rateObj . current = rate
402407 }
403- break
408+
409+ rateObj . expiration = rateExpiration
404410 }
405- } catch ( error : unknown ) {
406- console . log (
407- `buildExchangeRates error querying rates server ${ String ( error ) } `
411+ }
412+ } catch ( error : unknown ) {
413+ console . log (
414+ `buildExchangeRates error querying rates server ${ String ( error ) } `
415+ )
416+ }
417+ } )
418+ await Promise . allSettled ( promises )
419+
420+ // Merge successful rate responses into the pair cache
421+ const cryptoPairCache = [ ...( exchangeRateCache ?. cryptoPairs ?? [ ] ) ]
422+ const fiatPairCache = [ ...( exchangeRateCache ?. fiatPairs ?? [ ] ) ]
423+ for ( const [ pluginId , tokenObj ] of Object . entries ( rates . crypto ) ) {
424+ for ( const [ tokenId , rateObj ] of Object . entries ( tokenObj ) ) {
425+ for ( const targetFiat of Object . keys ( rateObj ) ) {
426+ const edgeTokenId = tokenId === '' ? null : tokenId
427+ const cryptoPairIndex = cryptoPairCache . findIndex (
428+ pair =>
429+ pair . asset . pluginId === pluginId &&
430+ pair . asset . tokenId === edgeTokenId &&
431+ pair . targetFiat === targetFiat
408432 )
433+ if ( cryptoPairIndex === - 1 ) {
434+ cryptoPairCache . push ( {
435+ asset : { pluginId, tokenId : edgeTokenId } ,
436+ targetFiat,
437+ isoDate : undefined ,
438+ expiration : pairExpiration
439+ } )
440+ } else {
441+ cryptoPairCache [ cryptoPairIndex ] = {
442+ asset : { pluginId, tokenId : edgeTokenId } ,
443+ targetFiat,
444+ isoDate : undefined ,
445+ expiration : pairExpiration
446+ }
447+ }
448+ }
449+ }
450+ }
451+ for ( const [ fiatCode , fiatObj ] of Object . entries ( rates . fiat ) ) {
452+ for ( const targetFiat of Object . keys ( fiatObj ) ) {
453+ const fiatPairIndex = fiatPairCache . findIndex (
454+ pair => pair . fiatCode === fiatCode && pair . targetFiat === targetFiat
455+ )
456+ if ( fiatPairIndex === - 1 ) {
457+ fiatPairCache . push ( {
458+ fiatCode,
459+ targetFiat,
460+ isoDate : undefined ,
461+ expiration : pairExpiration
462+ } )
463+ } else {
464+ fiatPairCache [ fiatPairIndex ] = {
465+ fiatCode,
466+ targetFiat,
467+ isoDate : undefined ,
468+ expiration : pairExpiration
469+ }
409470 }
410471 }
411472 }
412-
413473 // Update the in-memory cache:
414474 exchangeRateCache = {
415475 rates,
416- cryptoPairs : Array . from ( cryptoPairMap . values ( ) ) ,
417- fiatPairs : Array . from ( fiatPairMap . values ( ) )
476+ cryptoPairs : cryptoPairCache ,
477+ fiatPairs : fiatPairCache
418478 }
419479
420480 // Write the cache to disk:
0 commit comments