diff --git a/cashtab/src/chronik/__tests__/index.test.js b/cashtab/src/chronik/__tests__/index.test.js --- a/cashtab/src/chronik/__tests__/index.test.js +++ b/cashtab/src/chronik/__tests__/index.test.js @@ -118,9 +118,9 @@ Mock the API response from chronik.tx('tokenId') called in returnGetTokenInfoChronikPromise -- for each tokenId used */ - chronik.tx = jest.fn(); + chronik.token = jest.fn(); for (let i = 0; i < mockChronikTxDetailsResponses.length; i += 1) { - when(chronik.tx) + when(chronik.token) .calledWith(mockChronikTxDetailsResponses[i].txid) .mockResolvedValue(mockChronikTxDetailsResponses[i]); } @@ -129,7 +129,7 @@ await finalizeTokensArray(chronik, mockPreliminaryTokensArray), ).toStrictEqual({ tokens: mockFinalTokenArray, - updatedTokenInfoById: mockFinalCachedTokenInfo, + cachedTokens: mockFinalCachedTokenInfo, newTokensToCache: true, }); }); @@ -148,7 +148,7 @@ ), ).toStrictEqual({ tokens: mockFinalTokenArray, - updatedTokenInfoById: mockFinalCachedTokenInfo, + cachedTokens: mockFinalCachedTokenInfo, newTokensToCache: false, }); }); @@ -159,12 +159,12 @@ 'https://FakeChronikUrlToEnsureMocksOnly.com', ); /* - Mock the API response from chronik.tx('tokenId') called + Mock the API response from chronik.token('tokenId') called in returnGetTokenInfoChronikPromise -- for each tokenId used */ - chronik.tx = jest.fn(); + chronik.token = jest.fn(); for (let i = 0; i < mockPartialChronikTxDetailsResponses.length; i += 1) { - when(chronik.tx) + when(chronik.token) .calledWith(mockPartialChronikTxDetailsResponses[i].txid) .mockResolvedValue(mockPartialChronikTxDetailsResponses[i]); } @@ -177,7 +177,7 @@ ), ).toStrictEqual({ tokens: mockFinalTokenArray, - updatedTokenInfoById: mockFinalCachedTokenInfo, + cachedTokens: mockFinalCachedTokenInfo, newTokensToCache: true, }); }); diff --git a/cashtab/src/chronik/fixtures/chronikUtxos.js b/cashtab/src/chronik/fixtures/chronikUtxos.js --- a/cashtab/src/chronik/fixtures/chronikUtxos.js +++ b/cashtab/src/chronik/fixtures/chronikUtxos.js @@ -6977,8 +6977,6 @@ tokenDocumentUrl: 'developer.bitcoin.com', tokenDocumentHash: '', decimals: 0, - tokenId: - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd', }, }, block: { @@ -8224,8 +8222,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1', }, }, block: { @@ -8316,8 +8312,6 @@ 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', tokenDocumentHash: '', decimals: 0, - tokenId: - '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', }, }, block: { @@ -8407,8 +8401,6 @@ tokenDocumentUrl: '', tokenDocumentHash: '', decimals: 0, - tokenId: - 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', }, }, block: { @@ -8498,8 +8490,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', }, }, block: { @@ -8592,8 +8582,6 @@ tokenDocumentUrl: '', tokenDocumentHash: '', decimals: 8, - tokenId: - 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', }, }, block: { @@ -8666,8 +8654,6 @@ tokenDocumentUrl: 'boomertakes.com', tokenDocumentHash: '', decimals: 5, - tokenId: - '22f4ba40312ea3e90e1bfa88d2aa694c271d2e07361907b6eb5568873ffa62bf', }, }, block: { @@ -8740,8 +8726,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'aa7202397a06097e8ff36855aa72c0ee032659747e5bd7cbcd3099fc3a62b6b6', }, }, block: { @@ -8818,8 +8802,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'da9460ce4b1c92b4f6ef4e4a6bc2d05539f49d02b17681389d9ce22b8dca50f0', }, }, block: { @@ -8892,8 +8874,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875', }, }, block: { @@ -8974,8 +8954,6 @@ tokenDocumentUrl: 'https://boomertakes.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - '16b12bbacdbb8c8a799adbfd782bfff9843c1f9b0be148eaae02a1a7f74f95c4', }, }, block: { @@ -9057,8 +9035,6 @@ tokenDocumentUrl: 'https://thecryptoguy.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba', }, }, block: { @@ -9131,8 +9107,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 2, - tokenId: - '9e9738e9ac3ff202736bf7775f875ebae6f812650df577a947c20c52475e43da', }, }, block: { @@ -9205,8 +9179,6 @@ tokenDocumentUrl: 'https://www.proofofwriting.com/26', tokenDocumentHash: '', decimals: 0, - tokenId: - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a', }, }, block: { @@ -9287,8 +9259,6 @@ tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', tokenDocumentHash: '', decimals: 0, - tokenId: - '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', }, }, block: { @@ -9361,8 +9331,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48', }, }, block: { @@ -9431,8 +9399,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '3515f4a9851ad44124e0ddf6149344deb27a97720fc7e5254a9d2c86da7415a9', }, }, block: { @@ -9501,8 +9467,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '6fb6122742cac8fd1df2d68997fdfa4c077bc22d9ef4a336bfb63d24225f9060', }, }, block: { @@ -9571,8 +9535,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '2936188a41f22a3e0a47d13296147fb3f9ddd2f939fe6382904d21a610e8e49c', }, }, block: { @@ -9645,8 +9607,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 1, - tokenId: - 'e859eeb52e7afca6217fb36784b3b6d3c7386a52f391dd0d00f2ec03a5e8e77b', }, }, block: { @@ -9727,8 +9687,6 @@ tokenDocumentUrl: 'https://cashtab.com', tokenDocumentHash: '', decimals: 0, - tokenId: - 'bdb3b4215ca0622e0c4c07655522c376eaa891838a82f0217fa453bb0595a37c', }, }, block: { @@ -9849,8 +9807,6 @@ tokenDocumentHash: '85b591c15c9f49531e39fcfeb2a5a26b2bd0f7c018fb9cd71b5d92dfb732d5cc', decimals: 7, - tokenId: - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', }, }, block: { @@ -9923,8 +9879,6 @@ tokenDocumentUrl: 'https://en.wikipedia.org/wiki/COVID-19', tokenDocumentHash: '', decimals: 0, - tokenId: - '7bbf452698a24b138b0357f689587fc6ea58410c34503b1179b91e40e10bba8b', }, }, block: { @@ -9988,8 +9942,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '6376cae692cf0302ecdd63234c14cbb2b21cec75ab538335f90254cfb3ed44cc', }, }, block: { @@ -10062,8 +10014,6 @@ tokenDocumentUrl: 'thecryptoguy.com', tokenDocumentHash: '', decimals: 0, - tokenId: - '666c4318d1f7fef5f2c698262492c519018d4e9130f95d05f6be9f0fb7149e96', }, }, block: { @@ -10136,8 +10086,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '157e0cdef5d5c51bdea00eac9ab821d809bb9d03cf98da85833614bedb129be6', }, }, block: { @@ -10219,8 +10167,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', }, }, block: { @@ -10294,8 +10240,6 @@ 'https://twinpeaks.fandom.com/wiki/Garmonbozia', tokenDocumentHash: '', decimals: 8, - tokenId: - 'ccf5fe5a387559c8ab9efdeb0c0ef1b444e677298cfddf07671245ce3cb3c79f', }, }, block: { @@ -10386,8 +10330,6 @@ 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', tokenDocumentHash: '', decimals: 0, - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', }, }, block: { @@ -10460,8 +10402,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', }, }, block: { @@ -10551,8 +10491,6 @@ tokenDocumentUrl: 'https://boomertakes.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', }, }, block: { @@ -10625,8 +10563,6 @@ tokenDocumentUrl: 'boomertakes.com', tokenDocumentHash: '', decimals: 2, - tokenId: - '3de671a7107d3803d78f7f4a4e5c794d0903a8d28d16076445c084943c1e2db8', }, }, block: { @@ -10695,8 +10631,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '44929ff3b1fc634f982fede112cf12b21199a2ebbcf718412a38de9177d77168', }, }, block: { @@ -10769,8 +10703,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - '639a8dba34788ff3ebd3977d4ac045825394285ee648bb1d159e1c12b787ff25', }, }, block: { @@ -10839,8 +10771,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'd376ebcd518067c8e10c0505865cf7336160b47807e6f1a95739ba90ae838840', }, }, block: { @@ -10913,8 +10843,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'b40d1f6acdb6ee68d7eca0167fe2753c076bc309b2e3b1af8bff70ca34b945b0', }, }, block: { @@ -10978,8 +10906,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'b39fdb53e21d67fa5fd3a11122f1452f15884047f2b80e8efe633c3b520b7a39', }, }, block: { @@ -11052,8 +10978,6 @@ tokenDocumentUrl: 'cdc.gov', tokenDocumentHash: '', decimals: 0, - tokenId: - '3adbf501e21c711d20118e003711168eb39f560c01f4c6d6736fa3f3fceaa577', }, }, block: { @@ -11134,8 +11058,6 @@ tokenDocumentUrl: 'thecryptoguy.com', tokenDocumentHash: '', decimals: 0, - tokenId: - '0916e71779c9de7ee125741d3f5ab01f556356dbc86fd327a24f1e9e22ebc917', }, }, block: { @@ -11208,8 +11130,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '6e24e89b6d5284138c69777527760500b99614631bca7f2a5c38f4648dae9524', }, }, block: { @@ -11283,8 +11203,6 @@ tokenDocumentHash: 'b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553', decimals: 8, - tokenId: - '8ead21ce4b3b9e7b57607b97b65b5013496dc6e3dfdea162c08ce7265a66ebc8', }, }, block: { @@ -11365,8 +11283,6 @@ tokenDocumentUrl: 'thecryptoguy.com', tokenDocumentHash: '', decimals: 8, - tokenId: - 'e4e1a2fb071fa71ca727e08ed1d8ea52a9531c79d1e5f1ebf483c66b71a8621c', }, }, block: { @@ -11439,8 +11355,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 5, - tokenId: - '45f0ff5cae7e89da6b96c26c8c48a959214c5f0e983e78d0925f8956ca8848c6', }, }, block: { @@ -11521,8 +11435,6 @@ tokenDocumentUrl: 'coinex.com', tokenDocumentHash: '', decimals: 0, - tokenId: - '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6', }, }, block: { @@ -11549,8 +11461,6 @@ 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', tokenDocumentHash: '', decimals: 0, - tokenId: - '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', }, }, { @@ -11563,8 +11473,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '3515f4a9851ad44124e0ddf6149344deb27a97720fc7e5254a9d2c86da7415a9', }, }, { @@ -11577,8 +11485,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '6fb6122742cac8fd1df2d68997fdfa4c077bc22d9ef4a336bfb63d24225f9060', }, }, { @@ -11591,8 +11497,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '2936188a41f22a3e0a47d13296147fb3f9ddd2f939fe6382904d21a610e8e49c', }, }, { @@ -11605,8 +11509,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '6e24e89b6d5284138c69777527760500b99614631bca7f2a5c38f4648dae9524', }, }, { @@ -11619,8 +11521,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - '639a8dba34788ff3ebd3977d4ac045825394285ee648bb1d159e1c12b787ff25', }, }, { @@ -11633,8 +11533,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'd376ebcd518067c8e10c0505865cf7336160b47807e6f1a95739ba90ae838840', }, }, { @@ -11647,8 +11545,6 @@ tokenDocumentUrl: 'https://boomertakes.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - '16b12bbacdbb8c8a799adbfd782bfff9843c1f9b0be148eaae02a1a7f74f95c4', }, }, { @@ -11661,8 +11557,6 @@ tokenDocumentUrl: 'boomertakes.com', tokenDocumentHash: '', decimals: 5, - tokenId: - '22f4ba40312ea3e90e1bfa88d2aa694c271d2e07361907b6eb5568873ffa62bf', }, }, { @@ -11675,8 +11569,6 @@ tokenDocumentUrl: 'boomertakes.com', tokenDocumentHash: '', decimals: 2, - tokenId: - '3de671a7107d3803d78f7f4a4e5c794d0903a8d28d16076445c084943c1e2db8', }, }, { @@ -11689,8 +11581,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '157e0cdef5d5c51bdea00eac9ab821d809bb9d03cf98da85833614bedb129be6', }, }, { @@ -11703,8 +11593,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '6376cae692cf0302ecdd63234c14cbb2b21cec75ab538335f90254cfb3ed44cc', }, }, { @@ -11717,8 +11605,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 5, - tokenId: - '45f0ff5cae7e89da6b96c26c8c48a959214c5f0e983e78d0925f8956ca8848c6', }, }, { @@ -11731,8 +11617,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '44929ff3b1fc634f982fede112cf12b21199a2ebbcf718412a38de9177d77168', }, }, { @@ -11745,8 +11629,6 @@ tokenDocumentUrl: 'https://en.wikipedia.org/wiki/COVID-19', tokenDocumentHash: '', decimals: 0, - tokenId: - '7bbf452698a24b138b0357f689587fc6ea58410c34503b1179b91e40e10bba8b', }, }, { @@ -11759,8 +11641,6 @@ tokenDocumentUrl: 'thecryptoguy.com', tokenDocumentHash: '', decimals: 8, - tokenId: - 'e4e1a2fb071fa71ca727e08ed1d8ea52a9531c79d1e5f1ebf483c66b71a8621c', }, }, { @@ -11773,8 +11653,6 @@ tokenDocumentUrl: 'thecryptoguy.com', tokenDocumentHash: '', decimals: 0, - tokenId: - '666c4318d1f7fef5f2c698262492c519018d4e9130f95d05f6be9f0fb7149e96', }, }, { @@ -11787,8 +11665,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', }, }, { @@ -11801,8 +11677,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', }, }, { @@ -11815,8 +11689,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'aa7202397a06097e8ff36855aa72c0ee032659747e5bd7cbcd3099fc3a62b6b6', }, }, { @@ -11829,8 +11701,6 @@ tokenDocumentUrl: 'thecryptoguy.com', tokenDocumentHash: '', decimals: 0, - tokenId: - '0916e71779c9de7ee125741d3f5ab01f556356dbc86fd327a24f1e9e22ebc917', }, }, { @@ -11843,8 +11713,6 @@ tokenDocumentUrl: 'coinex.com', tokenDocumentHash: '', decimals: 0, - tokenId: - '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6', }, }, { @@ -11857,8 +11725,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1', }, }, { @@ -11871,8 +11737,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 2, - tokenId: - '9e9738e9ac3ff202736bf7775f875ebae6f812650df577a947c20c52475e43da', }, }, { @@ -11885,8 +11749,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48', }, }, { @@ -11899,8 +11761,6 @@ tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', tokenDocumentHash: '', decimals: 0, - tokenId: - '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', }, }, { @@ -11914,8 +11774,6 @@ tokenDocumentHash: 'b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553', decimals: 8, - tokenId: - '8ead21ce4b3b9e7b57607b97b65b5013496dc6e3dfdea162c08ce7265a66ebc8', }, }, { @@ -11928,8 +11786,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'b40d1f6acdb6ee68d7eca0167fe2753c076bc309b2e3b1af8bff70ca34b945b0', }, }, { @@ -11942,8 +11798,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875', }, }, { @@ -11956,8 +11810,6 @@ tokenDocumentUrl: '', tokenDocumentHash: '', decimals: 8, - tokenId: - 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', }, }, { @@ -11971,8 +11823,6 @@ 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', tokenDocumentHash: '', decimals: 0, - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', }, }, { @@ -11985,8 +11835,6 @@ tokenDocumentUrl: 'cdc.gov', tokenDocumentHash: '', decimals: 0, - tokenId: - '3adbf501e21c711d20118e003711168eb39f560c01f4c6d6736fa3f3fceaa577', }, }, { @@ -11999,8 +11847,6 @@ tokenDocumentUrl: 'https://www.proofofwriting.com/26', tokenDocumentHash: '', decimals: 0, - tokenId: - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a', }, }, { @@ -12013,8 +11859,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'da9460ce4b1c92b4f6ef4e4a6bc2d05539f49d02b17681389d9ce22b8dca50f0', }, }, { @@ -12027,8 +11871,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - 'b39fdb53e21d67fa5fd3a11122f1452f15884047f2b80e8efe633c3b520b7a39', }, }, { @@ -12041,8 +11883,6 @@ tokenDocumentUrl: 'https://cashtab.com', tokenDocumentHash: '', decimals: 0, - tokenId: - 'bdb3b4215ca0622e0c4c07655522c376eaa891838a82f0217fa453bb0595a37c', }, }, { @@ -12055,8 +11895,6 @@ tokenDocumentUrl: 'developer.bitcoin.com', tokenDocumentHash: '', decimals: 0, - tokenId: - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd', }, }, { @@ -12069,8 +11907,6 @@ tokenDocumentUrl: '', tokenDocumentHash: '', decimals: 0, - tokenId: - 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', }, }, { @@ -12083,8 +11919,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', }, }, { @@ -12097,8 +11931,6 @@ tokenDocumentUrl: 'https://thecryptoguy.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba', }, }, { @@ -12111,8 +11943,6 @@ tokenDocumentUrl: 'https://cashtab.com/', tokenDocumentHash: '', decimals: 1, - tokenId: - 'e859eeb52e7afca6217fb36784b3b6d3c7386a52f391dd0d00f2ec03a5e8e77b', }, }, { @@ -12128,8 +11958,6 @@ tokenDocumentHash: '85b591c15c9f49531e39fcfeb2a5a26b2bd0f7c018fb9cd71b5d92dfb732d5cc', decimals: 7, - tokenId: - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', }, }, { @@ -12142,8 +11970,6 @@ tokenDocumentUrl: 'https://boomertakes.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', }, }, { @@ -12156,13 +11982,11 @@ tokenDocumentUrl: 'https://twinpeaks.fandom.com/wiki/Garmonbozia', tokenDocumentHash: '', decimals: 8, - tokenId: - 'ccf5fe5a387559c8ab9efdeb0c0ef1b444e677298cfddf07671245ce3cb3c79f', }, }, ]; -export const mockFinalCachedTokenInfo = { +export const legacyMockFinalCachedTokenInfo = { 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd': { tokenTicker: 'ST', tokenName: 'ST', @@ -12566,8 +12390,19 @@ '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6', }, }; +const calculatedMockFinalCachedTokenInfo = new Map(); +const legacyCachedTokenIds = Object.keys(legacyMockFinalCachedTokenInfo); +for (const tokenId of legacyCachedTokenIds) { + const legacyGenesisInfo = JSON.parse( + JSON.stringify(legacyMockFinalCachedTokenInfo[tokenId]), + ); + // Remove the tokenId key which we do not need stored at the value + delete legacyGenesisInfo.tokenId; + calculatedMockFinalCachedTokenInfo.set(tokenId, legacyGenesisInfo); +} +export const mockFinalCachedTokenInfo = calculatedMockFinalCachedTokenInfo; -export const mockPartialCachedTokenInfo = { +export const legacyMockPartialCachedTokenInfo = { '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901': { tokenTicker: '🍔', tokenName: 'Burger', @@ -12945,6 +12780,19 @@ '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6', }, }; +const calculatedMockPartialCachedTokenInfo = new Map(); +const legacyMockPartialCachedTokenIds = Object.keys( + legacyMockPartialCachedTokenInfo, +); +for (const tokenId of legacyMockPartialCachedTokenIds) { + const legacyGenesisInfo = JSON.parse( + JSON.stringify(legacyMockPartialCachedTokenInfo[tokenId]), + ); + // Remove the tokenId key which we do not need stored at the value + delete legacyGenesisInfo.tokenId; + calculatedMockPartialCachedTokenInfo.set(tokenId, legacyGenesisInfo); +} +export const mockPartialCachedTokenInfo = calculatedMockPartialCachedTokenInfo; export const mockPartialChronikTxDetailsResponses = [ { @@ -13020,8 +12868,6 @@ tokenDocumentUrl: 'developer.bitcoin.com', tokenDocumentHash: '', decimals: 0, - tokenId: - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd', }, }, block: { @@ -14267,8 +14113,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1', }, }, block: { @@ -14341,8 +14185,6 @@ tokenDocumentUrl: 'https://www.proofofwriting.com/26', tokenDocumentHash: '', decimals: 0, - tokenId: - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a', }, }, block: { @@ -16383,7 +16225,8 @@ tokenQty: '888.88888888', }, ]; -export const mockTokenInfoById = { + +export const legacyMockTokenInfoById = { 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd': { tokenTicker: 'ST', tokenName: 'ST', @@ -16796,6 +16639,17 @@ '56e9b1d16c9989186c846187db57d9a9389c3ecc74e7237c1d1d0327cf904a55', }, }; +const calculatedMockTokenInfoById = new Map(); +const legacyMockTokenInfoByIdTokenIds = Object.keys(legacyMockTokenInfoById); +for (const tokenId of legacyMockTokenInfoByIdTokenIds) { + const legacyGenesisInfo = JSON.parse( + JSON.stringify(legacyMockTokenInfoById[tokenId]), + ); + // Remove the tokenId key which we do not need stored at the value + delete legacyGenesisInfo.tokenId; + calculatedMockTokenInfoById.set(tokenId, legacyGenesisInfo); +} +export const mockTokenInfoById = calculatedMockTokenInfoById; export const mockFinalizedSlpUtxos = [ { outpoint: { diff --git a/cashtab/src/chronik/fixtures/mocks.js b/cashtab/src/chronik/fixtures/mocks.js --- a/cashtab/src/chronik/fixtures/mocks.js +++ b/cashtab/src/chronik/fixtures/mocks.js @@ -10773,7 +10773,7 @@ parsedTxHistory: [], }, }; -export const txHistoryTokenInfoById = { +export const legacyTxHistoryTokenInfoById = { 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd': { tokenTicker: 'ST', tokenName: 'ST', @@ -11312,6 +11312,19 @@ 'cf601c56b58bc05a39a95374a4a865f0a8b56544ea937b30fb46315441717c50', }, }; +const calculatedTxHistoryTokenInfoById = new Map(); +const legacyTxHistoryTokenInfoByIdTokenIds = Object.keys( + legacyTxHistoryTokenInfoById, +); +for (const tokenId of legacyTxHistoryTokenInfoByIdTokenIds) { + const legacyGenesisInfo = JSON.parse( + JSON.stringify(legacyTxHistoryTokenInfoById[tokenId]), + ); + // Remove the tokenId key which we do not need stored at the value + delete legacyGenesisInfo.tokenId; + calculatedTxHistoryTokenInfoById.set(tokenId, legacyGenesisInfo); +} +export const txHistoryTokenInfoById = calculatedTxHistoryTokenInfoById; export const stakingRwd = { tx: { txid: 'c8b0783e36ab472f26108007ffa522ee82b79db3777c84b0448f5b9ef35be895', @@ -11620,8 +11633,6 @@ tokenDocumentHash: '', tokenDocumentUrl: 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', tokenName: 'Covid19 Lifetime Immunity', tokenTicker: 'NOCOVID', }, @@ -11727,8 +11738,6 @@ tokenDocumentHash: '', tokenDocumentUrl: 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', tokenName: 'Covid19 Lifetime Immunity', tokenTicker: 'NOCOVID', }, @@ -11818,8 +11827,6 @@ success: true, tokenDocumentHash: '', tokenDocumentUrl: 'https://cashtab.com/', - tokenId: - 'cf601c56b58bc05a39a95374a4a865f0a8b56544ea937b30fb46315441717c50', tokenName: 'UpdateTest', tokenTicker: 'UDT', }, @@ -11926,8 +11933,6 @@ success: true, tokenDocumentHash: '', tokenDocumentUrl: 'https://cashtabapp.com/', - tokenId: - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', tokenName: 'CashTabBits', tokenTicker: 'CTB', }, @@ -12630,8 +12635,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 0, - tokenId: - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875', success: true, }, airdropFlag: false, @@ -12735,8 +12738,6 @@ tokenDocumentHash: '85b591c15c9f49531e39fcfeb2a5a26b2bd0f7c018fb9cd71b5d92dfb732d5cc', decimals: 7, - tokenId: - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', success: true, }, airdropFlag: false, @@ -12856,8 +12857,6 @@ tokenDocumentUrl: 'https://cashtabapp.com/', tokenDocumentHash: '', decimals: 9, - tokenId: - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', success: true, }, airdropFlag: false, diff --git a/cashtab/src/chronik/index.js b/cashtab/src/chronik/index.js --- a/cashtab/src/chronik/index.js +++ b/cashtab/src/chronik/index.js @@ -6,6 +6,7 @@ import appConfig from 'config/app'; import { getStackArray } from 'ecash-script'; import cashaddr from 'ecashaddrjs'; +import defaultCashtabCache from 'config/cashtabCache'; export const getTxHistoryPage = async (chronik, hash160, page = 0) => { let txHistoryPage; @@ -238,7 +239,14 @@ return preliminaryTokensArray; }; -const returnGetTokenInfoChronikPromise = (chronik, tokenId) => { +/** + * Get and cache genesisInfo for a token + * @param {object} chronik chronik-client instance + * @param {string} tokenId tokenId you want genesisInfo for + * @param {Map} cachedTokens tokens currently in cashtab's token cache + * @returns + */ +const returnGetTokenInfoChronikPromise = (chronik, tokenId, cachedTokens) => { /* The chronik.tx(txid) API call returns extensive transaction information For the purposes of finalizing token information, we only need the token metadata @@ -250,12 +258,23 @@ will return an array with all required metadata */ return new Promise((resolve, reject) => { - chronik.tx(tokenId).then( + chronik.token(tokenId).then( result => { - const thisTokenInfo = result.slpTxData.genesisInfo; - thisTokenInfo.tokenId = tokenId; - // You only want the genesis info for tokenId - resolve(thisTokenInfo); + if ('slpTxData' in result) { + // NNG chronik + cachedTokens.set(tokenId, result.slpTxData.genesisInfo); + resolve(result.slpTxData.genesisInfo); + } + if ('genesisInfo' in result) { + // in-node chronik + cachedTokens.set(tokenId, result.genesisInfo); + resolve(result.genesisInfo); + } + reject( + new Error( + `Invalid token info format from chronik.token(${tokenId})`, + ), + ); }, err => { reject(err); @@ -264,9 +283,16 @@ }); }; +/** + * Add genesisInfo and calculate balance using now-known token decimals + * @param {array} preliminaryTokensArray array of token objects formatted to be read by Cashtab + * @param {Map} cachedTokens + * @returns {array} finalizedTokensArray, same as preliminaryTokensArray but updated for decimals for + * tokens where we did not yet have this info from cache or chronik + */ export const processPreliminaryTokensArray = ( preliminaryTokensArray, - tokenInfoByTokenId, + cachedTokens, ) => { /* Iterate over preliminaryTokensArray to @@ -282,7 +308,11 @@ const thisTokenId = thisToken.tokenId; // Because tokenInfoByTokenId is indexed by tokenId, it's easy to reference - const thisTokenInfo = tokenInfoByTokenId[thisTokenId]; + const thisTokenInfo = cachedTokens.get(thisTokenId); + + if (typeof thisTokenInfo === 'undefined') { + console.log(`tokenId`, thisTokenId); + } // The decimals are specifically needed to calculate the correct balance const thisTokenDecimals = thisTokenInfo.decimals; @@ -305,7 +335,7 @@ export const finalizeTokensArray = async ( chronik, preliminaryTokensArray, - cachedTokenInfoById = {}, + cachedTokens = defaultCashtabCache.tokens, ) => { // Iterate over preliminaryTokensArray to determine what tokens you need to make API calls for @@ -316,54 +346,32 @@ 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 (cachedTokens.has(thisTokenId)) { // If you already have this info in cache, do not create an API request for it continue; } const thisTokenInfoPromise = returnGetTokenInfoChronikPromise( chronik, thisTokenId, + cachedTokens, ); getTokenInfoPromises.push(thisTokenInfoPromise); } const newTokensToCache = getTokenInfoPromises.length > 0; - // Get all the token info you need - let tokenInfoArray = []; + // Fetch uncached token genesisInfo and add to cache try { - tokenInfoArray = await Promise.all(getTokenInfoPromises); + await Promise.all(getTokenInfoPromises); } catch (err) { console.log(`Error in Promise.all(getTokenInfoPromises)`, err); } - // Add the token info you received from those API calls to - // your token info cache object, cachedTokenInfoByTokenId - - const updatedTokenInfoById = cachedTokenInfoById; - for (let i = 0; i < tokenInfoArray.length; i += 1) { - /* tokenInfoArray is an array of objects that look like - { - "tokenTicker": "ST", - "tokenName": "ST", - "tokenDocumentUrl": "developer.bitcoin.com", - "tokenDocumentHash": "", - "decimals": 0, - "tokenId": "bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd" - } - */ - - const thisTokenInfo = tokenInfoArray[i]; - const thisTokenId = thisTokenInfo.tokenId; - // Add this entry to updatedTokenInfoById - updatedTokenInfoById[thisTokenId] = thisTokenInfo; - } - // Now use cachedTokenInfoByTokenId object to finalize token info // Split this out into a separate function so you can unit test const finalTokenArray = processPreliminaryTokensArray( preliminaryTokensArray, - updatedTokenInfoById, + cachedTokens, ); // Sort tokens alphabetically by ticker @@ -371,17 +379,23 @@ a.info.tokenTicker.localeCompare(b.info.tokenTicker), ); - return { tokens: finalTokenArray, updatedTokenInfoById, newTokensToCache }; + return { tokens: finalTokenArray, cachedTokens, newTokensToCache }; }; -export const finalizeSlpUtxos = (preliminarySlpUtxos, tokenInfoById) => { +/** + * Use now-known tokenDecimals to add decimal-adjusted tokenQty to token utxos + * @param {array} preliminarySlpUtxos slpUtxos without tokenQty calculated by tokenDecimals + * @param {Map} cachedTokens the tokens key of cashtabCache + * @returns + */ +export const finalizeSlpUtxos = (preliminarySlpUtxos, cachedTokens) => { // We need tokenQty in each slpUtxo to support transaction creation // Add this info here const finalizedSlpUtxos = []; for (let i = 0; i < preliminarySlpUtxos.length; i += 1) { const thisUtxo = preliminarySlpUtxos[i]; const thisTokenId = thisUtxo.slpMeta.tokenId; - const { decimals } = tokenInfoById[thisTokenId]; + const { decimals } = cachedTokens.get(thisTokenId); // Update balance according to decimals thisUtxo.tokenQty = new BN(thisUtxo.slpToken.amount) .shiftedBy(-1 * decimals) @@ -470,7 +484,7 @@ }); }; -export const parseChronikTx = (tx, wallet, tokenInfoById) => { +export const parseChronikTx = (tx, wallet, cachedTokens) => { const walletHash160s = getHashArrayFromWallet(wallet); const { inputs, outputs } = tx; // Assign defaults @@ -751,7 +765,7 @@ // Get token genesis info from cache let decimals = 0; try { - genesisInfo = tokenInfoById[tx.slpTxData.slpMeta.tokenId]; + genesisInfo = cachedTokens.get(tx.slpTxData.slpMeta.tokenId); if (typeof genesisInfo !== 'undefined') { genesisInfo.success = true; decimals = genesisInfo.decimals; @@ -805,7 +819,14 @@ }; }; -export const getTxHistoryChronik = async (chronik, wallet, tokenInfoById) => { +/** + * + * @param {*} chronik + * @param {*} wallet + * @param {*} cachedTokens + * @returns + */ +export const getTxHistoryChronik = async (chronik, wallet, cachedTokens) => { // Create array of promises to get chronik history for each address // Combine them all and sort by blockheight and firstSeen // Add all the info cashtab needs to make them useful @@ -847,12 +868,12 @@ // Parse txs const chronikTxHistory = []; - const uncachedTokenIds = []; + const uncachedTokenIds = new Set(); for (let i = 0; i < sortedTxHistoryArray.length; i += 1) { const sortedTx = sortedTxHistoryArray[i]; // Add token genesis info so parsing function can calculate amount by decimals - sortedTx.parsed = parseChronikTx(sortedTx, wallet, tokenInfoById); - // Check to see if this tx was a token tx with uncached tokenInfoById + sortedTx.parsed = parseChronikTx(sortedTx, wallet, cachedTokens); + // Check to see if this tx was from a token without genesisInfo in cachedTokens if ( sortedTx.parsed.isEtokenTx && sortedTx.parsed.genesisInfo && @@ -860,41 +881,27 @@ ) { // Only add if the token id is not already in uncachedTokenIds const uncachedTokenId = sortedTx.parsed.slpMeta.tokenId; - if (!uncachedTokenIds.includes(uncachedTokenId)) - uncachedTokenIds.push(uncachedTokenId); + uncachedTokenIds.add(uncachedTokenId); } chronikTxHistory.push(sortedTx); } - const txHistoryNewTokensToCache = uncachedTokenIds.length > 0; - - if (!txHistoryNewTokensToCache) { - // This will almost always be the case - // Edge case to find uncached token info in tx history that was not caught in processing utxos - // Requires performing transactions in one wallet, then loading the same wallet in another browser later - return { - parsedTxHistory: chronikTxHistory, - txHistoryUpdatedTokenInfoById: tokenInfoById, - txHistoryNewTokensToCache, - }; - } + const txHistoryNewTokensToCache = uncachedTokenIds.size > 0; // Iterate over uncachedTokenIds to get genesis info and add to cache const getTokenInfoPromises = []; - for (let i = 0; i < uncachedTokenIds.length; i += 1) { - const thisTokenId = uncachedTokenIds[i]; - + for (const uncachedTokenId of uncachedTokenIds) { const thisTokenInfoPromise = returnGetTokenInfoChronikPromise( chronik, - thisTokenId, + uncachedTokenId, + cachedTokens, ); getTokenInfoPromises.push(thisTokenInfoPromise); } // Get all the token info you need - let tokenInfoArray = []; try { - tokenInfoArray = await Promise.all(getTokenInfoPromises); + await Promise.all(getTokenInfoPromises); } catch (err) { console.log( `Error in Promise.all(getTokenInfoPromises) in getTxHistoryChronik`, @@ -902,31 +909,9 @@ ); } - // Add the token info you received from those API calls to - // your token info cache object, cachedTokenInfoByTokenId - - const txHistoryUpdatedTokenInfoById = tokenInfoById; - for (let i = 0; i < tokenInfoArray.length; i += 1) { - /* tokenInfoArray is an array of objects that look like - { - "tokenTicker": "ST", - "tokenName": "ST", - "tokenDocumentUrl": "developer.bitcoin.com", - "tokenDocumentHash": "", - "decimals": 0, - "tokenId": "bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd" - } - */ - - const thisTokenInfo = tokenInfoArray[i]; - const thisTokenId = thisTokenInfo.tokenId; - // Add this entry to updatedTokenInfoById - txHistoryUpdatedTokenInfoById[thisTokenId] = thisTokenInfo; - } - return { parsedTxHistory: chronikTxHistory, - txHistoryUpdatedTokenInfoById, + cachedTokens, txHistoryNewTokensToCache, }; }; diff --git a/cashtab/src/config/app.js b/cashtab/src/config/app.js --- a/cashtab/src/config/app.js +++ b/cashtab/src/config/app.js @@ -4,6 +4,7 @@ import mainLogo from 'assets/logo_primary.png'; import tokenLogo from 'assets/logo_secondary.png'; import { cashtabSettings } from 'config/cashtabSettings'; +import { defaultCashtabCache } from 'config/cashtabCache'; // App settings not adjustable by the user const appConfig = { @@ -25,7 +26,11 @@ notificationDurationLong: 5, localStorageMaxCharacters: 24, monitorExtension: false, - defaultCashtabState: { contactList: [], settings: cashtabSettings }, + defaultCashtabState: { + contactList: [], + settings: cashtabSettings, + cashtabCache: defaultCashtabCache, + }, }; export default appConfig; diff --git a/cashtab/src/config/cashtabCache.js b/cashtab/src/config/cashtabCache.js --- a/cashtab/src/config/cashtabCache.js +++ b/cashtab/src/config/cashtabCache.js @@ -4,7 +4,7 @@ // Default cashtab cache object used for validation and initialization of new wallets without a cache const defaultCashtabCache = { - tokenInfoById: {}, + tokens: new Map(), }; export default defaultCashtabCache; diff --git a/cashtab/src/helpers/__tests__/index.test.js b/cashtab/src/helpers/__tests__/index.test.js --- a/cashtab/src/helpers/__tests__/index.test.js +++ b/cashtab/src/helpers/__tests__/index.test.js @@ -1,7 +1,7 @@ // Copyright (c) 2023 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -import { isMobile } from 'helpers'; +import { isMobile, cashtabCacheToJSON, storedCashtabCacheToMap } from 'helpers'; import vectors from 'helpers/fixtures/vectors'; describe('Detect mobile or desktop devices', () => { @@ -14,3 +14,19 @@ }); }); }); + +describe('Converts cashtabCache to and from JSON for storage and in-app use', () => { + const { expectedReturns } = vectors.cashtabCacheToJSON; + + expectedReturns.forEach(expectedReturn => { + const { description, cashtabCache, cashtabCacheJson } = expectedReturn; + it(`cashtabCacheToJSON and storedCashtabCacheToMap: ${description}`, () => { + expect(cashtabCacheToJSON(cashtabCache)).toStrictEqual( + cashtabCacheJson, + ); + expect(storedCashtabCacheToMap(cashtabCacheJson)).toStrictEqual( + cashtabCache, + ); + }); + }); +}); diff --git a/cashtab/src/helpers/fixtures/mocks.js b/cashtab/src/helpers/fixtures/mocks.js new file mode 100644 --- /dev/null +++ b/cashtab/src/helpers/fixtures/mocks.js @@ -0,0 +1,25 @@ +const mockTokenCache = new Map(); + +mockTokenCache.set( + '3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', + { + tokenTicker: 'BEAR', + tokenName: 'BearNip', + url: 'https://cashtab.com/', + decimals: 0, + hash: '', + }, +); + +mockTokenCache.set( + 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', + { + tokenTicker: 'CTD', + tokenName: 'Cashtab Dark', + url: 'https://cashtab.com/', + decimals: 0, + hash: '', + }, +); + +export const mockCashtabCache = { tokens: mockTokenCache }; diff --git a/cashtab/src/helpers/fixtures/vectors.js b/cashtab/src/helpers/fixtures/vectors.js --- a/cashtab/src/helpers/fixtures/vectors.js +++ b/cashtab/src/helpers/fixtures/vectors.js @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +import { mockCashtabCache } from 'helpers/fixtures/mocks'; // Test vectors for helper functions export default { @@ -31,4 +32,43 @@ }, ], }, + cashtabCacheToJSON: { + expectedReturns: [ + { + description: + 'Converts cashtabCache with populated token cache to JSON for storage', + cashtabCache: mockCashtabCache, + cashtabCacheJson: { + tokens: [ + [ + '3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', + { + decimals: 0, + hash: '', + tokenName: 'BearNip', + tokenTicker: 'BEAR', + url: 'https://cashtab.com/', + }, + ], + [ + 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', + { + decimals: 0, + hash: '', + tokenName: 'Cashtab Dark', + tokenTicker: 'CTD', + url: 'https://cashtab.com/', + }, + ], + ], + }, + }, + { + description: + 'Converts cashtabCache with empty token cache to JSON for storage', + cashtabCache: { tokens: new Map() }, + cashtabCacheJson: { tokens: [] }, + }, + ], + }, }; diff --git a/cashtab/src/helpers/index.js b/cashtab/src/helpers/index.js --- a/cashtab/src/helpers/index.js +++ b/cashtab/src/helpers/index.js @@ -10,3 +10,28 @@ navigator.userAgentData.mobile === true ); }; + +/** + * Convert cashtabCache to a JSON for storage + * @param {object} cashtabCache {tokens: <Map of genesis info by tokenId>} + * @returns {JSON} + */ +export const cashtabCacheToJSON = cashtabCache => { + return { + ...cashtabCache, + tokens: Array.from(cashtabCache.tokens.entries()), + }; +}; + +/** + * Convert stored cashtabCache from JSON to more useful data types + * For now, this means converting the one key 'tokens' from a keyvalue array to a Map + * @param {JSON} storedCashtabCache + * @returns {Map} + */ +export const storedCashtabCacheToMap = storedCashtabCache => { + return { + ...storedCashtabCache, + tokens: new Map(storedCashtabCache.tokens), + }; +}; diff --git a/cashtab/src/hooks/__tests__/useWalletStorage.test.js b/cashtab/src/hooks/__tests__/useWalletStorage.test.js --- a/cashtab/src/hooks/__tests__/useWalletStorage.test.js +++ b/cashtab/src/hooks/__tests__/useWalletStorage.test.js @@ -15,6 +15,7 @@ clearLocalForage, initializeCashtabStateForTests, } from 'components/fixtures/helpers'; +import { cashtabCacheToJSON, storedCashtabCacheToMap } from 'helpers'; const TRIGGER_UTXO_REFRESH_INTERVAL_MS = 50; @@ -172,4 +173,42 @@ expect(result.current.fiatPrice).toBe(xecPriceGbp); }); }); + it('localforage can set and get a map of tokeninfo by tokenId', async () => { + const mockTokenCache = new Map(); + + mockTokenCache.set( + '3fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d109', + { + tokenTicker: 'BEAR', + tokenName: 'BearNip', + url: 'https://cashtab.com/', + decimals: 0, + hash: '', + }, + ); + + mockTokenCache.set( + 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', + { + tokenTicker: 'CTD', + tokenName: 'Cashtab Dark', + url: 'https://cashtab.com/', + decimals: 0, + hash: '', + }, + ); + + const mockCashtabCache = { tokens: mockTokenCache }; + + await localforage.setItem( + 'testCache', + cashtabCacheToJSON(mockCashtabCache), + ); + + const revivedCashtabCache = storedCashtabCacheToMap( + await localforage.getItem('testCache'), + ); + + expect(mockCashtabCache).toStrictEqual(revivedCashtabCache); + }); }); diff --git a/cashtab/src/hooks/useWallet.js b/cashtab/src/hooks/useWallet.js --- a/cashtab/src/hooks/useWallet.js +++ b/cashtab/src/hooks/useWallet.js @@ -14,7 +14,6 @@ isValidCashtabCache, isValidContactList, migrateLegacyCashtabSettings, - parseInvalidCashtabCacheForMigration, } from 'validation'; import localforage from 'localforage'; import { @@ -25,6 +24,7 @@ finalizeSlpUtxos, getTxHistoryChronik, parseChronikTx, + returnGetTokenInfoChronikPromise, } from 'chronik'; import { queryAliasServer } from 'utils/aliasUtils'; import cashaddr from 'ecashaddrjs'; @@ -41,6 +41,7 @@ } from 'components/Common/CustomIcons'; import { supportedFiatCurrencies } from 'config/cashtabSettings'; import { notification } from 'antd'; +import { cashtabCacheToJSON, storedCashtabCacheToMap } from 'helpers'; // Cashtab is always running the `update` function at an interval // When the websocket detects an incoming tx (or when the wallet is first loaded) // Set this interval to near-instant (50ms) @@ -57,7 +58,6 @@ ); const [wallet, setWallet] = useState(false); const [chronikWebsocket, setChronikWebsocket] = useState(null); - const [cashtabCache, setCashtabCache] = useState(defaultCashtabCache); const [fiatPrice, setFiatPrice] = useState(null); const [apiError, setApiError] = useState(false); const [checkFiatInterval, setCheckFiatInterval] = useState(null); @@ -139,51 +139,29 @@ const preliminaryTokensArray = getPreliminaryTokensArray(preliminarySlpUtxos); - const { tokens, updatedTokenInfoById, newTokensToCache } = - await finalizeTokensArray( - chronik, - preliminaryTokensArray, - cashtabCache.tokenInfoById, - ); - - // If you have more token info now, write this to local storage - if (newTokensToCache) { - writeTokenInfoByIdToCache(updatedTokenInfoById); - // Update the tokenInfoById key in cashtabCache - setCashtabCache({ - ...cashtabCache, - tokenInfoById: updatedTokenInfoById, - }); - } + const { tokens, newTokensToCache } = await finalizeTokensArray( + chronik, + preliminaryTokensArray, + cashtabState.cashtabCache.tokens, + ); const slpUtxos = finalizeSlpUtxos( preliminarySlpUtxos, - updatedTokenInfoById, + cachedTokens, ); - const { - parsedTxHistory, - txHistoryUpdatedTokenInfoById, - txHistoryNewTokensToCache, - } = await getTxHistoryChronik( - chronik, - wallet, - updatedTokenInfoById, - ); - if (txHistoryNewTokensToCache) { - console.log( - `Uncached token info found in tx history, adding to cache`, - ); - writeTokenInfoByIdToCache(txHistoryUpdatedTokenInfoById); - // Update the tokenInfoById key in cashtabCache - setCashtabCache({ - ...cashtabCache, - tokenInfoById: txHistoryUpdatedTokenInfoById, + const { parsedTxHistory, cachedTokens, txHistoryNewTokensToCache } = + await getTxHistoryChronik(chronik, wallet, cachedTokens); + + // If you have updated cachedTokens from finalizeTokensArray or getTxHistoryChronik + // Update in state and localforage + if (newTokensToCache || txHistoryNewTokensToCache) { + updateCashtabState('cashtabCache', { + ...cashtabState.cashtabCache, + tokens: cachedTokens, }); } - // If you were missing any token info for tokens in this tx history, get it - const newState = { balances: getWalletBalanceFromUtxos(nonSlpUtxos), slpUtxos, @@ -241,9 +219,18 @@ // We lock the UI by setting loading to true while we set items in localforage // This is to prevent rapid user action from corrupting the db setLoading(true); + // Update the changed key in state setCashtabState({ ...cashtabState, [`${key}`]: value }); + // Update the changed key in localforage + + // Handle any items that must be converted to JSON before storage + // For now, this is just cashtabCache + if (key === 'cashtabCache') { + value = cashtabCacheToJSON(value); + } + try { await localforage.setItem(key, value); } catch (err) { @@ -299,6 +286,28 @@ // Set cashtabState settings to valid localforage or migrated settings cashtabState.settings = settings; } + + // cashtabCache + let cashtabCache = await localforage.getItem('cashtabCache'); + + if (cashtabCache !== null) { + // If we find cashtabCache in localforage + + // cashtabCache must be converted from JSON as it stores a Map + cashtabCache = storedCashtabCacheToMap(cashtabCache); + + if (!isValidCashtabCache(cashtabCache)) { + // If a cashtabCache object is present but invalid, nuke it and start again + // Existing bugs in legacy cashtabCache storage + cashtabCache = defaultCashtabCache; + // Update localforage on app load only if existing values are in an obsolete format + updateCashtabState('cashtabCache', cashtabCache); + } + + // Set cashtabState cashtabCache to valid localforage or migrated settings + cashtabState.cashtabCache = cashtabCache; + } + setCashtabState(cashtabState); }; @@ -398,18 +407,6 @@ return wallet; }; - const writeTokenInfoByIdToCache = async tokenInfoById => { - console.log(`writeTokenInfoByIdToCache`); - const cashtabCache = defaultCashtabCache; - cashtabCache.tokenInfoById = tokenInfoById; - try { - await localforage.setItem('cashtabCache', cashtabCache); - console.log(`cashtabCache successfully updated`); - } catch (err) { - console.log(`Error in writeCashtabCache()`, err); - } - }; - const writeWalletState = async (wallet, newState) => { // Add new state as an object on the active wallet wallet.state = newState; @@ -902,22 +899,11 @@ ); } - // Get tokenInfoById from cashtabCache to parse this tx - let tokenInfoById = {}; - try { - tokenInfoById = cashtabCache.tokenInfoById; - } catch (err) { - console.log( - `Error getting tokenInfoById from cache on incoming tx`, - err, - ); - } - // parse tx for notification const parsedChronikTx = parseChronikTx( incomingTxDetails, wallet, - tokenInfoById, + cashtabState.cashtabCache.tokens, ); /* If this is an incoming eToken tx and parseChronikTx was not able to get genesis info from cache, then get genesis info from API and add to cache */ @@ -935,27 +921,25 @@ } else { // Get genesis info from API and add to cache try { - // Get the tokenID + // Get the genesis info and add it to cache const incomingTokenId = parsedChronikTx.slpMeta.tokenId; - // chronik call to genesis tx to get this info - const tokenGenesisInfo = await chronik.tx( - incomingTokenId, - ); - const { genesisInfo } = tokenGenesisInfo.slpTxData; - // Add this to cashtabCache - let tokenInfoByIdUpdatedForThisToken = tokenInfoById; - tokenInfoByIdUpdatedForThisToken[incomingTokenId] = - genesisInfo; - writeTokenInfoByIdToCache( - tokenInfoByIdUpdatedForThisToken, + const genesisInfoArr = await Promise.all( + returnGetTokenInfoChronikPromise( + chronik, + incomingTokenId, + cashtabState.cashtabCache.tokens, + ), ); - // Update the tokenInfoById key in cashtabCache - setCashtabCache({ - ...cashtabCache, - tokenInfoById: tokenInfoByIdUpdatedForThisToken, + + // Update in state and localforage + await updateCashtabState('cashtabCache', { + ...cashtabState.cashtabCache, + tokens: cashtabState.cashtabCache.tokens, }); + const genesisInfo = genesisInfoArr[0]; + // Calculate eToken amount with decimals eTokenAmountReceived = new BN( parsedChronikTx.etokenAmount, @@ -1125,36 +1109,6 @@ return setChronikWebsocket(ws); }; - const loadCashtabCache = async () => { - // get cache object from localforage - let localCashtabCache; - try { - localCashtabCache = await localforage.getItem('cashtabCache'); - // If there is no keyvalue pair in localforage with key 'cashtabCache' - if (localCashtabCache === null) { - // Use the default - localforage.setItem('cashtabCache', defaultCashtabCache); - setCashtabCache(defaultCashtabCache); - return defaultCashtabCache; - } - } catch (err) { - console.log(`Error getting cashtabCache`, err); - setCashtabCache(defaultCashtabCache); - return defaultCashtabCache; - } - // If you found an object in localforage at the cashtabCache key, make sure it's valid - if (isValidCashtabCache(localCashtabCache)) { - setCashtabCache(localCashtabCache); - return localCashtabCache; - } - // if not valid, parse the cache object, finds what param is missing, and sticks it in - const migratedCashtabCache = - parseInvalidCashtabCacheForMigration(localCashtabCache); - localforage.setItem('cashtabCache', migratedCashtabCache); - setCashtabCache(migratedCashtabCache); - return defaultCashtabCache; - }; - // With different currency selections possible, need unique intervals for price checks // Must be able to end them and set new ones with new currencies const initializeFiatPriceApi = async selectedFiatCurrency => { @@ -1396,7 +1350,6 @@ const cashtabBootup = async () => { setWallet(await getWallet()); await loadCashtabState(); - await loadCashtabCache(); }; useEffect(() => { @@ -1463,7 +1416,6 @@ fiatPrice, loading, apiError, - cashtabCache, refreshAliases, aliases, setAliases, diff --git a/cashtab/src/validation/__tests__/index.test.js b/cashtab/src/validation/__tests__/index.test.js --- a/cashtab/src/validation/__tests__/index.test.js +++ b/cashtab/src/validation/__tests__/index.test.js @@ -16,7 +16,6 @@ isValidAirdropExclusionArray, isValidContactList, migrateLegacyCashtabSettings, - parseInvalidCashtabCacheForMigration, isValidCashtabCache, validateMnemonic, meetsAliasSpec, @@ -36,15 +35,9 @@ invalidXecAirdropListMultipleValidValues, validXecAirdropExclusionList, invalidXecAirdropExclusionList, - validCashtabCache, - cashtabCacheWithOneBadTokenId, - cashtabCacheWithDecimalNotNumber, - cashtabCacheWithTokenNameNotString, - cashtabCacheWithMissingTokenName, } from 'validation/fixtures/mocks'; import vectors from 'validation/fixtures/vectors'; import { when } from 'jest-when'; -import defaultCashtabCache from 'config/cashtabCache'; import appConfig from 'config/app'; import aliasSettings from 'config/alias'; import { toXec } from 'wallet'; @@ -340,30 +333,6 @@ it(`Rejects a domain input as numbers ${appConfig.tokenTicker} token document URL`, () => { expect(isValidTokenDocumentUrl(12345)).toBe(false); }); - it(`Recognizes the default cashtabCache object as valid`, () => { - expect(isValidCashtabCache(defaultCashtabCache)).toBe(true); - }); - it(`Recognizes a valid cashtabCache object`, () => { - expect(isValidCashtabCache(validCashtabCache)).toBe(true); - }); - it(`Rejects a cashtabCache object if one token id is invalid`, () => { - expect(isValidCashtabCache(cashtabCacheWithOneBadTokenId)).toBe(false); - }); - it(`Rejects a cashtabCache object if decimals is not a number`, () => { - expect(isValidCashtabCache(cashtabCacheWithDecimalNotNumber)).toBe( - false, - ); - }); - it(`Rejects a cashtabCache object if tokenName is not a string`, () => { - expect(isValidCashtabCache(cashtabCacheWithTokenNameNotString)).toBe( - false, - ); - }); - it(`Rejects a cashtabCache object if tokenName is missing`, () => { - expect(isValidCashtabCache(cashtabCacheWithMissingTokenName)).toBe( - false, - ); - }); it(`Recognizes a valid cashtab settings object`, () => { expect( isValidCashtabSettings({ @@ -603,62 +572,6 @@ it(`isValidAirdropExclusionArray rejects a null airdrop exclusion list`, () => { expect(isValidAirdropExclusionArray(null)).toBe(false); }); - it('parseInvalidCashtabCacheForMigration updates an invalid cashtabCache object and keeps existing valid cache params intact', () => - expect( - parseInvalidCashtabCacheForMigration({ - tokenInfoById: { - '1c6c9c64d70b285befe733f175d0f384538576876bd280b10587df81279d3f5e': - { - decimals: 2, - tokenDocumentHash: '', - tokenDocumentUrl: 'https://cashtab.com/', - tokenId: - '1c6c9c64d70b285befe733f175d0f384538576876bd280b10587df81279d3f5e', - tokenName: 'test', - tokenTicker: 'TEST', - }, - 'fb4233e8a568993976ed38a81c2671587c5ad09552dedefa78760deed6ff87aa': - { - decimals: 2, - tokenDocumentHash: '', - tokenDocumentUrl: 'https://cashtab.com/', - tokenId: - 'fb4233e8a568993976ed38a81c2671587c5ad09552dedefa78760deed6ff87aa', - tokenName: 'test2', - tokenTicker: 'TEST2', - }, - }, - }), - ).toStrictEqual({ - tokenInfoById: { - '1c6c9c64d70b285befe733f175d0f384538576876bd280b10587df81279d3f5e': - { - decimals: 2, - tokenDocumentHash: '', - tokenDocumentUrl: 'https://cashtab.com/', - tokenId: - '1c6c9c64d70b285befe733f175d0f384538576876bd280b10587df81279d3f5e', - tokenName: 'test', - tokenTicker: 'TEST', - }, - 'fb4233e8a568993976ed38a81c2671587c5ad09552dedefa78760deed6ff87aa': - { - decimals: 2, - tokenDocumentHash: '', - tokenDocumentUrl: 'https://cashtab.com/', - tokenId: - 'fb4233e8a568993976ed38a81c2671587c5ad09552dedefa78760deed6ff87aa', - tokenName: 'test2', - tokenTicker: 'TEST2', - }, - }, - })); - - it('parseInvalidCashtabCacheForMigration sets cashtabCache object with no exsting valid cache to default values', () => - expect(parseInvalidCashtabCacheForMigration({})).toStrictEqual({ - tokenInfoById: {}, - })); - it(`accepts a valid wallet name`, () => { expect(isValidNewWalletNameLength('Apollo')).toBe(true); }); @@ -936,3 +849,13 @@ }); }); }); + +describe('Determines if cashtabCache is valid or invalid', () => { + const { expectedReturns } = vectors.isValidCashtabCache; + expectedReturns.forEach(expectedReturn => { + const { description, cashtabCache, isValid } = expectedReturn; + it(`isValidCashtabCache: ${description}`, () => { + expect(isValidCashtabCache(cashtabCache)).toBe(isValid); + }); + }); +}); diff --git a/cashtab/src/validation/fixtures/mocks.js b/cashtab/src/validation/fixtures/mocks.js --- a/cashtab/src/validation/fixtures/mocks.js +++ b/cashtab/src/validation/fixtures/mocks.js @@ -39,857 +39,3 @@ 'ecash:qqlqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqyz0v403dj,' + 'ecash:qz2taa43tljkvnvkeqv9pyx337hmg0zclqfqjrqst4,' + 'ecash:qp0hlj26nwjpk9c3f0umjz7qmwpzfh0fhckq4zj9s6'; - -export const validCashtabCache = { - tokenInfoById: { - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd': { - tokenTicker: 'ST', - tokenName: 'ST', - tokenDocumentUrl: 'developer.bitcoin.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd', - }, - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1': { - tokenTicker: 'CTP', - tokenName: 'Cash Tab Points', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1', - }, - '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901': { - tokenTicker: '🍔', - tokenName: 'Burger', - tokenDocumentUrl: - 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', - }, - 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d': { - tokenTicker: 'TAP', - tokenName: 'Thoughts and Prayers', - tokenDocumentUrl: '', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', - }, - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e': { - tokenTicker: 'TBC', - tokenName: 'tabcash', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', - }, - 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb': { - tokenTicker: 'NAKAMOTO', - tokenName: 'NAKAMOTO', - tokenDocumentUrl: '', - tokenDocumentHash: '', - decimals: 8, - tokenId: - 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', - }, - '22f4ba40312ea3e90e1bfa88d2aa694c271d2e07361907b6eb5568873ffa62bf': { - tokenTicker: 'CLA', - tokenName: 'Cashtab Local Alpha', - tokenDocumentUrl: 'boomertakes.com', - tokenDocumentHash: '', - decimals: 5, - tokenId: - '22f4ba40312ea3e90e1bfa88d2aa694c271d2e07361907b6eb5568873ffa62bf', - }, - 'aa7202397a06097e8ff36855aa72c0ee032659747e5bd7cbcd3099fc3a62b6b6': { - tokenTicker: 'CTL', - tokenName: 'Cashtab Token Launch Launch Token', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'aa7202397a06097e8ff36855aa72c0ee032659747e5bd7cbcd3099fc3a62b6b6', - }, - 'da9460ce4b1c92b4f6ef4e4a6bc2d05539f49d02b17681389d9ce22b8dca50f0': { - tokenTicker: 'SA', - tokenName: 'Spinner Alpha', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'da9460ce4b1c92b4f6ef4e4a6bc2d05539f49d02b17681389d9ce22b8dca50f0', - }, - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875': { - tokenTicker: 'LVV', - tokenName: 'Lambda Variant Variants', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875', - }, - '16b12bbacdbb8c8a799adbfd782bfff9843c1f9b0be148eaae02a1a7f74f95c4': { - tokenTicker: 'CGEN', - tokenName: 'Cashtab Genesis', - tokenDocumentUrl: 'https://boomertakes.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - '16b12bbacdbb8c8a799adbfd782bfff9843c1f9b0be148eaae02a1a7f74f95c4', - }, - 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba': { - tokenTicker: 'TBS', - tokenName: 'TestBits', - tokenDocumentUrl: 'https://thecryptoguy.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba', - }, - '9e9738e9ac3ff202736bf7775f875ebae6f812650df577a947c20c52475e43da': { - tokenTicker: 'CUTT', - tokenName: 'Cashtab Unit Test Token', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 2, - tokenId: - '9e9738e9ac3ff202736bf7775f875ebae6f812650df577a947c20c52475e43da', - }, - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a': { - tokenTicker: 'POW', - tokenName: 'ProofofWriting.com Token', - tokenDocumentUrl: 'https://www.proofofwriting.com/26', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a', - }, - '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1': { - tokenTicker: 'HONK', - tokenName: 'HONK HONK', - tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', - }, - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48': { - tokenTicker: 'DVV', - tokenName: 'Delta Variant Variants', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48', - }, - '3515f4a9851ad44124e0ddf6149344deb27a97720fc7e5254a9d2c86da7415a9': { - tokenTicker: '001', - tokenName: '01', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '3515f4a9851ad44124e0ddf6149344deb27a97720fc7e5254a9d2c86da7415a9', - }, - '6fb6122742cac8fd1df2d68997fdfa4c077bc22d9ef4a336bfb63d24225f9060': { - tokenTicker: '002', - tokenName: '2', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '6fb6122742cac8fd1df2d68997fdfa4c077bc22d9ef4a336bfb63d24225f9060', - }, - '2936188a41f22a3e0a47d13296147fb3f9ddd2f939fe6382904d21a610e8e49c': { - tokenTicker: '002', - tokenName: '2', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '2936188a41f22a3e0a47d13296147fb3f9ddd2f939fe6382904d21a610e8e49c', - }, - 'e859eeb52e7afca6217fb36784b3b6d3c7386a52f391dd0d00f2ec03a5e8e77b': { - tokenTicker: 'test', - tokenName: 'test', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 1, - tokenId: - 'e859eeb52e7afca6217fb36784b3b6d3c7386a52f391dd0d00f2ec03a5e8e77b', - }, - 'bdb3b4215ca0622e0c4c07655522c376eaa891838a82f0217fa453bb0595a37c': { - tokenTicker: 'Service', - tokenName: 'Evc token', - tokenDocumentUrl: 'https://cashtab.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'bdb3b4215ca0622e0c4c07655522c376eaa891838a82f0217fa453bb0595a37c', - }, - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d': { - tokenTicker: 'WDT', - tokenName: - 'Test Token With Exceptionally Long Name For CSS And Style Revisions', - tokenDocumentUrl: - 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', - tokenDocumentHash: - '85b591c15c9f49531e39fcfeb2a5a26b2bd0f7c018fb9cd71b5d92dfb732d5cc', - decimals: 7, - tokenId: - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', - }, - '7bbf452698a24b138b0357f689587fc6ea58410c34503b1179b91e40e10bba8b': { - tokenTicker: 'COVID', - tokenName: 'COVID-19', - tokenDocumentUrl: 'https://en.wikipedia.org/wiki/COVID-19', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '7bbf452698a24b138b0357f689587fc6ea58410c34503b1179b91e40e10bba8b', - }, - '6376cae692cf0302ecdd63234c14cbb2b21cec75ab538335f90254cfb3ed44cc': { - tokenTicker: 'CLT', - tokenName: 'Cashtab Local Tests', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '6376cae692cf0302ecdd63234c14cbb2b21cec75ab538335f90254cfb3ed44cc', - }, - '666c4318d1f7fef5f2c698262492c519018d4e9130f95d05f6be9f0fb7149e96': { - tokenTicker: 'CPG', - tokenName: 'Cashtab Prod Gamma', - tokenDocumentUrl: 'thecryptoguy.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '666c4318d1f7fef5f2c698262492c519018d4e9130f95d05f6be9f0fb7149e96', - }, - '157e0cdef5d5c51bdea00eac9ab821d809bb9d03cf98da85833614bedb129be6': { - tokenTicker: 'CLNSP', - tokenName: 'ComponentLongNameSpeedLoad', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '157e0cdef5d5c51bdea00eac9ab821d809bb9d03cf98da85833614bedb129be6', - }, - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55': { - tokenTicker: 'CTB', - tokenName: 'CashTabBits', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', - }, - 'ccf5fe5a387559c8ab9efdeb0c0ef1b444e677298cfddf07671245ce3cb3c79f': { - tokenTicker: 'XGB', - tokenName: 'Garmonbozia', - tokenDocumentUrl: 'https://twinpeaks.fandom.com/wiki/Garmonbozia', - tokenDocumentHash: '', - decimals: 8, - tokenId: - 'ccf5fe5a387559c8ab9efdeb0c0ef1b444e677298cfddf07671245ce3cb3c79f', - }, - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3': { - tokenTicker: 'NOCOVID', - tokenName: 'Covid19 Lifetime Immunity', - tokenDocumentUrl: - 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', - }, - 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc': { - tokenTicker: 'CTD', - tokenName: 'Cashtab Dark', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', - }, - '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a': { - tokenTicker: 'XBIT', - tokenName: 'eBits', - tokenDocumentUrl: 'https://boomertakes.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', - }, - '3de671a7107d3803d78f7f4a4e5c794d0903a8d28d16076445c084943c1e2db8': { - tokenTicker: 'CLB', - tokenName: 'Cashtab Local Beta', - tokenDocumentUrl: 'boomertakes.com', - tokenDocumentHash: '', - decimals: 2, - tokenId: - '3de671a7107d3803d78f7f4a4e5c794d0903a8d28d16076445c084943c1e2db8', - }, - '44929ff3b1fc634f982fede112cf12b21199a2ebbcf718412a38de9177d77168': { - tokenTicker: 'coin', - tokenName: 'johncoin', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '44929ff3b1fc634f982fede112cf12b21199a2ebbcf718412a38de9177d77168', - }, - '639a8dba34788ff3ebd3977d4ac045825394285ee648bb1d159e1c12b787ff25': { - tokenTicker: 'CFL', - tokenName: 'Cashtab Facelift', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - '639a8dba34788ff3ebd3977d4ac045825394285ee648bb1d159e1c12b787ff25', - }, - 'd376ebcd518067c8e10c0505865cf7336160b47807e6f1a95739ba90ae838840': { - tokenTicker: 'CFL', - tokenName: 'Cashtab Facelift', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'd376ebcd518067c8e10c0505865cf7336160b47807e6f1a95739ba90ae838840', - }, - 'b40d1f6acdb6ee68d7eca0167fe2753c076bc309b2e3b1af8bff70ca34b945b0': { - tokenTicker: 'KAT', - tokenName: 'KA_Test', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'b40d1f6acdb6ee68d7eca0167fe2753c076bc309b2e3b1af8bff70ca34b945b0', - }, - 'b39fdb53e21d67fa5fd3a11122f1452f15884047f2b80e8efe633c3b520b7a39': { - tokenTicker: 'SCΩΩG', - tokenName: 'Scoogi Omega', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'b39fdb53e21d67fa5fd3a11122f1452f15884047f2b80e8efe633c3b520b7a39', - }, - '3adbf501e21c711d20118e003711168eb39f560c01f4c6d6736fa3f3fceaa577': { - tokenTicker: 'OMI', - tokenName: 'Omicron', - tokenDocumentUrl: 'cdc.gov', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '3adbf501e21c711d20118e003711168eb39f560c01f4c6d6736fa3f3fceaa577', - }, - '0916e71779c9de7ee125741d3f5ab01f556356dbc86fd327a24f1e9e22ebc917': { - tokenTicker: 'CTL2', - tokenName: 'Cashtab Token Launch Launch Token v2', - tokenDocumentUrl: 'thecryptoguy.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '0916e71779c9de7ee125741d3f5ab01f556356dbc86fd327a24f1e9e22ebc917', - }, - '6e24e89b6d5284138c69777527760500b99614631bca7f2a5c38f4648dae9524': { - tokenTicker: 'CBB', - tokenName: 'Cashtab Beta Bits', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '6e24e89b6d5284138c69777527760500b99614631bca7f2a5c38f4648dae9524', - }, - '8ead21ce4b3b9e7b57607b97b65b5013496dc6e3dfdea162c08ce7265a66ebc8': { - tokenTicker: 'IFP', - tokenName: 'Infrastructure Funding Proposal Token', - tokenDocumentUrl: 'ifp.cash', - tokenDocumentHash: - 'b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553', - decimals: 8, - tokenId: - '8ead21ce4b3b9e7b57607b97b65b5013496dc6e3dfdea162c08ce7265a66ebc8', - }, - 'e4e1a2fb071fa71ca727e08ed1d8ea52a9531c79d1e5f1ebf483c66b71a8621c': { - tokenTicker: 'CPA', - tokenName: 'Cashtab Prod Alpha', - tokenDocumentUrl: 'thecryptoguy.com', - tokenDocumentHash: '', - decimals: 8, - tokenId: - 'e4e1a2fb071fa71ca727e08ed1d8ea52a9531c79d1e5f1ebf483c66b71a8621c', - }, - '45f0ff5cae7e89da6b96c26c8c48a959214c5f0e983e78d0925f8956ca8848c6': { - tokenTicker: 'CMA', - tokenName: 'CashtabMintAlpha', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 5, - tokenId: - '45f0ff5cae7e89da6b96c26c8c48a959214c5f0e983e78d0925f8956ca8848c6', - }, - '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6': { - tokenTicker: 'CTLv3', - tokenName: 'Cashtab Token Launch Launch Token v3', - tokenDocumentUrl: 'coinex.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6', - }, - }, -}; -export const cashtabCacheWithOneBadTokenId = { - tokenInfoById: { - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd': { - tokenTicker: 'ST', - tokenName: 'ST', - tokenDocumentUrl: 'developer.bitcoin.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd', - }, - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1': { - tokenTicker: 'CTP', - tokenName: 'Cash Tab Points', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1', - }, - '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901': { - tokenTicker: '🍔', - tokenName: 'Burger', - tokenDocumentUrl: - 'https://c4.wallpaperflare.com/wallpaper/58/564/863/giant-hamburger-wallpaper-preview.jpg', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '1f6a65e7a4bde92c0a012de2bcf4007034504a765377cdf08a3ee01d1eaa6901', - }, - 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d': { - tokenTicker: 'TAP', - tokenName: 'Thoughts and Prayers', - tokenDocumentUrl: '', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'dd84ca78db4d617221b58eabc6667af8fe2f7eadbfcc213d35be9f1b419beb8d', - }, - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e': { - tokenTicker: 'TBC', - tokenName: 'tabcash', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', - }, - 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb': { - tokenTicker: 'NAKAMOTO', - tokenName: 'NAKAMOTO', - tokenDocumentUrl: '', - tokenDocumentHash: '', - decimals: 8, - tokenId: - 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb', - }, - '22f4ba40312ea3e90e1bfa88d2aa694c271d2e07361907b6eb5568873ffa62bf': { - tokenTicker: 'CLA', - tokenName: 'Cashtab Local Alpha', - tokenDocumentUrl: 'boomertakes.com', - tokenDocumentHash: '', - decimals: 5, - tokenId: - '22f4ba40312ea3e90e1bfa88d2aa694c271d2e07361907b6eb5568873ffa62bf', - }, - 'aa7202397a06097e8ff36855aa72c0ee032659747e5bd7cbcd3099fc3a62b6b6': { - tokenTicker: 'CTL', - tokenName: 'Cashtab Token Launch Launch Token', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'aa7202397a06097e8ff36855aa72c0ee032659747e5bd7cbcd3099fc3a62b6b6', - }, - 'da9460ce4b1c92b4f6ef4e4a6bc2d05539f49d02b17681389d9ce22b8dca50f0': { - tokenTicker: 'SA', - tokenName: 'Spinner Alpha', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'da9460ce4b1c92b4f6ef4e4a6bc2d05539f49d02b17681389d9ce22b8dca50f0', - }, - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875': { - tokenTicker: 'LVV', - tokenName: 'Lambda Variant Variants', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '4db25a4b2f0b57415ce25fab6d9cb3ac2bbb444ff493dc16d0615a11ad06c875', - }, - '16b12bbacdbb8c8a799adbfd782bfff9843c1f9b0be148eaae02a1a7f74f95c4': { - tokenTicker: 'CGEN', - tokenName: 'Cashtab Genesis', - tokenDocumentUrl: 'https://boomertakes.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - '16b12bbacdbb8c8a799adbfd782bfff9843c1f9b0be148eaae02a1a7f74f95c4', - }, - 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba': { - tokenTicker: 'TBS', - tokenName: 'TestBits', - tokenDocumentUrl: 'https://thecryptoguy.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - 'bd1acc4c986de57af8d6d2a64aecad8c30ee80f37ae9d066d758923732ddc9ba', - }, - '9e9738e9ac3ff202736bf7775f875ebae6f812650df577a947c20c52475e43da': { - tokenTicker: 'CUTT', - tokenName: 'Cashtab Unit Test Token', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 2, - tokenId: - '9e9738e9ac3ff202736bf7775f875ebae6f812650df577a947c20c52475e43da', - }, - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a': { - tokenTicker: 'POW', - tokenName: 'ProofofWriting.com Token', - tokenDocumentUrl: 'https://www.proofofwriting.com/26', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'f36e1b3d9a2aaf74f132fef3834e9743b945a667a4204e761b85f2e7b65fd41a', - }, - '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1': { - tokenTicker: 'HONK', - tokenName: 'HONK HONK', - tokenDocumentUrl: 'THE REAL HONK SLP TOKEN', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '7f8889682d57369ed0e32336f8b7e0ffec625a35cca183f4e81fde4e71a538a1', - }, - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48': { - tokenTicker: 'DVV', - tokenName: 'Delta Variant Variants', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48', - }, - '3515f4a9851ad44124e0ddf6149344deb27a97720fc7e5254a9d2c86da7415a9': { - tokenTicker: '001', - tokenName: '01', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '3515f4a9851ad44124e0ddf6149344deb27a97720fc7e5254a9d2c86da7415a9', - }, - '6fb6122742cac8fd1df2d68997fdfa4c077bc22d9ef4a336bfb63d24225f9060': { - tokenTicker: '002', - tokenName: '2', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '6fb6122742cac8fd1df2d68997fdfa4c077bc22d9ef4a336bfb63d24225f9060', - }, - '2936188a41f22a3e0a47d13296147fb3f9ddd2f939fe6382904d21a610e8e49c': { - tokenTicker: '002', - tokenName: '2', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '2936188a41f22a3e0a47d13296147fb3f9ddd2f939fe6382904d21a610e8e49c', - }, - 'e859eeb52e7afca6217fb36784b3b6d3c7386a52f391dd0d00f2ec03a5e8e77b': { - tokenTicker: 'test', - tokenName: 'test', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 1, - tokenId: - 'e859eeb52e7afca6217fb36784b3b6d3c7386a52f391dd0d00f2ec03a5e8e77b', - }, - 'bdb3b4215ca0622e0c4c07655522c376eaa891838a82f0217fa453bb0595a37c': { - tokenTicker: 'Service', - tokenName: 'Evc token', - tokenDocumentUrl: 'https://cashtab.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'bdb3b4215ca0622e0c4c07655522c376eaa891838a82f0217fa453bb0595a37c', - }, - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d': { - tokenTicker: 'WDT', - tokenName: - 'Test Token With Exceptionally Long Name For CSS And Style Revisions', - tokenDocumentUrl: - 'https://www.ImpossiblyLongWebsiteDidYouThinkWebDevWouldBeFun.org', - tokenDocumentHash: - '85b591c15c9f49531e39fcfeb2a5a26b2bd0f7c018fb9cd71b5d92dfb732d5cc', - decimals: 7, - tokenId: - '7443f7c831cdf2b2b04d5f0465ed0bcf348582675b0e4f17906438c232c22f3d', - }, - '7bbf452698a24b138b0357f689587fc6ea58410c34503b1179b91e40e10bba8b': { - tokenTicker: 'COVID', - tokenName: 'COVID-19', - tokenDocumentUrl: 'https://en.wikipedia.org/wiki/COVID-19', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '7bbf452698a24b138b0357f689587fc6ea58410c34503b1179b91e40e10bba8b', - }, - '6376cae692cf0302ecdd63234c14cbb2b21cec75ab538335f90254cfb3ed44cc': { - tokenTicker: 'CLT', - tokenName: 'Cashtab Local Tests', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '6376cae692cf0302ecdd63234c14cbb2b21cec75ab538335f90254cfb3ed44cc', - }, - '666c4318d1f7fef5f2c698262492c519018d4e9130f95d05f6be9f0fb7149e96': { - tokenTicker: 'CPG', - tokenName: 'Cashtab Prod Gamma', - tokenDocumentUrl: 'thecryptoguy.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '666c4318d1f7fef5f2c698262492c519018d4e9130f95d05f6be9f0fb7149e96', - }, - '157e0cdef5d5c51bdea00eac9ab821d809bb9d03cf98da85833614bedb129be6': { - tokenTicker: 'CLNSP', - tokenName: 'ComponentLongNameSpeedLoad', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '157e0cdef5d5c51bdea00eac9ab821d809bb9d03cf98da85833614bedb129be6', - }, - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55': { - tokenTicker: 'CTB', - tokenName: 'CashTabBits', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', - }, - 'ccf5fe5a387559c8ab9efdeb0c0ef1b444e677298cfddf07671245ce3cb3c79f': { - tokenTicker: 'XGB', - tokenName: 'Garmonbozia', - tokenDocumentUrl: 'https://twinpeaks.fandom.com/wiki/Garmonbozia', - tokenDocumentHash: '', - decimals: 8, - tokenId: - 'ccf5fe5a387559c8ab9efdeb0c0ef1b444e677298cfddf07671245ce3cb3c79f', - }, - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3': { - tokenTicker: 'NOCOVID', - tokenName: 'Covid19 Lifetime Immunity', - tokenDocumentUrl: - 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', - }, - 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc': { - tokenTicker: 'CTD', - tokenName: 'Cashtab Dark', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'b8f2a9e767a0be7b80c7e414ef2534586d4da72efddb39a4e70e501ab73375cc', - }, - '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a': { - tokenTicker: 'XBIT', - tokenName: 'eBits', - tokenDocumentUrl: 'https://boomertakes.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - '1101bd5d7b6bbc3176fb2b93d08e76ab532b04ff731d71502249e3cb9b6fcb1a', - }, - '3de671a7107d3803d78f7f4a4e5c794d0903a8d28d16076445c084943c1e2db8': { - tokenTicker: 'CLB', - tokenName: 'Cashtab Local Beta', - tokenDocumentUrl: 'boomertakes.com', - tokenDocumentHash: '', - decimals: 2, - tokenId: - '3de671a7107d3803d78f7f4a4e5c794d0903a8d28d16076445c084943c1e2db8', - }, - '44929ff3b1fc634f982fede112cf12b21199a2ebbcf718412a38de9177d77168': { - tokenTicker: 'coin', - tokenName: 'johncoin', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '44929ff3b1fc634f982fede112cf12b21199a2ebbcf718412a38de9177d77168', - }, - '639a8dba34788ff3ebd3977d4ac045825394285ee648bb1d159e1c12b787ff25': { - tokenTicker: 'CFL', - tokenName: 'Cashtab Facelift', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 9, - tokenId: - '639a8dba34788ff3ebd3977d4ac045825394285ee648bb1d159e1c12b787ff25', - }, - 'd376ebcd518067c8e10c0505865cf7336160b47807e6f1a95739ba90ae838840': { - tokenTicker: 'CFL', - tokenName: 'Cashtab Facelift', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'd376ebcd518067c8e10c0505865cf7336160b47807e6f1a95739ba90ae838840', - }, - 'b40d1f6acdb6ee68d7eca0167fe2753c076bc309b2e3b1af8bff70ca34b945b0': { - tokenTicker: 'KAT', - tokenName: 'KA_Test', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'b40d1f6acdb6ee68d7eca0167fe2753c076bc309b2e3b1af8bff70ca34b945b0', - }, - 'b39fdb53e21d67fa5fd3a11122f1452f15884047f2b80e8efe633c3b520b7a39': { - tokenTicker: 'SCΩΩG', - tokenName: 'Scoogi Omega', - tokenDocumentUrl: 'https://cashtab.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - 'b39fdb53e21d67fa5fd3a11122f1452f15884047f2b80e8efe633c3b520b7a39', - }, - '3adbf501e21c711d20118e003711168eb39f560c01f4c6d6736fa3f3fceaa577': { - tokenTicker: 'OMI', - tokenName: 'Omicron', - tokenDocumentUrl: 'cdc.gov', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '3adbf501e21c711d20118e003711168eb39f560c01f4c6d6736fa3f3fceaa577', - }, - '0916e71779c9de7ee125741d3f5ab01f556356dbc86fd327a24f1e9e22ebc917': { - tokenTicker: 'CTL2', - tokenName: 'Cashtab Token Launch Launch Token v2', - tokenDocumentUrl: 'thecryptoguy.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '0916e71779c9de7ee125741d3f5ab01f556356dbc86fd327a24f1e9e22ebc917', - }, - '6e24e89b6d5284138c69777527760500b99614631bca7f2a5c38f4648dae9524': { - tokenTicker: 'CBB', - tokenName: 'Cashtab Beta Bits', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '6e24e89b6d5284138c69777527760500b99614631bca7f2a5c38f4648dae9524', - }, - '8ead21ce4b3b9e7b57607b97b65b5013496dc6e3dfdea162c08ce7265a66ebc8': { - tokenTicker: 'IFP', - tokenName: 'Infrastructure Funding Proposal Token', - tokenDocumentUrl: 'ifp.cash', - tokenDocumentHash: - 'b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553', - decimals: 8, - tokenId: - '8ead21ce4b3b9e7b57607b97b65b5013496dc6e3dfdea162c08ce7265a66ebc8', - }, - 'e4e1a2fb071fa71ca727e08ed1d8ea52a9531c79d1e5f1ebf483c66b71a8621c': { - tokenTicker: 'CPA', - tokenName: 'Cashtab Prod Alpha', - tokenDocumentUrl: 'thecryptoguy.com', - tokenDocumentHash: '', - decimals: 8, - tokenId: - 'e4e1a2fb071fa71ca727e08ed1d8ea52a9531c79d1e5f1ebf483c66b71a8621c', - }, - '45f0ff5cae7e89da6b96c26c8c48a959214c5f0e983e78d0925f8956ca8848c6': { - tokenTicker: 'CMA', - tokenName: 'CashtabMintAlpha', - tokenDocumentUrl: 'https://cashtabapp.com/', - tokenDocumentHash: '', - decimals: 5, - tokenId: - '45f0ff5cae7e89da6b96c26c8c48a959214c5f0e983e78d0925f8956ca8848c6', - }, - '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc6': { - tokenTicker: 'CTLv3', - tokenName: 'Cashtab Token Launch Launch Token v3', - tokenDocumentUrl: 'coinex.com', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '77ec4036ef8546ac46df6d3a5374e961216f92624627eaeef5d2e1a253df9fc', - }, - }, -}; -export const cashtabCacheWithDecimalNotNumber = { - tokenInfoById: { - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3': { - tokenTicker: 'NOCOVID', - tokenName: 'Covid19 Lifetime Immunity', - tokenDocumentUrl: - 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenDocumentHash: '', - decimals: '0', - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', - }, - }, -}; -export const cashtabCacheWithTokenNameNotString = { - tokenInfoById: { - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3': { - tokenTicker: 'NOCOVID', - tokenName: 888, - tokenDocumentUrl: - 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', - }, - }, -}; -export const cashtabCacheWithMissingTokenName = { - tokenInfoById: { - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3': { - tokenTicker: 'NOCOVID', - tokenDocumentUrl: - 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', - tokenDocumentHash: '', - decimals: 0, - tokenId: - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', - }, - }, -}; diff --git a/cashtab/src/validation/fixtures/vectors.js b/cashtab/src/validation/fixtures/vectors.js --- a/cashtab/src/validation/fixtures/vectors.js +++ b/cashtab/src/validation/fixtures/vectors.js @@ -5,6 +5,8 @@ // Test vectors for validation functions import appConfig from 'config/app'; import { cashtabSettings } from 'config/cashtabSettings'; +import defaultCashtabCache from 'config/cashtabCache'; +import { mockCashtabCache } from 'helpers/fixtures/mocks'; export default { shouldDisableXecSend: { @@ -687,4 +689,23 @@ }, ], }, + isValidCashtabCache: { + expectedReturns: [ + { + description: 'Returns false for legacy cashtabCache', + cashtabCache: { tokenInfoById: {} }, + isValid: false, + }, + { + description: 'Returns true for current version cashtabCache', + cashtabCache: mockCashtabCache, + isValid: true, + }, + { + description: 'Returns true for default cashtabCache', + cashtabCache: defaultCashtabCache, + isValid: true, + }, + ], + }, }; diff --git a/cashtab/src/validation/index.js b/cashtab/src/validation/index.js --- a/cashtab/src/validation/index.js +++ b/cashtab/src/validation/index.js @@ -271,19 +271,6 @@ return settings; }; -export const parseInvalidCashtabCacheForMigration = invalidCashtabCache => { - // create a copy of the invalidCashtabCache - let migratedCashtabCache = invalidCashtabCache; - // determine if settings are invalid because it is missing a parameter - for (let param in defaultCashtabCache) { - if (!Object.prototype.hasOwnProperty.call(invalidCashtabCache, param)) { - // adds the default setting for only that parameter - migratedCashtabCache[param] = defaultCashtabCache[param]; - } - } - return migratedCashtabCache; -}; - /** * Check if an array is a valid Cashtab contact list * A valid contact list is an array of objects @@ -321,69 +308,23 @@ return true; }; +/** + * Validate cashtabCache object found in localforage + * @param {object} cashtabCache + * @returns {boolean} + */ export const isValidCashtabCache = cashtabCache => { - /* - Object must contain all keys listed in defaultCashtabCache - The tokenInfoById object must have keys that are valid token IDs, - and at each one an object like: - { - "tokenTicker": "ST", - "tokenName": "ST", - "tokenDocumentUrl": "developer.bitcoin.com", - "tokenDocumentHash": "", - "decimals": 0, - "tokenId": "bf24d955f59351e738ecd905966606a6837e478e1982943d724eab10caad82fd" - } + // Legacy cashtabCache is an object with key tokenInfoById + // At this key is an object with keys of tokenId + // We are replacing this with a map + // Due to existing bugs in how this is stored, we are not migrating - i.e. an object that contains these keys - 'tokenTicker' is a string - 'tokenName' is a string - 'tokenDocumentUrl' is a string - 'tokenDocumentHash' is a string - 'decimals' is a number - 'tokenId' is a valid tokenId - */ - - // Check that every key in defaultCashtabCache is also in this cashtabCache - const cashtabCacheKeys = Object.keys(defaultCashtabCache); - for (let i = 0; i < cashtabCacheKeys.length; i += 1) { - if (!(cashtabCacheKeys[i] in cashtabCache)) { - return false; - } - } - - // Check that tokenInfoById is expected type and that tokenIds are valid - - const { tokenInfoById } = cashtabCache; - - const tokenIds = Object.keys(tokenInfoById); - - for (let i = 0; i < tokenIds.length; i += 1) { - const thisTokenId = tokenIds[i]; - if (!isValidTokenId(thisTokenId)) { - return false; - } - const { - tokenTicker, - tokenName, - tokenDocumentUrl, - tokenDocumentHash, - decimals, - tokenId, - } = tokenInfoById[thisTokenId]; - - if ( - typeof tokenTicker !== 'string' || - typeof tokenName !== 'string' || - typeof tokenDocumentUrl !== 'string' || - typeof tokenDocumentHash !== 'string' || - typeof decimals !== 'number' || - !isValidTokenId(tokenId) - ) { - return false; - } + const existingKeys = Object.keys(cashtabCache); + if (existingKeys.length !== 1 || existingKeys[0] !== 'tokens') { + return false; } + // We do not validate the stored map is valid, as we validate this before storing it return true; };