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 @@ -8,7 +8,6 @@ isValidStoredWallet, isLegacyMigrationRequired, getHashArrayFromWallet, - checkWalletForTokenInfo, isActiveWebsocket, getWalletBalanceFromUtxos, } from 'utils/cashMethods'; @@ -880,56 +879,91 @@ // get txid info const txid = msg.txid; - const txDetails = await chronik.tx(txid); + + let incomingTxDetails; + try { + incomingTxDetails = await chronik.tx(txid); + } catch (err) { + // In this case, no notification + return console.log( + `Error in chronik.tx(${txid} while processing an incoming websocket tx`, + err, + ); + } + + // 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(txDetails, wallet); + const parsedChronikTx = parseChronikTx( + BCH, + incomingTxDetails, + wallet, + tokenInfoById, + ); + /* 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 */ if (parsedChronikTx.incoming) { if (parsedChronikTx.isEtokenTx) { - try { - // Get the tokenID - const incomingTokenId = parsedChronikTx.slpMeta.tokenId; - - // Check cache for token info - // NB this procedure will change when chronik utxo formatting is implemented - let incomingTokenInfo = checkWalletForTokenInfo( - incomingTokenId, - wallet, + let eTokenAmountReceived = parsedChronikTx.etokenAmount; + if (parsedChronikTx.genesisInfo.success) { + // Send this info to the notification function + eTokenReceivedNotification( + currency, + parsedChronikTx.genesisInfo.tokenTicker, + eTokenAmountReceived, + parsedChronikTx.genesisInfo.tokenName, ); + } else { + // Get genesis info from API and add to cache + try { + // Get the tokenID + const incomingTokenId = parsedChronikTx.slpMeta.tokenId; - let eTokenAmountReceived; - if (!incomingTokenInfo) { // chronik call to genesis tx to get this info const tokenGenesisInfo = await chronik.tx( incomingTokenId, ); - incomingTokenInfo = { - decimals: - tokenGenesisInfo.slpTxData.genesisInfo.decimals, - name: tokenGenesisInfo.slpTxData.genesisInfo - .tokenName, - ticker: tokenGenesisInfo.slpTxData.genesisInfo - .tokenTicker, - }; + const { genesisInfo } = tokenGenesisInfo.slpTxData; + // Add this to cashtabCache + let tokenInfoByIdUpdatedForThisToken = tokenInfoById; + tokenInfoByIdUpdatedForThisToken[incomingTokenId] = + genesisInfo; + writeTokenInfoByIdToCache( + tokenInfoByIdUpdatedForThisToken, + ); + // Update the tokenInfoById key in cashtabCache + setCashtabCache({ + ...cashtabCache, + tokenInfoById: tokenInfoByIdUpdatedForThisToken, + }); + + // Calculate eToken amount with decimals + eTokenAmountReceived = new BigNumber( + parsedChronikTx.etokenAmount, + ).shiftedBy(-1 * genesisInfo.decimals); + + // Send this info to the notification function + eTokenReceivedNotification( + currency, + genesisInfo.tokenTicker, + eTokenAmountReceived, + genesisInfo.tokenName, + ); + } catch (err) { + console.log( + `Error in getting and setting new token info for incoming eToken tx`, + err, + ); } - // Calculate eToken amount with decimals - eTokenAmountReceived = new BigNumber( - parsedChronikTx.etokenAmount, - ).shiftedBy(-1 * incomingTokenInfo.decimals); - // Send this info to the notification function - eTokenReceivedNotification( - currency, - incomingTokenInfo.ticker, - eTokenAmountReceived, - incomingTokenInfo.name, - ); - } catch (err) { - // In this case, no incoming tx notification is received - // This is an acceptable error condition, no need to fallback to another notification option - console.log( - `Error parsing eToken data for incoming tx notification`, - err, - ); } } else { xecReceivedNotificationWebsocket( diff --git a/web/cashtab/src/utils/__tests__/cashMethods.test.js b/web/cashtab/src/utils/__tests__/cashMethods.test.js --- a/web/cashtab/src/utils/__tests__/cashMethods.test.js +++ b/web/cashtab/src/utils/__tests__/cashMethods.test.js @@ -14,7 +14,6 @@ parseOpReturn, convertEcashtoEtokenAddr, getHashArrayFromWallet, - checkWalletForTokenInfo, isActiveWebsocket, parseXecSendValue, getChangeAddressFromInputUtxos, @@ -1367,27 +1366,6 @@ 'ba8257db65f40359989c7b894c5e88ed7b6344f6', ]); }); - - it(`Returns decimals, name, and ticker for an eToken stored in wallet object`, () => { - expect( - checkWalletForTokenInfo( - '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', - validStoredWallet, - ), - ).toStrictEqual({ - decimals: 0, - name: 'Covid19 Lifetime Immunity', - ticker: 'NOCOVID', - }); - }); - it(`Returns false for an eToken not stored in a wallet object`, () => { - expect( - checkWalletForTokenInfo( - '98183238638ecb4ddc365056e22de0e8a05448c1e6084bae247fae5a74ad4f48', - validStoredWallet, - ), - ).toBe(false); - }); it(`isActiveWebsocket returns true for an active chronik websocket connection`, () => { expect(isActiveWebsocket(activeWebsocketAlpha)).toBe(true); }); 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 @@ -314,6 +314,17 @@ tokenType: 'FUNGIBLE', txType: 'SEND', }, + genesisInfo: { + decimals: 0, + success: true, + tokenDocumentHash: '', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenName: 'Covid19 Lifetime Immunity', + tokenTicker: 'NOCOVID', + }, etokenAmount: '12', legacy: { airdropFlag: false, @@ -358,6 +369,17 @@ tokenType: 'FUNGIBLE', txType: 'SEND', }, + genesisInfo: { + decimals: 0, + success: true, + tokenDocumentHash: '', + tokenDocumentUrl: + 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/covid-19-vaccines', + tokenId: + '4bd147fc5d5ff26249a9299c46b80920c0b81f59a60e05428262160ebee0b0c3', + tokenName: 'Covid19 Lifetime Immunity', + tokenTicker: 'NOCOVID', + }, etokenAmount: '17', legacy: { airdropFlag: false, @@ -403,6 +425,16 @@ tokenId: 'cf601c56b58bc05a39a95374a4a865f0a8b56544ea937b30fb46315441717c50', }, + genesisInfo: { + decimals: 7, + success: true, + tokenDocumentHash: '', + tokenDocumentUrl: 'https://cashtab.com/', + tokenId: + 'cf601c56b58bc05a39a95374a4a865f0a8b56544ea937b30fb46315441717c50', + tokenName: 'UpdateTest', + tokenTicker: 'UDT', + }, legacy: { amountSent: '0', amountReceived: 0, @@ -447,6 +479,16 @@ tokenId: 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', }, + genesisInfo: { + decimals: 9, + success: true, + tokenDocumentHash: '', + tokenDocumentUrl: 'https://cashtabapp.com/', + tokenId: + 'acba1d7f354c6d4d001eb99d31de174e5cea8a31d692afd6e7eb8474ad541f55', + tokenName: 'CashTabBits', + tokenTicker: 'CTB', + }, legacy: { amountSent: 0, amountReceived: '5.46', diff --git a/web/cashtab/src/utils/cashMethods.js b/web/cashtab/src/utils/cashMethods.js --- a/web/cashtab/src/utils/cashMethods.js +++ b/web/cashtab/src/utils/cashMethods.js @@ -832,31 +832,6 @@ return hash160Array; }; -export const checkWalletForTokenInfo = (tokenId, wallet) => { - /* - Check wallet for cached information about a given tokenId - Return {decimals: tokenDecimals, name: tokenName, ticker: tokenTicker} - If this tokenId does not exist in wallet, return false - */ - try { - const { tokens } = wallet.state; - for (let i = 0; i < tokens.length; i += 1) { - const thisTokenId = tokens[i].tokenId; - if (tokenId === thisTokenId) { - return { - decimals: tokens[i].info.decimals, - ticker: tokens[i].info.tokenTicker, - name: tokens[i].info.tokenName, - }; - } - } - } catch (err) { - return false; - } - - return false; -}; - export const isActiveWebsocket = ws => { // Return true if websocket is connected and subscribed // Otherwise return false 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 @@ -680,21 +680,26 @@ xecAmount = xecAmount.toString(); // Get decimal info for correct etokenAmount + let genesisInfo = {}; if (isEtokenTx) { // Get token genesis info from cache - let tokenGenesisInfo = {}; + let decimals = 0; try { - tokenGenesisInfo = tokenInfoById[tx.slpTxData.slpMeta.tokenId]; + genesisInfo = tokenInfoById[tx.slpTxData.slpMeta.tokenId]; + genesisInfo.success = true; // tokenGenesisInfo should be there for every tx in tx history, since it's already been cached for every utxo in the wallet // but try...catch just in case - decimals = tokenGenesisInfo.decimals; + decimals = genesisInfo.decimals; etokenAmount = etokenAmount.shiftedBy(-1 * decimals); } catch (err) { console.log( `Error getting token info from cache in parseChronikTx`, err, ); + // To keep this function synchronous, do not get this info from the API if it is not in cache + // Instead, return a flag so that useWallet.js knows and can fetch this info + add it to cache + genesisInfo.success = false; } } etokenAmount = etokenAmount.toString(); @@ -712,6 +717,7 @@ isEtokenTx, etokenAmount, slpMeta, + genesisInfo, legacy: { amountSent: incoming ? 0 : xecAmount, amountReceived: incoming ? xecAmount : 0,