diff --git a/web/cashtab/src/hooks/useWallet.js b/web/cashtab/src/hooks/useWallet.js --- a/web/cashtab/src/hooks/useWallet.js +++ b/web/cashtab/src/hooks/useWallet.js @@ -262,12 +262,11 @@ const preliminaryTokensArray = getPreliminaryTokensArray(slpUtxos); console.log(`preliminaryTokensArray`, preliminaryTokensArray); - const finalTokenArray = await finalizeTokensArray( - chronik, - preliminaryTokensArray, - ); + const { finalTokenArray, cachedTokenInfoByTokenId } = + await finalizeTokensArray(chronik, preliminaryTokensArray); console.log(`finalTokenArray`, finalTokenArray); + console.log(`cachedTokenInfoByTokenId`, cachedTokenInfoByTokenId); // If an error is returned or utxos from only 1 address are returned if ( diff --git a/web/cashtab/src/utils/__tests__/chronik.test.js b/web/cashtab/src/utils/__tests__/chronik.test.js --- a/web/cashtab/src/utils/__tests__/chronik.test.js +++ b/web/cashtab/src/utils/__tests__/chronik.test.js @@ -1,7 +1,6 @@ import { organizeUtxosByType, getPreliminaryTokensArray, - updateCachedTokenInfoAndFinalizeTokensArray, finalizeTokensArray, } from 'utils/chronik'; import { @@ -55,7 +54,7 @@ ).toStrictEqual(mockPreliminaryTokensArray); }); -it(`finalizeTokensArray successfully returns finalTokenArray`, async () => { +it(`finalizeTokensArray successfully returns finalTokenArray and cachedTokenInfoById even if no cachedTokenInfoById is provided`, async () => { // Initialize chronik const chronik = new ChronikClient( 'https://FakeChronikUrlToEnsureMocksOnly.com', @@ -73,5 +72,54 @@ expect( await finalizeTokensArray(chronik, mockPreliminaryTokensArray), - ).toStrictEqual(mockFinalTokenArray); + ).toStrictEqual({ + finalTokenArray: mockFinalTokenArray, + cachedTokenInfoById: mockFinalCachedTokenInfo, + }); +}); + +it(`finalizeTokensArray successfully returns finalTokenArray and cachedTokenInfoById when called with all token info in cache`, async () => { + // Initialize chronik + const chronik = new ChronikClient( + 'https://FakeChronikUrlToEnsureMocksOnly.com', + ); + + expect( + await finalizeTokensArray( + chronik, + mockPreliminaryTokensArrayClone, + mockFinalCachedTokenInfo, + ), + ).toStrictEqual({ + finalTokenArray: mockFinalTokenArray, + cachedTokenInfoById: mockFinalCachedTokenInfo, + }); +}); + +it(`updateCachedTokenInfoAndFinalizeTokensArray successfully returns finalTokenArray and cachedTokenInfoById when called with some token info in cache`, async () => { + // Initialize chronik + const chronik = new ChronikClient( + 'https://FakeChronikUrlToEnsureMocksOnly.com', + ); + /* + Mock the API response from chronik.tx('tokenId') called + in returnGetTokenInfoChronikPromise -- for each tokenId used + */ + chronik.tx = jest.fn(); + for (let i = 0; i < mockPartialChronikTxDetailsResponses.length; i += 1) { + when(chronik.tx) + .calledWith(mockPartialChronikTxDetailsResponses[i].txid) + .mockResolvedValue(mockPartialChronikTxDetailsResponses[i]); + } + + expect( + await finalizeTokensArray( + chronik, + mockPreliminaryTokensArrayCloneClone, + mockPartialCachedTokenInfo, + ), + ).toStrictEqual({ + finalTokenArray: mockFinalTokenArray, + cachedTokenInfoById: mockFinalCachedTokenInfo, + }); }); diff --git a/web/cashtab/src/utils/chronik.js b/web/cashtab/src/utils/chronik.js --- a/web/cashtab/src/utils/chronik.js +++ b/web/cashtab/src/utils/chronik.js @@ -204,7 +204,11 @@ return finalTokenArray; }; -export const finalizeTokensArray = async (chronik, preliminaryTokensArray) => { +export const finalizeTokensArray = async ( + chronik, + preliminaryTokensArray, + cachedTokenInfoById = {}, +) => { // Iterate over preliminaryTokensArray to determine what tokens you need to make API calls for // Create an array of promises @@ -213,6 +217,11 @@ for (let i = 0; i < preliminaryTokensArray.length; i += 1) { const thisTokenId = preliminaryTokensArray[i].tokenId; + // See if you already have this info in cachedTokenInfo + if (thisTokenId in cachedTokenInfoById) { + // If you already have this info in cache, do not create an API request for it + continue; + } const thisTokenInfoPromise = returnGetTokenInfoChronikPromise( chronik, thisTokenId, @@ -220,6 +229,12 @@ getTokenInfoPromises.push(thisTokenInfoPromise); } + // For this test plan, to be removed later in stack + console.log( + `Cashtab asking chronik for token info about ${getTokenInfoPromises.length} tokens`, + ); + console.log(`getTokenInfoPromises.length`, getTokenInfoPromises.length); + // Get all the token info you need let tokenInfoArray = []; try { @@ -228,9 +243,8 @@ console.log(`Error in Promise.all(getTokenInfoPromises)`, err); } - // Create a reference object that indexes token metadata by token ID - // This object can then be used to add token metadata to each token ID - const tokenInfoByTokenId = {}; + // Add the token info you received from those API calls to + // your token info cache object, cachedTokenInfoByTokenId for (let i = 0; i < tokenInfoArray.length; i += 1) { /* tokenInfoArray is an array of objects that look like { @@ -246,15 +260,15 @@ const thisTokenInfo = tokenInfoArray[i]; const thisTokenId = thisTokenInfo.tokenId; // Add this entry to updatedCachedTokenInfo - tokenInfoByTokenId[thisTokenId] = thisTokenInfo; + cachedTokenInfoById[thisTokenId] = thisTokenInfo; } - // Now use tokenInfoByTokenId object to finalize token info + // Now use cachedTokenInfoByTokenId object to finalize token info // Split this out into a separate function so you can unit test const finalTokenArray = processPreliminaryTokensArray( preliminaryTokensArray, - tokenInfoByTokenId, + cachedTokenInfoById, ); - return finalTokenArray; + return { finalTokenArray, cachedTokenInfoById }; };