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 @@ -229,7 +229,11 @@ // Preserve bch-api for tx history for now, as this will take another stacked diff to migrate to chronik const txHistory = await getTxHistory(BCH, cashAddresses); - const chronikTxHistory = await getTxHistoryChronik(chronik, wallet); + const chronikTxHistory = await getTxHistoryChronik( + chronik, + BCH, + wallet, + ); console.log( `chronikTxHistory as flattened array, sorted by blockheight and time first seen, with parse info, and partial legacy parse info`, chronikTxHistory, 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 @@ -44,6 +44,7 @@ } from '../__mocks__/chronikTxHistory'; import { ChronikClient } from 'chronik-client'; import { when } from 'jest-when'; +import BCHJS from '@psf/bch-js'; it(`getTokenStats successfully returns a token stats object`, async () => { // Initialize chronik @@ -210,8 +211,17 @@ }); it(`Successfully parses an incoming XEC tx`, () => { + const BCH = new BCHJS({ + restURL: 'https://FakeBchApiUrlToEnsureMocksOnly.com', + }); + // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment + BCH.Address.hash160ToCash = jest + .fn() + .mockReturnValue( + 'bitcoincash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvll3cvjwd', + ); expect( - parseChronikTx(lambdaIncomingXecTx, mockParseTxWallet), + parseChronikTx(BCH, lambdaIncomingXecTx, mockParseTxWallet), ).toStrictEqual({ incoming: true, xecAmount: '42', @@ -227,13 +237,23 @@ isEncryptedMessage: false, opReturnMessage: '', outgoingTx: false, + replyAddress: 'ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6', tokenTx: false, }, }); }); it(`Successfully parses an outgoing XEC tx`, () => { + const BCH = new BCHJS({ + restURL: 'https://FakeBchApiUrlToEnsureMocksOnly.com', + }); + // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment + BCH.Address.hash160ToCash = jest + .fn() + .mockReturnValue( + 'bitcoincash:qpmytrdsakt0axrrlswvaj069nat3p9s7ct4lsf8k9', + ); expect( - parseChronikTx(lambdaOutgoingXecTx, mockParseTxWallet), + parseChronikTx(BCH, lambdaOutgoingXecTx, mockParseTxWallet), ).toStrictEqual({ incoming: false, xecAmount: '222', @@ -249,13 +269,21 @@ isEncryptedMessage: false, opReturnMessage: '', outgoingTx: true, + replyAddress: 'ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj', tokenTx: false, }, }); }); it(`Successfully parses an incoming eToken tx`, () => { + const BCH = new BCHJS(); + // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment + BCH.Address.hash160ToCash = jest + .fn() + .mockReturnValue( + 'bitcoincash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvll3cvjwd', + ); expect( - parseChronikTx(lambdaIncomingEtokenTx, mockParseTxWallet), + parseChronikTx(BCH, lambdaIncomingEtokenTx, mockParseTxWallet), ).toStrictEqual({ incoming: true, xecAmount: '5.46', @@ -278,13 +306,23 @@ isEncryptedMessage: false, opReturnMessage: '', outgoingTx: false, + replyAddress: 'ecash:qp89xgjhcqdnzzemts0aj378nfe2mhu9yvxj9nhgg6', tokenTx: true, }, }); }); it(`Successfully parses an outgoing eToken tx`, () => { + const BCH = new BCHJS({ + restURL: 'https://FakeBchApiUrlToEnsureMocksOnly.com', + }); + // This function needs to be mocked as bch-js functions that require Buffer types do not work in jest environment + BCH.Address.hash160ToCash = jest + .fn() + .mockReturnValue( + 'bitcoincash:qpmytrdsakt0axrrlswvaj069nat3p9s7ct4lsf8k9', + ); expect( - parseChronikTx(lambdaOutgoingEtokenTx, mockParseTxWallet), + parseChronikTx(BCH, lambdaOutgoingEtokenTx, mockParseTxWallet), ).toStrictEqual({ incoming: false, xecAmount: '5.46', @@ -307,6 +345,7 @@ isEncryptedMessage: false, opReturnMessage: '', outgoingTx: true, + replyAddress: 'ecash:qpmytrdsakt0axrrlswvaj069nat3p9s7cjctmjasj', tokenTx: true, }, }); 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 @@ -9,6 +9,7 @@ } from 'utils/cashMethods'; import ecies from 'ecies-lite'; import wif from 'wif'; +import cashaddr from 'ecashaddrjs'; // Return false if do not get a valid response export const getTokenStats = async (chronik, tokenId) => { @@ -423,7 +424,7 @@ }); }; -export const parseChronikTx = (tx, wallet) => { +export const parseChronikTx = (BCH, tx, wallet) => { const walletHash160s = getHashArrayFromWallet(wallet); const { inputs, outputs } = tx; // Assign defaults @@ -441,6 +442,7 @@ let isCashtabMessage = false; let isEncryptedMessage = false; let decryptionSuccess = false; + let replyAddress = ''; // Iterate over inputs to see if this is an incoming tx (incoming === true) for (let i = 0; i < inputs.length; i += 1) { @@ -465,7 +467,15 @@ thisInputSendingHash160.indexOf('76a914') + '76a914'.length, thisInputSendingHash160.lastIndexOf('88ac'), ); + + let replyAddressBchFormat = + BCH.Address.hash160ToCash(originatingHash160); + + const { type, hash } = cashaddr.decode(replyAddressBchFormat); + replyAddress = cashaddr.encode('ecash', type, hash); + console.log(`replyAddressXecFormat`, replyAddress); } catch (err) { + console.log(`err from ${originatingHash160}`, err); // If the transaction is nonstandard, don't worry about a reply address for now originatingHash160 = 'N/A'; } @@ -684,6 +694,7 @@ isCashtabMessage, isEncryptedMessage, decryptionSuccess, + replyAddress, }, }; } @@ -704,11 +715,12 @@ isCashtabMessage, isEncryptedMessage, decryptionSuccess, + replyAddress, }, }; }; -export const getTxHistoryChronik = async (chronik, wallet) => { +export const getTxHistoryChronik = async (chronik, BCH, wallet) => { // 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 @@ -754,7 +766,7 @@ const parsedTxs = []; for (let i = 0; i < sortedTxHistoryArray.length; i += 1) { const sortedTx = sortedTxHistoryArray[i]; - sortedTx.parsed = parseChronikTx(sortedTx, wallet); + sortedTx.parsed = parseChronikTx(BCH, sortedTx, wallet); parsedTxs.push(sortedTx); }