From 23de831ea86899b838fcb2f2ad68417869c06cbe Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 1 Sep 2021 12:14:29 -0400 Subject: [PATCH 01/41] feat(TxState): Add logs to debug --- package.json | 2 +- src/transaction/TransactionController.test.ts | 369 +----------------- src/transaction/TransactionController.ts | 37 +- src/transaction/mocks/mockEthTxs.ts | 77 ++++ src/transaction/mocks/mockTokenTxs.ts | 288 ++++++++++++++ 5 files changed, 405 insertions(+), 368 deletions(-) create mode 100644 src/transaction/mocks/mockEthTxs.ts create mode 100644 src/transaction/mocks/mockTokenTxs.ts diff --git a/package.json b/package.json index 11e243e992..d7785bd701 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@metamask/controllers", - "version": "15.0.1", + "version": "14.2.0-guto3", "description": "Collection of platform-agnostic modules for creating secure data models for cryptocurrency wallets", "keywords": [ "MetaMask", diff --git a/src/transaction/TransactionController.test.ts b/src/transaction/TransactionController.test.ts index f69e3488d0..eba01c0a10 100644 --- a/src/transaction/TransactionController.test.ts +++ b/src/transaction/TransactionController.test.ts @@ -10,6 +10,8 @@ import { TransactionStatus, TransactionMeta, } from './TransactionController'; +import { mockEthTxs } from './mocks/mockEthTxs'; +import { mockTokenTxs } from './mocks/mockTokenTxs'; const globalAny: any = global; @@ -142,372 +144,9 @@ const TOKEN_TRANSACTION_HASH = const ETHER_TRANSACTION_HASH = '0xa9d17df83756011ea63e1f0ca50a6627df7cac9806809e36680fcf4e88cb9dae'; -const ETH_TRANSACTIONS = [ - { - blockNumber: '4535101', - confirmations: '10', - contractAddress: '', - cumulativeGasUsed: '120607', - from: '0xe46abaf75cfbff815c0b7ffed6f02b0760ea27f1', - gas: '335208', - gasPrice: '10000000000', - gasUsed: '21000', - hash: ETHER_TRANSACTION_HASH, - input: '0x', - isError: '0', - nonce: '9', - timeStamp: '1543596286', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - transactionIndex: '2', - txreceipt_status: '1', - value: '100000000000000000', - }, - { - blockNumber: '4535108', - confirmations: '3', - contractAddress: '', - cumulativeGasUsed: '693910', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - gas: '335208', - gasPrice: '20000000000', - gasUsed: '21000', - hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff92', - input: '0x', - isError: '0', - nonce: '0', - timeStamp: '1543596378', - to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', - transactionIndex: '12', - txreceipt_status: '1', - value: '50000000000000000', - }, - { - blockNumber: '4535105', - confirmations: '4', - contractAddress: '', - cumulativeGasUsed: '693910', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - gas: '335208', - gasPrice: '20000000000', - gasUsed: '21000', - hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff91', - input: '0x', - isError: '0', - nonce: '1', - timeStamp: '1543596356', - transactionIndex: '13', - txreceipt_status: '1', - value: '50000000000000000', - }, - { - blockNumber: '4535106', - confirmations: '4', - contractAddress: '', - cumulativeGasUsed: '693910', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - gas: '335208', - gasPrice: '20000000000', - gasUsed: '21000', - hash: '0x342e9d73e10004af41d04973139fc7219dbadcbb5629730cfe65e9f9cb15ff91', - input: '0x11', - isError: '0', - nonce: '3', - timeStamp: '1543596356', - to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', - transactionIndex: '13', - txreceipt_status: '1', - value: '50000000000000000', - }, -]; +const ETH_TRANSACTIONS = mockEthTxs(ETHER_TRANSACTION_HASH); -const TOKEN_TRANSACTIONS = [ - { - blockNumber: '8222239', - timeStamp: '1564091067', - hash: TOKEN_TRANSACTION_HASH, - nonce: '2329', - blockHash: - '0x3c30a9be9aea7be13caad419444140c11839d72e70479ec7e9c6d8bd08c533bc', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '69', - gas: '624874', - gasPrice: '20000000000', - gasUsed: '609874', - cumulativeGasUsed: '3203881', - input: 'deprecated', - confirmations: '3659676', - }, - { - blockNumber: '8222250', - timeStamp: '1564091247', - hash: '0xdcd1c8bee545d3f76d80b20a23ad44276ba2e376681228eb4570cf3518491279', - nonce: '2330', - blockHash: - '0x16986dd66bedb20a5b846ec2b6c0ecaa62f1c4b51fac58c1326101fd9126dd82', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '40', - gas: '594268', - gasPrice: '20000000000', - gasUsed: '579268', - cumulativeGasUsed: '2009011', - input: 'deprecated', - confirmations: '3659665', - }, - { - blockNumber: '8223771', - timeStamp: '1564111652', - hash: '0x070369e6f560b0deca52e050ff1a961fa7b688bbec5cea08435921c9d9b0f52e', - nonce: '2333', - blockHash: - '0x0aff8b36881be99df6d176d7c64c2171672c0483684a10c112d2c90fefe30a0a', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '132', - gas: '583810', - gasPrice: '6000000000', - gasUsed: '568810', - cumulativeGasUsed: '6956245', - input: 'deprecated', - confirmations: '3658144', - }, - { - blockNumber: '8224850', - timeStamp: '1564126442', - hash: '0x8ef20ec9597c8c2e945bcc76d2668e5d3bb088b081fe8c5b5af2e1cbd315a20f', - nonce: '31', - blockHash: - '0xb80d4d861ecb7a3cb14e591c0aaeb226842d0267772affa2acc1a590c7535647', - from: '0x6c70e3563cef0c6835703bb2664c9f59a92353e4', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '10000000000000000000', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '169', - gas: '78447', - gasPrice: '2000000000', - gasUsed: '52298', - cumulativeGasUsed: '7047823', - input: 'deprecated', - confirmations: '3657065', - }, - { - blockNumber: '8228053', - timeStamp: '1564168901', - hash: '0xa0f2d7b558bb3cc28fa568f6feb8ed30eb28a01a674d7c0d4ae603fc691e6020', - nonce: '2368', - blockHash: - '0x62c515ea049842c968ca67499f47a32a11394364d319d9c9cc0a0211652a7294', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '43', - gas: '567156', - gasPrice: '3000000000', - gasUsed: '552156', - cumulativeGasUsed: '3048261', - input: 'deprecated', - confirmations: '3653862', - }, - { - blockNumber: '8315335', - timeStamp: '1565339223', - hash: '0x464df60fe00b6dd04c9e8ab341d02af9b10a619d2fcd60fd2971f10edf12118f', - nonce: '206760', - blockHash: - '0x98275388ef6708debe35ac7bf2e30143c9b1fd9e0e457ca03598fc1f4209e273', - from: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad', - contractAddress: '0x4dc3643dbc642b72c158e7f3d2ff232df61cb6ce', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '100000000000000000', - tokenName: 'Amber', - tokenSymbol: 'AMB', - tokenDecimal: '18', - transactionIndex: '186', - gas: '60000', - gasPrice: '2000000000', - gasUsed: '52108', - cumulativeGasUsed: '7490707', - input: 'deprecated', - confirmations: '3566580', - }, - { - blockNumber: '8350846', - timeStamp: '1565815049', - hash: '0xc0682327ad3efd56dfa33e8206b4e09efad4e419a6191076069d217e3ee2341f', - nonce: '2506', - blockHash: - '0xd0aa3c0e319fdfeb21b0192cf77b9760b8668060a5977a5f10f8413531083afa', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '4', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '48', - gas: '578737', - gasPrice: '3000000000', - gasUsed: '518737', - cumulativeGasUsed: '2848015', - input: 'deprecated', - confirmations: '3531069', - }, - { - blockNumber: '8350859', - timeStamp: '1565815221', - hash: '0x989ea9f3ee576fa43957f44363e839adf1a4a397c3d8392a4f7cbbf7949fd0ae', - nonce: '2', - blockHash: - '0xb9cf1d29c665c052e3831b5754903e539c5b0b1d33b8bcab6cd2d450764d601f', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x09cabec1ead1c0ba254b09efb3ee13841712be14', - value: '10000000000000000000', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '31', - gas: '60734', - gasPrice: '1000000000', - gasUsed: '54745', - cumulativeGasUsed: '7833857', - input: 'deprecated', - confirmations: '3531056', - }, - { - blockNumber: '8679548', - timeStamp: '1570244087', - hash: '0xc0016b89b3b525b30d73f242653b0d80ec3ebf285376dff5bb52cef3261498b2', - nonce: '3', - blockHash: - '0x1ceb2f8b83087f010773e2acf63d1526633c8a884bd1980f118a1bba576be69f', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '56', - gas: '993379', - gasPrice: '1440000000', - gasUsed: '647253', - cumulativeGasUsed: '3562204', - input: 'deprecated', - confirmations: '3202367', - }, - { - blockNumber: '8679548', - timeStamp: '1570244087', - hash: '0xc0016b89b3b525b30d73f242653b0d80ec3ebf285376dff5bb52cef3261498b2', - nonce: '3', - blockHash: - '0x1ceb2f8b83087f010773e2acf63d1526633c8a884bd1980f118a1bba576be69f', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '56', - gas: '993379', - gasPrice: '1440000000', - gasUsed: '647253', - cumulativeGasUsed: '3562204', - input: 'deprecated', - confirmations: '3202367', - }, - { - blockNumber: '8694142', - timeStamp: '1570440625', - hash: '0xd8397138bb93d56e50d01e92a9eae99ebd3ae28844acdaa4663976a5501116cf', - nonce: '2837', - blockHash: - '0xba45dd64e71e146066af9b6d2dd3bc5d72f4a3399148c155dced74c139fc3c51', - from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', - contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '0', - tokenName: 'Sai Stablecoin v1.0', - tokenSymbol: 'SAI', - tokenDecimal: '18', - transactionIndex: '217', - gas: '600632', - gasPrice: '9000000000', - gasUsed: '570632', - cumulativeGasUsed: '9023725', - input: 'deprecated', - confirmations: '3187773', - }, - { - blockNumber: '10877041', - timeStamp: '1600310867', - hash: '0xc8bd16b6b41b4c24849eb6869702e1489c808cb5b125b01f084e38fefcb5ea77', - nonce: '4', - blockHash: - '0x7fa16a022bcf1f69c2d7adf6bd7d3f058e808eec5c66aaa910dfa8016a5333d1', - from: '0x090d4613473dee047c3f2706764f49e0821d256e', - contractAddress: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '400000000000000000000', - tokenName: 'Uniswap', - tokenSymbol: 'UNI', - tokenDecimal: '18', - transactionIndex: '42', - gas: '90038', - gasPrice: '550000000000', - gasUsed: '81853', - cumulativeGasUsed: '3163540', - input: 'deprecated', - confirmations: '1004874', - }, - { - blockNumber: '10877897', - timeStamp: '1600321973', - hash: '0xa7162489faef826ee77862ed5210b01726524f09428f69842118dad394842d62', - nonce: '6', - blockHash: - '0xa74eb9d16f65f307dde4ce58c813c981b28f242edf1090ee2ac42caac9dccaca', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - contractAddress: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', - to: '0x5e736f1f25992b2cad20ded179a52823d3d24b26', - value: '400000000000000000000', - tokenName: 'Uniswap', - tokenSymbol: 'UNI', - tokenDecimal: '18', - transactionIndex: '86', - gas: '60759', - gasPrice: '640000000000', - gasUsed: '25506', - cumulativeGasUsed: '4408393', - input: 'deprecated', - confirmations: '1004018', - }, -]; +const TOKEN_TRANSACTIONS = mockTokenTxs(TOKEN_TRANSACTION_HASH); const TRANSACTIONS_IN_STATE: TransactionMeta[] = [ // Token tx, hash is in TOKEN_TRANSACTIONS diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 1838a3d0ef..a7cd97bcb9 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -673,6 +673,11 @@ export class TransactionController extends BaseController< this.updateTransaction(transactionMeta); const rawTransaction = bufferToHex(signedTx.serialize()); + console.log( + 'Controller Log @ 635 -> rawTransaction in approveTransaction method', + rawTransaction, + ); + transactionMeta.rawTransaction = rawTransaction; this.updateTransaction(transactionMeta); const transactionHash = await query(this.ethQuery, 'sendRawTransaction', [ @@ -1017,7 +1022,8 @@ export class TransactionController extends BaseController< await safelyExecute(() => Promise.all( transactions.map(async (meta, index) => { - // Using fallback to networkID only when there is no chainId present. Should be removed when networkID is completely removed. + // Using fallback to networkID only when there is no chainId present. + // Should be removed when networkID is completely removed. if ( meta.status === TransactionStatus.submitted && (meta.chainId === currentChainId || @@ -1026,6 +1032,12 @@ export class TransactionController extends BaseController< const txObj = await query(this.ethQuery, 'getTransactionByHash', [ meta.transactionHash, ]); + + console.log( + 'Controller Log @ 1088 queryTransactionStatuses txObj', + txObj, + ); + /* istanbul ignore next */ if (txObj?.blockNumber) { transactions[index].status = TransactionStatus.confirmed; @@ -1037,6 +1049,10 @@ export class TransactionController extends BaseController< ), ); /* istanbul ignore else */ + console.log( + 'Controller Log @ 1104 queryTransactionStatuses gotUpdates', + gotUpdates, + ); if (gotUpdates) { this.update({ transactions: this.trimTransactionsForState(transactions), @@ -1114,6 +1130,15 @@ export class TransactionController extends BaseController< etherscanTokenResponse, ] = await handleTransactionFetch(networkType, address, opt); + console.log( + 'Controller Log @ 1238 fetchAll etherscanTxResponse', + etherscanTxResponse, + ); + console.log( + 'Controller Log @ 1238 fetchAll etherscanTokenResponse', + etherscanTokenResponse, + ); + const normalizedTxs = etherscanTxResponse.result.map( (tx: EtherscanTransactionMeta) => this.normalizeTx(tx, currentNetworkID, currentChainId), @@ -1172,6 +1197,10 @@ export class TransactionController extends BaseController< if (allTxs.length > this.state.transactions.length) { this.update({ transactions: this.trimTransactionsForState(allTxs) }); } + console.log( + 'Controller Log @ 1250 fetchAll this.state.transactions', + this.state.transactions, + ); return latestIncomingTxBlockNumber; } @@ -1212,7 +1241,7 @@ export class TransactionController extends BaseController< } /** - * Fucntion to determine if the transaction is in a final state + * Function to determine if the transaction is in a final state * @param status - Transaction status * @returns boolean if the transaction is in a final state */ @@ -1224,6 +1253,10 @@ export class TransactionController extends BaseController< status === TransactionStatus.cancelled ); } + + // private async transactionStateReconciler(remoteTxs: any, localTxs: any) {} + + // private groupByNonce(transactions: Transaction[]) {} } export default TransactionController; diff --git a/src/transaction/mocks/mockEthTxs.ts b/src/transaction/mocks/mockEthTxs.ts new file mode 100644 index 0000000000..948ae395cf --- /dev/null +++ b/src/transaction/mocks/mockEthTxs.ts @@ -0,0 +1,77 @@ +export const mockEthTxs = (etherTxHash: string) => [ + { + blockNumber: '4535101', + confirmations: '10', + contractAddress: '', + cumulativeGasUsed: '120607', + from: '0xe46abaf75cfbff815c0b7ffed6f02b0760ea27f1', + gas: '335208', + gasPrice: '10000000000', + gasUsed: '21000', + hash: etherTxHash, + input: '0x', + isError: '0', + nonce: '9', + timeStamp: '1543596286', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + transactionIndex: '2', + txreceipt_status: '1', + value: '100000000000000000', + }, + { + blockNumber: '4535108', + confirmations: '3', + contractAddress: '', + cumulativeGasUsed: '693910', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + gas: '335208', + gasPrice: '20000000000', + gasUsed: '21000', + hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff92', + input: '0x', + isError: '0', + nonce: '0', + timeStamp: '1543596378', + to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', + transactionIndex: '12', + txreceipt_status: '1', + value: '50000000000000000', + }, + { + blockNumber: '4535105', + confirmations: '4', + contractAddress: '', + cumulativeGasUsed: '693910', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + gas: '335208', + gasPrice: '20000000000', + gasUsed: '21000', + hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff91', + input: '0x', + isError: '0', + nonce: '1', + timeStamp: '1543596356', + transactionIndex: '13', + txreceipt_status: '1', + value: '50000000000000000', + }, + { + blockNumber: '4535106', + confirmations: '4', + contractAddress: '', + cumulativeGasUsed: '693910', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + gas: '335208', + gasPrice: '20000000000', + gasUsed: '21000', + hash: '0x342e9d73e10004af41d04973139fc7219dbadcbb5629730cfe65e9f9cb15ff91', + input: '0x11', + isError: '0', + nonce: '3', + timeStamp: '1543596356', + to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', + transactionIndex: '13', + txreceipt_status: '1', + value: '50000000000000000', + }, +]; diff --git a/src/transaction/mocks/mockTokenTxs.ts b/src/transaction/mocks/mockTokenTxs.ts new file mode 100644 index 0000000000..c0f794f880 --- /dev/null +++ b/src/transaction/mocks/mockTokenTxs.ts @@ -0,0 +1,288 @@ +export const mockTokenTxs = (tokenTxHash: string) => [ + { + blockNumber: '8222239', + timeStamp: '1564091067', + hash: tokenTxHash, + nonce: '2329', + blockHash: + '0x3c30a9be9aea7be13caad419444140c11839d72e70479ec7e9c6d8bd08c533bc', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '69', + gas: '624874', + gasPrice: '20000000000', + gasUsed: '609874', + cumulativeGasUsed: '3203881', + input: 'deprecated', + confirmations: '3659676', + }, + { + blockNumber: '8222250', + timeStamp: '1564091247', + hash: '0xdcd1c8bee545d3f76d80b20a23ad44276ba2e376681228eb4570cf3518491279', + nonce: '2330', + blockHash: + '0x16986dd66bedb20a5b846ec2b6c0ecaa62f1c4b51fac58c1326101fd9126dd82', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '40', + gas: '594268', + gasPrice: '20000000000', + gasUsed: '579268', + cumulativeGasUsed: '2009011', + input: 'deprecated', + confirmations: '3659665', + }, + { + blockNumber: '8223771', + timeStamp: '1564111652', + hash: '0x070369e6f560b0deca52e050ff1a961fa7b688bbec5cea08435921c9d9b0f52e', + nonce: '2333', + blockHash: + '0x0aff8b36881be99df6d176d7c64c2171672c0483684a10c112d2c90fefe30a0a', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '132', + gas: '583810', + gasPrice: '6000000000', + gasUsed: '568810', + cumulativeGasUsed: '6956245', + input: 'deprecated', + confirmations: '3658144', + }, + { + blockNumber: '8224850', + timeStamp: '1564126442', + hash: '0x8ef20ec9597c8c2e945bcc76d2668e5d3bb088b081fe8c5b5af2e1cbd315a20f', + nonce: '31', + blockHash: + '0xb80d4d861ecb7a3cb14e591c0aaeb226842d0267772affa2acc1a590c7535647', + from: '0x6c70e3563cef0c6835703bb2664c9f59a92353e4', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '10000000000000000000', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '169', + gas: '78447', + gasPrice: '2000000000', + gasUsed: '52298', + cumulativeGasUsed: '7047823', + input: 'deprecated', + confirmations: '3657065', + }, + { + blockNumber: '8228053', + timeStamp: '1564168901', + hash: '0xa0f2d7b558bb3cc28fa568f6feb8ed30eb28a01a674d7c0d4ae603fc691e6020', + nonce: '2368', + blockHash: + '0x62c515ea049842c968ca67499f47a32a11394364d319d9c9cc0a0211652a7294', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '43', + gas: '567156', + gasPrice: '3000000000', + gasUsed: '552156', + cumulativeGasUsed: '3048261', + input: 'deprecated', + confirmations: '3653862', + }, + { + blockNumber: '8315335', + timeStamp: '1565339223', + hash: '0x464df60fe00b6dd04c9e8ab341d02af9b10a619d2fcd60fd2971f10edf12118f', + nonce: '206760', + blockHash: + '0x98275388ef6708debe35ac7bf2e30143c9b1fd9e0e457ca03598fc1f4209e273', + from: '0x00cfbbaf7ddb3a1476767101c12a0162e241fbad', + contractAddress: '0x4dc3643dbc642b72c158e7f3d2ff232df61cb6ce', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + tokenName: 'Amber', + tokenSymbol: 'AMB', + tokenDecimal: '18', + transactionIndex: '186', + gas: '60000', + gasPrice: '2000000000', + gasUsed: '52108', + cumulativeGasUsed: '7490707', + input: 'deprecated', + confirmations: '3566580', + }, + { + blockNumber: '8350846', + timeStamp: '1565815049', + hash: '0xc0682327ad3efd56dfa33e8206b4e09efad4e419a6191076069d217e3ee2341f', + nonce: '2506', + blockHash: + '0xd0aa3c0e319fdfeb21b0192cf77b9760b8668060a5977a5f10f8413531083afa', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '4', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '48', + gas: '578737', + gasPrice: '3000000000', + gasUsed: '518737', + cumulativeGasUsed: '2848015', + input: 'deprecated', + confirmations: '3531069', + }, + { + blockNumber: '8350859', + timeStamp: '1565815221', + hash: '0x989ea9f3ee576fa43957f44363e839adf1a4a397c3d8392a4f7cbbf7949fd0ae', + nonce: '2', + blockHash: + '0xb9cf1d29c665c052e3831b5754903e539c5b0b1d33b8bcab6cd2d450764d601f', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x09cabec1ead1c0ba254b09efb3ee13841712be14', + value: '10000000000000000000', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '31', + gas: '60734', + gasPrice: '1000000000', + gasUsed: '54745', + cumulativeGasUsed: '7833857', + input: 'deprecated', + confirmations: '3531056', + }, + { + blockNumber: '8679548', + timeStamp: '1570244087', + hash: '0xc0016b89b3b525b30d73f242653b0d80ec3ebf285376dff5bb52cef3261498b2', + nonce: '3', + blockHash: + '0x1ceb2f8b83087f010773e2acf63d1526633c8a884bd1980f118a1bba576be69f', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '56', + gas: '993379', + gasPrice: '1440000000', + gasUsed: '647253', + cumulativeGasUsed: '3562204', + input: 'deprecated', + confirmations: '3202367', + }, + { + blockNumber: '8679548', + timeStamp: '1570244087', + hash: '0xc0016b89b3b525b30d73f242653b0d80ec3ebf285376dff5bb52cef3261498b2', + nonce: '3', + blockHash: + '0x1ceb2f8b83087f010773e2acf63d1526633c8a884bd1980f118a1bba576be69f', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '56', + gas: '993379', + gasPrice: '1440000000', + gasUsed: '647253', + cumulativeGasUsed: '3562204', + input: 'deprecated', + confirmations: '3202367', + }, + { + blockNumber: '8694142', + timeStamp: '1570440625', + hash: '0xd8397138bb93d56e50d01e92a9eae99ebd3ae28844acdaa4663976a5501116cf', + nonce: '2837', + blockHash: + '0xba45dd64e71e146066af9b6d2dd3bc5d72f4a3399148c155dced74c139fc3c51', + from: '0xdfa6edae2ec0cf1d4a60542422724a48195a5071', + contractAddress: '0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '0', + tokenName: 'Sai Stablecoin v1.0', + tokenSymbol: 'SAI', + tokenDecimal: '18', + transactionIndex: '217', + gas: '600632', + gasPrice: '9000000000', + gasUsed: '570632', + cumulativeGasUsed: '9023725', + input: 'deprecated', + confirmations: '3187773', + }, + { + blockNumber: '10877041', + timeStamp: '1600310867', + hash: '0xc8bd16b6b41b4c24849eb6869702e1489c808cb5b125b01f084e38fefcb5ea77', + nonce: '4', + blockHash: + '0x7fa16a022bcf1f69c2d7adf6bd7d3f058e808eec5c66aaa910dfa8016a5333d1', + from: '0x090d4613473dee047c3f2706764f49e0821d256e', + contractAddress: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '400000000000000000000', + tokenName: 'Uniswap', + tokenSymbol: 'UNI', + tokenDecimal: '18', + transactionIndex: '42', + gas: '90038', + gasPrice: '550000000000', + gasUsed: '81853', + cumulativeGasUsed: '3163540', + input: 'deprecated', + confirmations: '1004874', + }, + { + blockNumber: '10877897', + timeStamp: '1600321973', + hash: '0xa7162489faef826ee77862ed5210b01726524f09428f69842118dad394842d62', + nonce: '6', + blockHash: + '0xa74eb9d16f65f307dde4ce58c813c981b28f242edf1090ee2ac42caac9dccaca', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + contractAddress: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984', + to: '0x5e736f1f25992b2cad20ded179a52823d3d24b26', + value: '400000000000000000000', + tokenName: 'Uniswap', + tokenSymbol: 'UNI', + tokenDecimal: '18', + transactionIndex: '86', + gas: '60759', + gasPrice: '640000000000', + gasUsed: '25506', + cumulativeGasUsed: '4408393', + input: 'deprecated', + confirmations: '1004018', + }, +]; From b26d881e751e2504e6ad5bbc4bd6930345eef307 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:08:54 -0400 Subject: [PATCH 02/41] feat(TxController): Add StateReconcileMethod enum --- src/transaction/TransactionController.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index a7cd97bcb9..8ff2e6214c 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -117,6 +117,15 @@ export enum WalletDevice { OTHER = 'other_device', } +/** + * Source of data used to reconcile local transactions end state + */ +export enum StateReconcileMethod { + ETHERSCAN = 'etherscan', + BLOCKCHAIN = 'blockchain', + OTHER = 'other', +} + type TransactionMetaBase = { isTransfer?: boolean; transferInformation?: { From de7f56afe2cb39f3e435c4f8d46b880c58d004fd Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:09:49 -0400 Subject: [PATCH 03/41] feat(TxController): Add method to get outdated txs --- src/transaction/TransactionController.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 8ff2e6214c..2be5a701bf 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1265,7 +1265,22 @@ export class TransactionController extends BaseController< // private async transactionStateReconciler(remoteTxs: any, localTxs: any) {} - // private groupByNonce(transactions: Transaction[]) {} + /** + * Verifies if the status of a local transaction is outdated respect the remote transaction + * @param remoteTxHash - Remote transaction hash + * @param localTxHash - Local transaction hash + * @param remoteTxStatus - Remote transaction status + * @param localTxStatus - Local transaction status + * @returns boolean + */ + private isTransactionOutdated( + remoteTxHash: string | undefined, + localTxHash: string | undefined, + remoteTxStatus: TransactionStatus, + localTxStatus: TransactionStatus, + ): boolean { + return remoteTxHash === localTxHash && remoteTxStatus !== localTxStatus; + } } export default TransactionController; From 23f609677e0e9a5151e78206454a8fc87115b433 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:10:17 -0400 Subject: [PATCH 04/41] feat(TxController): Add method to get array of outdated txs --- src/transaction/TransactionController.ts | 25 +++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 2be5a701bf..596a54488d 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1263,7 +1263,30 @@ export class TransactionController extends BaseController< ); } - // private async transactionStateReconciler(remoteTxs: any, localTxs: any) {} + /** + * Get all the transactions that are locally outdated respect a + * remote source (etherscan or blockchain). The returned array + * contains the transactions with the updated data. + * @param remoteTxs - Array of transactions from remote source + * @param localTxs - Array of transactions stored locally + * @returns TransactionMeta array + */ + private getOutdatedTransactions( + remoteTxs: TransactionMeta[], + localTxs: TransactionMeta[], + ): TransactionMeta[] { + return remoteTxs.filter((tx) => { + const isTxOutdated = localTxs.find(({ transactionHash, status }) => { + return this.isTransactionOutdated( + transactionHash, + tx.transactionHash, + status, + tx.status, + ); + }); + return isTxOutdated; + }); + } /** * Verifies if the status of a local transaction is outdated respect the remote transaction From 3e5818cfe4286313c113f1d02bc1675c903c7d6c Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:10:54 -0400 Subject: [PATCH 05/41] feat(TxController): Add method to get array of new txs --- src/transaction/TransactionController.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 596a54488d..d5978072ce 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1263,6 +1263,25 @@ export class TransactionController extends BaseController< ); } + /** + * Get all transactions that are in the remote transactions array + * but not in the local transactions array + * @param remoteTxs - Array of transactions from remote source + * @param localTxs - Array of transactions stored locally + * @returns TransactionMeta array + */ + private getNewTransactions( + remoteTxs: TransactionMeta[], + localTxs: TransactionMeta[], + ): TransactionMeta[] { + return remoteTxs.filter((tx) => { + const alreadyInTransactions = localTxs.find( + ({ transactionHash }) => transactionHash === tx.transactionHash, + ); + return !alreadyInTransactions; + }); + } + /** * Get all the transactions that are locally outdated respect a * remote source (etherscan or blockchain). The returned array From 376a97217fff62e72f0ed115c7939d317c05cad7 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:11:56 -0400 Subject: [PATCH 06/41] feat(TxController): Add method to reconcile txs from etherscan --- src/transaction/TransactionController.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index d5978072ce..346a6a6979 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1263,6 +1263,22 @@ export class TransactionController extends BaseController< ); } + private etherscanTransactionStateReconciler( + remoteTxs: TransactionMeta[], + localTxs: TransactionMeta[], + ): TransactionMeta[] { + const outdatedTxs = this.getOutdatedTransactions(remoteTxs, localTxs); + const newTxs = this.getNewTransactions(remoteTxs, localTxs); + + const updatedLocalTxs = localTxs.map((tx: TransactionMeta) => { + const txIdx = outdatedTxs.findIndex( + ({ transactionHash }) => transactionHash === tx.transactionHash, + ); + return txIdx === -1 ? tx : outdatedTxs[txIdx]; + }); + + return [...newTxs, ...updatedLocalTxs]; + } /** * Get all transactions that are in the remote transactions array * but not in the local transactions array From 2e3199cd79e5829e7c8bbee9f50e7b3fda21f18d Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:12:18 -0400 Subject: [PATCH 07/41] feat(TxController): Add method to reconcile txs --- src/transaction/TransactionController.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 346a6a6979..75b9ca5203 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1263,6 +1263,30 @@ export class TransactionController extends BaseController< ); } + /** + * Resolves the locally stored transactions with the blockchain or etherscan. Then updated TransactionController State + * @param remoteTxs - Array of transactions fetched from etherscan, the blockchain or other source + * @param localTxs - Array of transactions currently stored in the state of the controller + * @param stateReconcileMethod - Strategy used to reconcile the transactions + * @returns void + */ + private transactionStateReconciler( + remoteTxs: TransactionMeta[], + localTxs: TransactionMeta[], + stateReconcileMethod: StateReconcileMethod, + ): TransactionMeta[] { + switch (stateReconcileMethod) { + case StateReconcileMethod.ETHERSCAN: + return this.etherscanTransactionStateReconciler(remoteTxs, localTxs); + case StateReconcileMethod.BLOCKCHAIN: + return []; + case StateReconcileMethod.OTHER: + return []; + default: + return []; + } + } + private etherscanTransactionStateReconciler( remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], From 0af90be8a9db6dcad0b62db78a594b8d79a57f1a Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 2 Sep 2021 13:14:01 -0400 Subject: [PATCH 08/41] feat(TxController): Add reconcile method to etherscan fetch --- src/transaction/TransactionController.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 75b9ca5203..7638b6513c 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1157,12 +1157,11 @@ export class TransactionController extends BaseController< this.normalizeTokenTx(tx, currentNetworkID, currentChainId), ); - const remoteTxs = [...normalizedTxs, ...normalizedTokenTxs].filter((tx) => { - const alreadyInTransactions = this.state.transactions.find( - ({ transactionHash }) => transactionHash === tx.transactionHash, + const allTxs = this.transactionStateReconciler( + [...normalizedTxs, ...normalizedTokenTxs], + this.state.transactions, + StateReconcileMethod.ETHERSCAN, ); - return !alreadyInTransactions; - }); const allTxs = [...remoteTxs, ...this.state.transactions]; allTxs.sort((a, b) => (a.time < b.time ? -1 : 1)); From b9e7992142dbbea1798339986a2f7d6dfc2c775d Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:41:56 -0300 Subject: [PATCH 09/41] test(TransactionController): Unify mocks in a single file --- src/transaction/mocks/mockEthTxs.ts | 77 ----------------- .../mocks/{mockTokenTxs.ts => txsMock.ts} | 82 ++++++++++++++++++- 2 files changed, 80 insertions(+), 79 deletions(-) delete mode 100644 src/transaction/mocks/mockEthTxs.ts rename src/transaction/mocks/{mockTokenTxs.ts => txsMock.ts} (80%) diff --git a/src/transaction/mocks/mockEthTxs.ts b/src/transaction/mocks/mockEthTxs.ts deleted file mode 100644 index 948ae395cf..0000000000 --- a/src/transaction/mocks/mockEthTxs.ts +++ /dev/null @@ -1,77 +0,0 @@ -export const mockEthTxs = (etherTxHash: string) => [ - { - blockNumber: '4535101', - confirmations: '10', - contractAddress: '', - cumulativeGasUsed: '120607', - from: '0xe46abaf75cfbff815c0b7ffed6f02b0760ea27f1', - gas: '335208', - gasPrice: '10000000000', - gasUsed: '21000', - hash: etherTxHash, - input: '0x', - isError: '0', - nonce: '9', - timeStamp: '1543596286', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - transactionIndex: '2', - txreceipt_status: '1', - value: '100000000000000000', - }, - { - blockNumber: '4535108', - confirmations: '3', - contractAddress: '', - cumulativeGasUsed: '693910', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - gas: '335208', - gasPrice: '20000000000', - gasUsed: '21000', - hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff92', - input: '0x', - isError: '0', - nonce: '0', - timeStamp: '1543596378', - to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', - transactionIndex: '12', - txreceipt_status: '1', - value: '50000000000000000', - }, - { - blockNumber: '4535105', - confirmations: '4', - contractAddress: '', - cumulativeGasUsed: '693910', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - gas: '335208', - gasPrice: '20000000000', - gasUsed: '21000', - hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff91', - input: '0x', - isError: '0', - nonce: '1', - timeStamp: '1543596356', - transactionIndex: '13', - txreceipt_status: '1', - value: '50000000000000000', - }, - { - blockNumber: '4535106', - confirmations: '4', - contractAddress: '', - cumulativeGasUsed: '693910', - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - gas: '335208', - gasPrice: '20000000000', - gasUsed: '21000', - hash: '0x342e9d73e10004af41d04973139fc7219dbadcbb5629730cfe65e9f9cb15ff91', - input: '0x11', - isError: '0', - nonce: '3', - timeStamp: '1543596356', - to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', - transactionIndex: '13', - txreceipt_status: '1', - value: '50000000000000000', - }, -]; diff --git a/src/transaction/mocks/mockTokenTxs.ts b/src/transaction/mocks/txsMock.ts similarity index 80% rename from src/transaction/mocks/mockTokenTxs.ts rename to src/transaction/mocks/txsMock.ts index c0f794f880..a639ea8037 100644 --- a/src/transaction/mocks/mockTokenTxs.ts +++ b/src/transaction/mocks/txsMock.ts @@ -1,4 +1,82 @@ -export const mockTokenTxs = (tokenTxHash: string) => [ +export const ethTxsMock = (etherTxHash: string) => [ + { + blockNumber: '4535101', + confirmations: '10', + contractAddress: '', + cumulativeGasUsed: '120607', + from: '0xe46abaf75cfbff815c0b7ffed6f02b0760ea27f1', + gas: '335208', + gasPrice: '10000000000', + gasUsed: '21000', + hash: etherTxHash, + input: '0x', + isError: '0', + nonce: '9', + timeStamp: '1543596286', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + transactionIndex: '2', + txreceipt_status: '1', + value: '100000000000000000', + }, + { + blockNumber: '4535108', + confirmations: '3', + contractAddress: '', + cumulativeGasUsed: '693910', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + gas: '335208', + gasPrice: '20000000000', + gasUsed: '21000', + hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff92', + input: '0x', + isError: '0', + nonce: '0', + timeStamp: '1543596378', + to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', + transactionIndex: '12', + txreceipt_status: '1', + value: '50000000000000000', + }, + { + blockNumber: '4535105', + confirmations: '4', + contractAddress: '', + cumulativeGasUsed: '693910', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + gas: '335208', + gasPrice: '20000000000', + gasUsed: '21000', + hash: '0x342e9d73e10004af41d04973339fc7219dbadcbb5629730cfe65e9f9cb15ff91', + input: '0x', + isError: '0', + nonce: '1', + timeStamp: '1543596356', + transactionIndex: '13', + txreceipt_status: '1', + value: '50000000000000000', + }, + { + blockNumber: '4535106', + confirmations: '4', + contractAddress: '', + cumulativeGasUsed: '693910', + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + gas: '335208', + gasPrice: '20000000000', + gasUsed: '21000', + hash: '0x342e9d73e10004af41d04973139fc7219dbadcbb5629730cfe65e9f9cb15ff91', + input: '0x11', + isError: '0', + nonce: '3', + timeStamp: '1543596356', + to: '0xb2d191b6fe03c5b8a1ab249cfe88c37553357a23', + transactionIndex: '13', + txreceipt_status: '1', + value: '50000000000000000', + }, +]; + +export const tokenTxsMock = (tokenTxHash: string) => [ { blockNumber: '8222239', timeStamp: '1564091067', @@ -16,7 +94,7 @@ export const mockTokenTxs = (tokenTxHash: string) => [ transactionIndex: '69', gas: '624874', gasPrice: '20000000000', - gasUsed: '609874', + gasUsed: '21000', cumulativeGasUsed: '3203881', input: 'deprecated', confirmations: '3659676', From ef99cff3ac16701607f43e549b1ba15e55329623 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:42:53 -0300 Subject: [PATCH 10/41] Update brach to main --- CHANGELOG.md | 8 +++++++- src/assets/TokenListController.ts | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50df5c0298..4c9d9a2707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [15.0.2] +### Fixed +- Change AbortController to default import ([#579](https://github.com/MetaMask/controllers/pull/579)) + - Fix error thrown when polyfilled AbortController is instantiated as a named import. + ## [15.0.1] ### Fixed - Add AbortController polyfill ([#575](https://github.com/MetaMask/controllers/pull/575)) @@ -358,7 +363,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - Remove shapeshift controller (#209) -[Unreleased]: https://github.com/MetaMask/controllers/compare/v15.0.1...HEAD +[Unreleased]: https://github.com/MetaMask/controllers/compare/v15.0.2...HEAD +[15.0.2]: https://github.com/MetaMask/controllers/compare/v15.0.1...v15.0.2 [15.0.1]: https://github.com/MetaMask/controllers/compare/v15.0.0...v15.0.1 [15.0.0]: https://github.com/MetaMask/controllers/compare/v14.2.0...v15.0.0 [14.2.0]: https://github.com/MetaMask/controllers/compare/v14.1.0...v14.2.0 diff --git a/src/assets/TokenListController.ts b/src/assets/TokenListController.ts index e615145b08..a57bddf95d 100644 --- a/src/assets/TokenListController.ts +++ b/src/assets/TokenListController.ts @@ -1,7 +1,8 @@ import contractMap from '@metamask/contract-metadata'; import type { Patch } from 'immer'; import { Mutex } from 'async-mutex'; -import { AbortController } from 'abort-controller'; +// eslint-disable-next-line import/no-named-as-default +import AbortController from 'abort-controller'; import { BaseController } from '../BaseControllerV2'; import type { RestrictedControllerMessenger } from '../ControllerMessenger'; import { safelyExecute } from '../util'; From 3bc92030150b0a74a8e7f6ef31fea95a549ce946 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:44:02 -0300 Subject: [PATCH 11/41] feat(getEtherscanApiUrl): Modify method to construct any url --- src/util.ts | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/util.ts b/src/util.ts index db799e5db4..160f53b342 100644 --- a/src/util.ts +++ b/src/util.ts @@ -148,29 +148,26 @@ export function getBuyURL( * Return a URL that can be used to fetch ETH transactions * * @param networkType - Network type of desired network - * @param address - Address to get the transactions from - * @param fromBlock? - Block from which transactions are needed - * @returns - URL to fetch the transactions from + * @param urlParams - Parameters used to construct the URL + * @returns - URL to fetch the access the endpoint */ export function getEtherscanApiUrl( networkType: string, - address: string, - action: string, - fromBlock?: string, - etherscanApiKey?: string, + urlParams: any, ): string { let etherscanSubdomain = 'api'; if (networkType !== MAINNET) { etherscanSubdomain = `api-${networkType}`; } const apiUrl = `https://${etherscanSubdomain}.etherscan.io`; - let url = `${apiUrl}/api?module=account&action=${action}&address=${address}&tag=latest&page=1`; - if (fromBlock) { - url += `&startBlock=${fromBlock}`; + let url = `${apiUrl}/api?`; + + for (const paramKey in urlParams) { + if (urlParams[paramKey]) { + url += `${paramKey}=${urlParams[paramKey]}&`; } - if (etherscanApiKey) { - url += `&apikey=${etherscanApiKey}`; } + url += 'tag=latest&page=1'; return url; } From 2f53370c7c040f16c9edaf4777b945eceb08a42e Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:44:37 -0300 Subject: [PATCH 12/41] test(getEtherscanApiUrl): Update --- src/util.test.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/util.test.ts b/src/util.test.ts index c0a343a4a9..20ef68df35 100644 --- a/src/util.test.ts +++ b/src/util.test.ts @@ -330,33 +330,31 @@ describe('util', () => { const action = 'txlist'; it('should return a correctly structured url', () => { - const url = util.getEtherscanApiUrl(networkType, address, action); + const url = util.getEtherscanApiUrl(networkType, { address, action }); expect(url.indexOf(`&action=${action}`)).toBeGreaterThan(0); }); it('should return a correctly structured url with from block', () => { const fromBlock = 'xxxxxx'; - const url = util.getEtherscanApiUrl( - networkType, + const url = util.getEtherscanApiUrl(networkType, { address, action, - fromBlock, - ); + startBlock: fromBlock, + }); expect(url.indexOf(`&startBlock=${fromBlock}`)).toBeGreaterThan(0); }); it('should return a correctly structured url with testnet subdomain', () => { const ropsten = 'ropsten'; - const url = util.getEtherscanApiUrl(ropsten, address, action); + const url = util.getEtherscanApiUrl(ropsten, { address, action }); expect(url.indexOf(`https://api-${ropsten}`)).toBe(0); }); it('should return a correctly structured url with apiKey', () => { const apiKey = 'xxxxxx'; - const url = util.getEtherscanApiUrl( - networkType, + const url = util.getEtherscanApiUrl(networkType, { address, action, - 'xxxxxx', - apiKey, - ); + startBlock: 'xxxxxx', + apikey: apiKey, + }); expect(url.indexOf(`&apikey=${apiKey}`)).toBeGreaterThan(0); }); }); From 93e0561ca629e6f2454e9b34c5e5ceae8ef8d791 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:52:01 -0300 Subject: [PATCH 13/41] feat(TransactionController): Add EtherscanTransactionStatus --- src/transaction/TransactionController.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 7638b6513c..ff5f27ec63 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -75,6 +75,7 @@ export interface Transaction { from: string; gas?: string; gasPrice?: string; + gasUsed?: string; nonce?: string; to?: string; value?: string; @@ -108,6 +109,20 @@ export enum TransactionStatus { unapproved = 'unapproved', } +/** + * Status of a transaction according to Etherscan. + * According to the documentation: "The status field returns + * 0 for failed transactions and 1 for successful transactions" + * successful: 1 + * failed: 0 + * error: Indicates an error while fetching the data + */ +export enum EtherscanTransactionStatus { + successful = 'successful', + failed = 'failed', + error = 'error', +} + /** * Options for wallet device. */ @@ -325,6 +340,7 @@ export class TransactionController extends BaseController< from: txMeta.from, gas: BNToHex(new BN(txMeta.gas)), gasPrice: BNToHex(new BN(txMeta.gasPrice)), + gasUsed: BNToHex(new BN(txMeta.gasUsed)), nonce: BNToHex(new BN(txMeta.nonce)), to: txMeta.to, value: BNToHex(new BN(txMeta.value)), @@ -359,6 +375,7 @@ export class TransactionController extends BaseController< from, gas, gasPrice, + gasUsed, hash, contractAddress, tokenDecimal, @@ -377,6 +394,7 @@ export class TransactionController extends BaseController< from, gas, gasPrice, + gasUsed, to, value, }, From fff6ddcddb4bb11bc11e14cb0f0d52c15783519f Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:52:34 -0300 Subject: [PATCH 14/41] feat(TransactionController): Add new status for TransactionStatus --- src/transaction/TransactionController.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index ff5f27ec63..5aae1080b8 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -103,6 +103,7 @@ export enum TransactionStatus { cancelled = 'cancelled', confirmed = 'confirmed', failed = 'failed', + failedBeforeChain = 'failedBeforeChain', rejected = 'rejected', signed = 'signed', submitted = 'submitted', From 94508a2f3f5aecdd6cd8c850e13455156b035730 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:53:23 -0300 Subject: [PATCH 15/41] feat(TransactionController): Add new failed condition for blockchain queries --- src/transaction/TransactionController.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 5aae1080b8..db26454a7c 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1061,10 +1061,10 @@ export class TransactionController extends BaseController< meta.transactionHash, ]); - console.log( - 'Controller Log @ 1088 queryTransactionStatuses txObj', - txObj, - ); + if (txObj === null) { + transactions[index].status = TransactionStatus.failed; + gotUpdates = true; + } /* istanbul ignore next */ if (txObj?.blockNumber) { From 42c74c9c3aa1069ab65a78c39be35790708d25ef Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:55:50 -0300 Subject: [PATCH 16/41] feat(TransactionController): Get transaction from state --- src/transaction/TransactionController.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index db26454a7c..9e72613f57 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1146,6 +1146,7 @@ export class TransactionController extends BaseController< ): Promise { const { provider, network: currentNetworkID } = this.getNetworkState(); const { chainId: currentChainId, type: networkType } = provider; + const { transactions } = this.state; const supportedNetworkIds = ['1', '3', '4', '42']; /* istanbul ignore next */ From 389a027525841d674ed655e71db2c72d05c3a5d3 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:57:58 -0300 Subject: [PATCH 17/41] feat(TransactionController): Update transactionStateReconciler method --- src/transaction/TransactionController.ts | 34 ++++++------------------ 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 9e72613f57..d3551caaa1 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1177,13 +1177,12 @@ export class TransactionController extends BaseController< this.normalizeTokenTx(tx, currentNetworkID, currentChainId), ); - const allTxs = this.transactionStateReconciler( + const [updateTxs, allTxs] = this.transactionStateReconciler( [...normalizedTxs, ...normalizedTokenTxs], - this.state.transactions, + transactions, StateReconcileMethod.ETHERSCAN, ); - const allTxs = [...remoteTxs, ...this.state.transactions]; allTxs.sort((a, b) => (a.time < b.time ? -1 : 1)); let latestIncomingTxBlockNumber: string | undefined; @@ -1221,8 +1220,9 @@ export class TransactionController extends BaseController< } } }); - // Update state only if new transactions were fetched - if (allTxs.length > this.state.transactions.length) { + // Update state only if new transactions were fetched or + // the status of a transaction has changed + if (updateTxs) { this.update({ transactions: this.trimTransactionsForState(allTxs) }); } console.log( @@ -1268,41 +1268,23 @@ export class TransactionController extends BaseController< return txsToKeep; } - /** - * Function to determine if the transaction is in a final state - * @param status - Transaction status - * @returns boolean if the transaction is in a final state - */ - private isFinalState(status: TransactionStatus) { - return ( - status === TransactionStatus.rejected || - status === TransactionStatus.confirmed || - status === TransactionStatus.failed || - status === TransactionStatus.cancelled - ); - } - /** * Resolves the locally stored transactions with the blockchain or etherscan. Then updated TransactionController State * @param remoteTxs - Array of transactions fetched from etherscan, the blockchain or other source * @param localTxs - Array of transactions currently stored in the state of the controller * @param stateReconcileMethod - Strategy used to reconcile the transactions - * @returns void + * @returns [boolean, TransactionMeta[]] */ private transactionStateReconciler( remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], stateReconcileMethod: StateReconcileMethod, - ): TransactionMeta[] { + ): [boolean, TransactionMeta[]] { switch (stateReconcileMethod) { case StateReconcileMethod.ETHERSCAN: return this.etherscanTransactionStateReconciler(remoteTxs, localTxs); - case StateReconcileMethod.BLOCKCHAIN: - return []; - case StateReconcileMethod.OTHER: - return []; default: - return []; + return [false, []]; } } From d70848e77144cff21fd37ef1430b5ab2a286ec9c Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:58:36 -0300 Subject: [PATCH 18/41] feat(TransactionController): Update etherscanTransactionStateReconciler method --- src/transaction/TransactionController.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index d3551caaa1..95a65400e0 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1291,9 +1291,16 @@ export class TransactionController extends BaseController< private etherscanTransactionStateReconciler( remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], - ): TransactionMeta[] { - const outdatedTxs = this.getOutdatedTransactions(remoteTxs, localTxs); - const newTxs = this.getNewTransactions(remoteTxs, localTxs); + ): [boolean, TransactionMeta[]] { + const outdatedTxs: TransactionMeta[] = this.getOutdatedTransactions( + remoteTxs, + localTxs, + ); + + const newTxs: TransactionMeta[] = this.getNewTransactions( + remoteTxs, + localTxs, + ); const updatedLocalTxs = localTxs.map((tx: TransactionMeta) => { const txIdx = outdatedTxs.findIndex( @@ -1302,8 +1309,11 @@ export class TransactionController extends BaseController< return txIdx === -1 ? tx : outdatedTxs[txIdx]; }); - return [...newTxs, ...updatedLocalTxs]; + const update = newTxs.length > 0 || updatedLocalTxs.length > 0; + + return [update, [...newTxs, ...updatedLocalTxs]]; } + /** * Get all transactions that are in the remote transactions array * but not in the local transactions array From cc5848e4a16700823c0d28335e9b056fcde33b00 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:58:57 -0300 Subject: [PATCH 19/41] feat(TransactionController): Update getOutdatedTransactions method --- src/transaction/TransactionController.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 95a65400e0..1e18e45053 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1345,13 +1345,11 @@ export class TransactionController extends BaseController< remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], ): TransactionMeta[] { - return remoteTxs.filter((tx) => { - const isTxOutdated = localTxs.find(({ transactionHash, status }) => { - return this.isTransactionOutdated( - transactionHash, - tx.transactionHash, - status, - tx.status, + return remoteTxs.filter((remoteTx) => { + const isTxOutdated = localTxs.find((localTx) => { + return ( + remoteTx.transactionHash === localTx.transactionHash && + this.isTransactionOutdated(remoteTx, localTx) ); }); return isTxOutdated; From 73236300a272cec565849ae0f3425886e49d854b Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:59:14 -0300 Subject: [PATCH 20/41] feat(TransactionController): Add isTransactionOutdated method --- src/transaction/TransactionController.ts | 26 +++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 1e18e45053..8e4e82b894 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1357,7 +1357,31 @@ export class TransactionController extends BaseController< } /** - * Verifies if the status of a local transaction is outdated respect the remote transaction + * Verifies if a local transaction is outdated in respect the remote transaction + * @param remoteTx - Remote transaction from Etherscan + * @param localTx - Local transaction + * @returns boolean + */ + private isTransactionOutdated( + remoteTx: TransactionMeta, + localTx: TransactionMeta, + ): boolean { + const statusOutdated = this.isStatusOutdated( + remoteTx.transactionHash, + localTx.transactionHash, + remoteTx.status, + localTx.status, + ); + const gasDataOutdated = this.isGasDataOutdated( + remoteTx.transaction.gas, + remoteTx.transaction.gasPrice, + remoteTx.transaction.gasUsed, + localTx.transaction.gas, + localTx.transaction.gasPrice, + localTx.transaction.gasUsed, + ); + return statusOutdated || gasDataOutdated; + } * @param remoteTxHash - Remote transaction hash * @param localTxHash - Local transaction hash * @param remoteTxStatus - Remote transaction status From 3c054c94161dab5963af9b4f5992f663a0aca7b6 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Mon, 6 Sep 2021 23:59:39 -0300 Subject: [PATCH 21/41] feat(TransactionController): Update isStatusOutdated method --- src/transaction/TransactionController.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 8e4e82b894..53d11b1537 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1382,13 +1382,16 @@ export class TransactionController extends BaseController< ); return statusOutdated || gasDataOutdated; } + + /** + * Verifies if the status of a local transaction is outdated in respect the remote transaction * @param remoteTxHash - Remote transaction hash * @param localTxHash - Local transaction hash * @param remoteTxStatus - Remote transaction status * @param localTxStatus - Local transaction status * @returns boolean */ - private isTransactionOutdated( + private isStatusOutdated( remoteTxHash: string | undefined, localTxHash: string | undefined, remoteTxStatus: TransactionStatus, From 053e9ecd9857d2cc6bc2b69db091a3bec905281d Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:00:05 -0300 Subject: [PATCH 22/41] feat(TransactionController): Add isGasDataOutdated method --- src/transaction/TransactionController.ts | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 53d11b1537..52191b2708 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1399,6 +1399,31 @@ export class TransactionController extends BaseController< ): boolean { return remoteTxHash === localTxHash && remoteTxStatus !== localTxStatus; } + + /** + * Verifies if the gas data of a local transaction is outdated in respect the remote transaction + * @param remoteGas - Remote gas + * @param remoteGasPrice - Remote gas price + * @param remoteGasUsed - Remote gas used in the transaction + * @param localGas - Local gas + * @param localGasPrice - Local gas price + * @param localGasUsed - Local gas used in the transaction + * @returns boolean + */ + private isGasDataOutdated( + remoteGas: string | undefined, + remoteGasPrice: string | undefined, + remoteGasUsed: string | undefined, + localGas: string | undefined, + localGasPrice: string | undefined, + localGasUsed: string | undefined, + ): boolean { + return ( + remoteGas !== localGas || + remoteGasPrice !== localGasPrice || + remoteGasUsed !== localGasUsed + ); + } } export default TransactionController; From 146f26a4b095942a58fd8d9c3d157e10f3cb9baf Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:00:26 -0300 Subject: [PATCH 23/41] feat(TransactionController): Update trimTransactionsForState method --- src/transaction/TransactionController.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 52191b2708..ff4c6d5b76 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1243,8 +1243,11 @@ export class TransactionController extends BaseController< * nonce, same day and network combo can result in confusing or broken experiences * in the UI. The transactions are then updated using the BaseController update. * @param transactions - arrray of transactions to be applied to the state + * @returns Array of TransactionMeta with the desired length. */ - private trimTransactionsForState(transactions: TransactionMeta[]) { + private trimTransactionsForState( + transactions: TransactionMeta[], + ): TransactionMeta[] { const nonceNetworkSet = new Set(); const txsToKeep = transactions.reverse().filter((tx) => { const { chainId, networkID, status, transaction, time } = tx; From f00d46f2f84decd41c14f8655fb05d89524b42e3 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:01:10 -0300 Subject: [PATCH 24/41] feat(TransactionController): Relocate isFinalState method --- src/transaction/TransactionController.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index ff4c6d5b76..ba1157867c 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1291,6 +1291,20 @@ export class TransactionController extends BaseController< } } + /** + * Function to determine if the transaction is in a final state + * @param status - Transaction status + * @returns boolean if the transaction is in a final state + */ + private isFinalState(status: TransactionStatus): boolean { + return ( + status === TransactionStatus.rejected || + status === TransactionStatus.confirmed || + status === TransactionStatus.failed || + status === TransactionStatus.cancelled + ); + } + private etherscanTransactionStateReconciler( remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], From eeea0f28dc38ccb6c7f9796d1465e184057408e2 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:02:52 -0300 Subject: [PATCH 25/41] feat(handletransationStatusFetch): Add method to check tx status in etherscan --- src/util.ts | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/util.ts b/src/util.ts index 160f53b342..78e176a178 100644 --- a/src/util.ts +++ b/src/util.ts @@ -17,6 +17,7 @@ import { FetchAllOptions, GasPriceValue, FeeMarketEIP1559Values, + EtherscanTransactionStatus, } from './transaction/TransactionController'; import { MessageParams } from './message-manager/MessageManager'; import { PersonalMessageParams } from './message-manager/PersonalMessageManager'; @@ -226,6 +227,44 @@ export async function handleTransactionFetch( return [etherscanTxResponse, etherscanTokenResponse]; } +/** + * Method to fetch tHe status of a single transaction in Etherscan, + * from the Etherscan docs: "The status field returns 0 for failed transactions + * and 1 for successful transactions." + * @param networkType - Network type of desired network + * @param transactionHash - Hash of the required transaction + * @param opt? - Object that can contain fromBlock and Etherscan service API key + * @returns Promise with the status of the transaction + */ +export async function handletransationStatusFetch( + networkType: string, + transactionHash: string, + opt?: FetchAllOptions, +): Promise { + const urlParams = { + module: 'transaction', + action: 'gettxreceiptstatus', + txhash: transactionHash, + apikey: opt?.etherscanApiKey, + }; + const etherscanTxUrl = getEtherscanApiUrl(networkType, urlParams); + + try { + const response = await handleFetch(etherscanTxUrl); + const { status, result } = response; + + if (status === '0') { + return EtherscanTransactionStatus.error; + } + + return result.status === '1' + ? EtherscanTransactionStatus.successful + : EtherscanTransactionStatus.failed; + } catch (e) { + return EtherscanTransactionStatus.error; + } +} + /** * Converts a hex string to a BN object * From 9b8e3ef15f6809df28c6bfee31fd130a6eeab28a Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:03:26 -0300 Subject: [PATCH 26/41] feat(handleTransactionFetch): Update method --- src/util.ts | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/util.ts b/src/util.ts index 78e176a178..94c2e0847b 100644 --- a/src/util.ts +++ b/src/util.ts @@ -184,25 +184,25 @@ export async function handleTransactionFetch( networkType: string, address: string, opt?: FetchAllOptions, -): Promise<[{ [result: string]: [] }, { [result: string]: [] }]> { +): Promise { // transactions - const etherscanTxUrl = getEtherscanApiUrl( - networkType, + const urlParams = { + module: 'account', address, - 'txlist', - opt?.fromBlock, - opt?.etherscanApiKey, - ); + startBlock: opt?.fromBlock, + apikey: opt?.etherscanApiKey, + }; + const etherscanTxUrl = getEtherscanApiUrl(networkType, { + ...urlParams, + action: 'txlist', + }); const etherscanTxResponsePromise = handleFetch(etherscanTxUrl); // tokens - const etherscanTokenUrl = getEtherscanApiUrl( - networkType, - address, - 'tokentx', - opt?.fromBlock, - opt?.etherscanApiKey, - ); + const etherscanTokenUrl = getEtherscanApiUrl(networkType, { + ...urlParams, + action: 'tokentx', + }); const etherscanTokenResponsePromise = handleFetch(etherscanTokenUrl); let [etherscanTxResponse, etherscanTokenResponse] = await Promise.all([ @@ -214,14 +214,17 @@ export async function handleTransactionFetch( etherscanTxResponse.status === '0' || etherscanTxResponse.result.length <= 0 ) { - etherscanTxResponse = { result: [] }; + etherscanTxResponse = { status: etherscanTxResponse.status, result: [] }; } if ( etherscanTokenResponse.status === '0' || etherscanTokenResponse.result.length <= 0 ) { - etherscanTokenResponse = { result: [] }; + etherscanTokenResponse = { + status: etherscanTokenResponse.status, + result: [], + }; } return [etherscanTxResponse, etherscanTokenResponse]; From 5b9a7aa2267a044d5ba76e93f4743670beae7232 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:04:10 -0300 Subject: [PATCH 27/41] style(util): Indentation --- src/util.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.ts b/src/util.ts index 94c2e0847b..2e9b73ed37 100644 --- a/src/util.ts +++ b/src/util.ts @@ -166,7 +166,7 @@ export function getEtherscanApiUrl( for (const paramKey in urlParams) { if (urlParams[paramKey]) { url += `${paramKey}=${urlParams[paramKey]}&`; - } + } } url += 'tag=latest&page=1'; return url; From 31b19ce90a49df9cf558eebdd3a610ff634b7694 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Tue, 7 Sep 2021 00:04:40 -0300 Subject: [PATCH 28/41] test(TransactionController): Update --- src/transaction/TransactionController.test.ts | 160 ++++++++++++++++-- 1 file changed, 143 insertions(+), 17 deletions(-) diff --git a/src/transaction/TransactionController.test.ts b/src/transaction/TransactionController.test.ts index eba01c0a10..c1bc471d29 100644 --- a/src/transaction/TransactionController.test.ts +++ b/src/transaction/TransactionController.test.ts @@ -10,8 +10,7 @@ import { TransactionStatus, TransactionMeta, } from './TransactionController'; -import { mockEthTxs } from './mocks/mockEthTxs'; -import { mockTokenTxs } from './mocks/mockTokenTxs'; +import { ethTxsMock, tokenTxsMock } from './mocks/txsMock'; const globalAny: any = global; @@ -144,9 +143,9 @@ const TOKEN_TRANSACTION_HASH = const ETHER_TRANSACTION_HASH = '0xa9d17df83756011ea63e1f0ca50a6627df7cac9806809e36680fcf4e88cb9dae'; -const ETH_TRANSACTIONS = mockEthTxs(ETHER_TRANSACTION_HASH); +const ETH_TRANSACTIONS = ethTxsMock(ETHER_TRANSACTION_HASH); -const TOKEN_TRANSACTIONS = mockTokenTxs(TOKEN_TRANSACTION_HASH); +const TOKEN_TRANSACTIONS = tokenTxsMock(TOKEN_TRANSACTION_HASH); const TRANSACTIONS_IN_STATE: TransactionMeta[] = [ // Token tx, hash is in TOKEN_TRANSACTIONS @@ -158,8 +157,9 @@ const TRANSACTIONS_IN_STATE: TransactionMeta[] = [ transaction: { from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', data: '0x', - gas: '0x6f4d2', - gasPrice: '0x2b12dbfa00', + gas: '624874', + gasPrice: '20000000000', + gasUsed: '21000', nonce: '0x12', to: '0x881d40237659c251811cec9c364ef91dc08d300c', value: '0x0', @@ -176,8 +176,87 @@ const TRANSACTIONS_IN_STATE: TransactionMeta[] = [ transaction: { from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', data: '0x', - gas: '0x6f4d2', - gasPrice: '0x2b12dbfa00', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: '0x5208', + nonce: '0x12', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + }, + transactionHash: ETHER_TRANSACTION_HASH, + toSmartContract: false, + }, +]; + +const TRANSACTIONS_IN_STATE_WITH_OUTDATED_STATUS: TransactionMeta[] = [ + { + id: 'token-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '624874', + gasPrice: '20000000000', + gasUsed: '21000', + nonce: '0x12', + to: '0x881d40237659c251811cec9c364ef91dc08d300c', + value: '0x0', + }, + transactionHash: TOKEN_TRANSACTION_HASH, + toSmartContract: true, + }, + { + id: 'eth-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: '0x5208', + nonce: '0x12', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + }, + transactionHash: ETHER_TRANSACTION_HASH, + toSmartContract: false, + }, +]; + +const TRANSACTIONS_IN_STATE_WITH_OUTDATED_GAS_DATA: TransactionMeta[] = [ + { + id: 'token-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '624874', + gasPrice: '20000000000', + gasUsed: undefined, + nonce: '0x12', + to: '0x881d40237659c251811cec9c364ef91dc08d300c', + value: '0x0', + }, + transactionHash: TOKEN_TRANSACTION_HASH, + toSmartContract: true, + }, + { + id: 'eth-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: undefined, nonce: '0x12', to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', value: '100000000000000000', @@ -218,12 +297,12 @@ const ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND = { }; const MOCK_FETCH_TX_HISTORY_DATA_OK = { - 'https://api-ropsten.etherscan.io/api?module=account&action=tokentx&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, - 'https://api.etherscan.io/api?module=account&action=tokentx&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, - 'https://api.etherscan.io/api?module=account&action=tokentx&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&tag=latest&page=1&startBlock=999': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, - 'https://api.etherscan.io/api?module=account&action=txlist&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api-ropsten.etherscan.io/api?module=account&action=txlist&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api.etherscan.io/api?module=account&action=txlist&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&tag=latest&page=1&startBlock=999': ETH_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, // check + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, // check + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA_FROM_BLOCK, }; const MOCK_FETCH_TX_HISTORY_DATA_ERROR = { @@ -751,7 +830,7 @@ describe('TransactionController', () => { expect(controller.state.transactions[0].transaction.to).toBe(from); }); - it('should fetch all the transactions from an address, including incoming token transactions, but not adding the ones already in state', async () => { + it('should fetch all the transactions from an address, including incoming token transactions without modifying transaction that have the same data in local and remote', async () => { globalAny.fetch = mockFetchs(MOCK_FETCH_TX_HISTORY_DATA_OK); const controller = new TransactionController({ getNetworkState: () => MOCK_MAINNET_NETWORK.state, @@ -772,7 +851,6 @@ describe('TransactionController', () => { expect(tokenTransaction?.id).toStrictEqual('token-transaction-id'); expect(ethTransaction?.id).toStrictEqual('eth-transaction-id'); }); - it('should fetch all the transactions from an address, including incoming transactions, in mainnet from block', async () => { globalAny.fetch = mockFetchs(MOCK_FETCH_TX_HISTORY_DATA_OK); const controller = new TransactionController({ @@ -789,7 +867,56 @@ describe('TransactionController', () => { expect(latestBlock).toBe('4535101'); expect(controller.state.transactions[0].transaction.to).toBe(from); }); + it('should fetch and updated all transactions with outdated status regarding the data provided by the remote source in mainnet', async () => { + globalAny.fetch = mockFetchs(MOCK_FETCH_TX_HISTORY_DATA_OK); + const controller = new TransactionController({ + getNetworkState: () => MOCK_MAINNET_NETWORK.state, + onNetworkStateChange: MOCK_MAINNET_NETWORK.subscribe, + getProvider: MOCK_MAINNET_NETWORK.getProvider, + }); + const from = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207'; + controller.wipeTransactions(); + expect(controller.state.transactions).toHaveLength(0); + + controller.state.transactions = TRANSACTIONS_IN_STATE_WITH_OUTDATED_STATUS; + + await controller.fetchAll(from); + expect(controller.state.transactions).toHaveLength(17); + const tokenTransaction = controller.state.transactions.find( + ({ transactionHash }) => transactionHash === TOKEN_TRANSACTION_HASH, + ) || { status: TransactionStatus.failed }; + const ethTransaction = controller.state.transactions.find( + ({ transactionHash }) => transactionHash === ETHER_TRANSACTION_HASH, + ) || { status: TransactionStatus.failed }; + expect(tokenTransaction?.status).toStrictEqual(TransactionStatus.confirmed); + expect(ethTransaction?.status).toStrictEqual(TransactionStatus.confirmed); + }); + it('should fetch and updated all transactions with outdated gas data regarding the data provided by the remote source in mainnet', async () => { + globalAny.fetch = mockFetchs(MOCK_FETCH_TX_HISTORY_DATA_OK); + const controller = new TransactionController({ + getNetworkState: () => MOCK_MAINNET_NETWORK.state, + onNetworkStateChange: MOCK_MAINNET_NETWORK.subscribe, + getProvider: MOCK_MAINNET_NETWORK.getProvider, + }); + const from = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207'; + controller.wipeTransactions(); + expect(controller.state.transactions).toHaveLength(0); + + controller.state.transactions = TRANSACTIONS_IN_STATE_WITH_OUTDATED_GAS_DATA; + + await controller.fetchAll(from); + expect(controller.state.transactions).toHaveLength(17); + + const tokenTransaction = controller.state.transactions.find( + ({ transactionHash }) => transactionHash === TOKEN_TRANSACTION_HASH, + ) || { transaction: { gasUsed: '0' } }; + const ethTransaction = controller.state.transactions.find( + ({ transactionHash }) => transactionHash === ETHER_TRANSACTION_HASH, + ) || { transaction: { gasUsed: '0x0' } }; + expect(tokenTransaction?.transaction.gasUsed).toStrictEqual('21000'); + expect(ethTransaction?.transaction.gasUsed).toStrictEqual('0x5208'); + }); it('should return', async () => { globalAny.fetch = mockFetch(MOCK_FETCH_TX_HISTORY_DATA_ERROR); const controller = new TransactionController({ @@ -938,7 +1065,6 @@ describe('TransactionController', () => { expect(controller.state.transactions[0].transaction.gasPrice).toBe( '0x4a817c800', ); - console.log(controller.state.transactions); resolve(''); }); }); From 07a951cbd7e31924649ad6b2133d43ab1329001b Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 10:56:18 -0300 Subject: [PATCH 29/41] test(TransactionController): Update mocks --- src/transaction/TransactionController.test.ts | 144 +++--------------- src/transaction/mocks/txsMock.ts | 132 +++++++++++++++- 2 files changed, 153 insertions(+), 123 deletions(-) diff --git a/src/transaction/TransactionController.test.ts b/src/transaction/TransactionController.test.ts index c1bc471d29..1859633e79 100644 --- a/src/transaction/TransactionController.test.ts +++ b/src/transaction/TransactionController.test.ts @@ -10,7 +10,13 @@ import { TransactionStatus, TransactionMeta, } from './TransactionController'; -import { ethTxsMock, tokenTxsMock } from './mocks/txsMock'; +import { + ethTxsMock, + tokenTxsMock, + txsInStateMock, + txsInStateWithOutdatedStatusMock, + txsInStateWithOutdatedGasDataMock, +} from './mocks/txsMock'; const globalAny: any = global; @@ -147,124 +153,20 @@ const ETH_TRANSACTIONS = ethTxsMock(ETHER_TRANSACTION_HASH); const TOKEN_TRANSACTIONS = tokenTxsMock(TOKEN_TRANSACTION_HASH); -const TRANSACTIONS_IN_STATE: TransactionMeta[] = [ - // Token tx, hash is in TOKEN_TRANSACTIONS - { - id: 'token-transaction-id', - chainId: '1', - status: TransactionStatus.confirmed, - time: 1615497996125, - transaction: { - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - data: '0x', - gas: '624874', - gasPrice: '20000000000', - gasUsed: '21000', - nonce: '0x12', - to: '0x881d40237659c251811cec9c364ef91dc08d300c', - value: '0x0', - }, - transactionHash: TOKEN_TRANSACTION_HASH, - toSmartContract: true, - }, - // ETH tx, hash is in ETH_TRANSACTIONS - { - id: 'eth-transaction-id', - chainId: '1', - status: TransactionStatus.confirmed, - time: 1615497996125, - transaction: { - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - data: '0x', - gas: '0x51d68', - gasPrice: '0x2540be400', - gasUsed: '0x5208', - nonce: '0x12', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '100000000000000000', - }, - transactionHash: ETHER_TRANSACTION_HASH, - toSmartContract: false, - }, -]; - -const TRANSACTIONS_IN_STATE_WITH_OUTDATED_STATUS: TransactionMeta[] = [ - { - id: 'token-transaction-id', - chainId: '1', - status: TransactionStatus.failedBeforeChain, - time: 1615497996125, - transaction: { - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - data: '0x', - gas: '624874', - gasPrice: '20000000000', - gasUsed: '21000', - nonce: '0x12', - to: '0x881d40237659c251811cec9c364ef91dc08d300c', - value: '0x0', - }, - transactionHash: TOKEN_TRANSACTION_HASH, - toSmartContract: true, - }, - { - id: 'eth-transaction-id', - chainId: '1', - status: TransactionStatus.failedBeforeChain, - time: 1615497996125, - transaction: { - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - data: '0x', - gas: '0x51d68', - gasPrice: '0x2540be400', - gasUsed: '0x5208', - nonce: '0x12', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '100000000000000000', - }, - transactionHash: ETHER_TRANSACTION_HASH, - toSmartContract: false, - }, -]; - -const TRANSACTIONS_IN_STATE_WITH_OUTDATED_GAS_DATA: TransactionMeta[] = [ - { - id: 'token-transaction-id', - chainId: '1', - status: TransactionStatus.failedBeforeChain, - time: 1615497996125, - transaction: { - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - data: '0x', - gas: '624874', - gasPrice: '20000000000', - gasUsed: undefined, - nonce: '0x12', - to: '0x881d40237659c251811cec9c364ef91dc08d300c', - value: '0x0', - }, - transactionHash: TOKEN_TRANSACTION_HASH, - toSmartContract: true, - }, - { - id: 'eth-transaction-id', - chainId: '1', - status: TransactionStatus.failedBeforeChain, - time: 1615497996125, - transaction: { - from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - data: '0x', - gas: '0x51d68', - gasPrice: '0x2540be400', - gasUsed: undefined, - nonce: '0x12', - to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', - value: '100000000000000000', - }, - transactionHash: ETHER_TRANSACTION_HASH, - toSmartContract: false, - }, -]; +const TRANSACTIONS_IN_STATE: TransactionMeta[] = txsInStateMock( + ETHER_TRANSACTION_HASH, + TOKEN_TRANSACTION_HASH, +); + +const TRANSACTIONS_IN_STATE_WITH_OUTDATED_STATUS: TransactionMeta[] = txsInStateWithOutdatedStatusMock( + ETHER_TRANSACTION_HASH, + TOKEN_TRANSACTION_HASH, +); + +const TRANSACTIONS_IN_STATE_WITH_OUTDATED_GAS_DATA: TransactionMeta[] = txsInStateWithOutdatedGasDataMock( + ETHER_TRANSACTION_HASH, + TOKEN_TRANSACTION_HASH, +); const ETH_TX_HISTORY_DATA = { message: 'OK', @@ -297,11 +199,11 @@ const ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND = { }; const MOCK_FETCH_TX_HISTORY_DATA_OK = { - 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, // check + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, // check + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA_FROM_BLOCK, }; diff --git a/src/transaction/mocks/txsMock.ts b/src/transaction/mocks/txsMock.ts index a639ea8037..6034154848 100644 --- a/src/transaction/mocks/txsMock.ts +++ b/src/transaction/mocks/txsMock.ts @@ -1,4 +1,6 @@ -export const ethTxsMock = (etherTxHash: string) => [ +import { TransactionMeta, TransactionStatus } from '../TransactionController'; + +export const ethTxsMock = (ethTxHash: string) => [ { blockNumber: '4535101', confirmations: '10', @@ -8,7 +10,7 @@ export const ethTxsMock = (etherTxHash: string) => [ gas: '335208', gasPrice: '10000000000', gasUsed: '21000', - hash: etherTxHash, + hash: ethTxHash, input: '0x', isError: '0', nonce: '9', @@ -364,3 +366,129 @@ export const tokenTxsMock = (tokenTxHash: string) => [ confirmations: '1004018', }, ]; + +export const txsInStateMock = ( + ethTxHash: string, + tokenTxHash: string, +): TransactionMeta[] => [ + { + id: 'token-transaction-id', + chainId: '1', + status: TransactionStatus.confirmed, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '624874', + gasPrice: '20000000000', + gasUsed: '21000', + nonce: '0x12', + to: '0x881d40237659c251811cec9c364ef91dc08d300c', + value: '0x0', + }, + transactionHash: tokenTxHash, + toSmartContract: true, + }, + { + id: 'eth-transaction-id', + chainId: '1', + status: TransactionStatus.confirmed, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: '0x5208', + nonce: '0x12', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + }, + transactionHash: ethTxHash, + toSmartContract: false, + }, +]; + +export const txsInStateWithOutdatedStatusMock = ( + ethTxHash: string, + tokenTxHash: string, +): TransactionMeta[] => [ + { + id: 'token-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '624874', + gasPrice: '20000000000', + gasUsed: '21000', + nonce: '0x12', + to: '0x881d40237659c251811cec9c364ef91dc08d300c', + value: '0x0', + }, + transactionHash: tokenTxHash, + toSmartContract: true, + }, + { + id: 'eth-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: '0x5208', + nonce: '0x12', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + }, + transactionHash: ethTxHash, + toSmartContract: false, + }, +]; + +export const txsInStateWithOutdatedGasDataMock = ( + ethTxHash: string, + tokenTxHash: string, +): TransactionMeta[] => [ + { + id: 'token-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '624874', + gasPrice: '20000000000', + gasUsed: undefined, + nonce: '0x12', + to: '0x881d40237659c251811cec9c364ef91dc08d300c', + value: '0x0', + }, + transactionHash: tokenTxHash, + toSmartContract: true, + }, + { + id: 'eth-transaction-id', + chainId: '1', + status: TransactionStatus.failedBeforeChain, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: undefined, + nonce: '0x12', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + }, + transactionHash: ethTxHash, + toSmartContract: false, + }, +]; From db32fa895e04d3bcfc2cfe6ee8ebfd6f7209eae8 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 10:56:51 -0300 Subject: [PATCH 30/41] lint --- src/transaction/TransactionController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index ba1157867c..be1d5062a6 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1181,7 +1181,7 @@ export class TransactionController extends BaseController< [...normalizedTxs, ...normalizedTokenTxs], transactions, StateReconcileMethod.ETHERSCAN, - ); + ); allTxs.sort((a, b) => (a.time < b.time ? -1 : 1)); From 2267fd65c40196407d9ebec6a2d5ac7855b00626 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 11:07:49 -0300 Subject: [PATCH 31/41] test(TransactionController): Add test case --- src/transaction/TransactionController.test.ts | 35 +++++++++++++++- src/transaction/mocks/txsMock.ts | 42 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.test.ts b/src/transaction/TransactionController.test.ts index 1859633e79..37c97cb009 100644 --- a/src/transaction/TransactionController.test.ts +++ b/src/transaction/TransactionController.test.ts @@ -16,6 +16,7 @@ import { txsInStateMock, txsInStateWithOutdatedStatusMock, txsInStateWithOutdatedGasDataMock, + txsInStateWithOutdatedStatusAndGasDataMock, } from './mocks/txsMock'; const globalAny: any = global; @@ -168,6 +169,11 @@ const TRANSACTIONS_IN_STATE_WITH_OUTDATED_GAS_DATA: TransactionMeta[] = txsInSta TOKEN_TRANSACTION_HASH, ); +const TRANSACTIONS_IN_STATE_WITH_OUTDATED_STATUS_AND_GAS_DATA: TransactionMeta[] = txsInStateWithOutdatedStatusAndGasDataMock( + ETHER_TRANSACTION_HASH, + TOKEN_TRANSACTION_HASH, +); + const ETH_TX_HISTORY_DATA = { message: 'OK', result: ETH_TRANSACTIONS, @@ -732,7 +738,7 @@ describe('TransactionController', () => { expect(controller.state.transactions[0].transaction.to).toBe(from); }); - it('should fetch all the transactions from an address, including incoming token transactions without modifying transaction that have the same data in local and remote', async () => { + it('should fetch all the transactions from an address, including incoming token transactions without modifying transactions that have the same data in local and remote', async () => { globalAny.fetch = mockFetchs(MOCK_FETCH_TX_HISTORY_DATA_OK); const controller = new TransactionController({ getNetworkState: () => MOCK_MAINNET_NETWORK.state, @@ -819,6 +825,33 @@ describe('TransactionController', () => { expect(tokenTransaction?.transaction.gasUsed).toStrictEqual('21000'); expect(ethTransaction?.transaction.gasUsed).toStrictEqual('0x5208'); }); + it('should fetch and updated all transactions with outdated status and gas data regarding the data provided by the remote source in mainnet', async () => { + globalAny.fetch = mockFetchs(MOCK_FETCH_TX_HISTORY_DATA_OK); + const controller = new TransactionController({ + getNetworkState: () => MOCK_MAINNET_NETWORK.state, + onNetworkStateChange: MOCK_MAINNET_NETWORK.subscribe, + getProvider: MOCK_MAINNET_NETWORK.getProvider, + }); + const from = '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207'; + controller.wipeTransactions(); + expect(controller.state.transactions).toHaveLength(0); + + controller.state.transactions = TRANSACTIONS_IN_STATE_WITH_OUTDATED_STATUS_AND_GAS_DATA; + + await controller.fetchAll(from); + expect(controller.state.transactions).toHaveLength(17); + + const tokenTransaction = controller.state.transactions.find( + ({ transactionHash }) => transactionHash === TOKEN_TRANSACTION_HASH, + ) || { status: TransactionStatus.failed, transaction: { gasUsed: '0' } }; + const ethTransaction = controller.state.transactions.find( + ({ transactionHash }) => transactionHash === ETHER_TRANSACTION_HASH, + ) || { status: TransactionStatus.failed, transaction: { gasUsed: '0x0' } }; + expect(tokenTransaction?.status).toStrictEqual(TransactionStatus.confirmed); + expect(ethTransaction?.status).toStrictEqual(TransactionStatus.confirmed); + expect(tokenTransaction?.transaction.gasUsed).toStrictEqual('21000'); + expect(ethTransaction?.transaction.gasUsed).toStrictEqual('0x5208'); + }); it('should return', async () => { globalAny.fetch = mockFetch(MOCK_FETCH_TX_HISTORY_DATA_ERROR); const controller = new TransactionController({ diff --git a/src/transaction/mocks/txsMock.ts b/src/transaction/mocks/txsMock.ts index 6034154848..204abcdf37 100644 --- a/src/transaction/mocks/txsMock.ts +++ b/src/transaction/mocks/txsMock.ts @@ -454,6 +454,48 @@ export const txsInStateWithOutdatedStatusMock = ( export const txsInStateWithOutdatedGasDataMock = ( ethTxHash: string, tokenTxHash: string, +): TransactionMeta[] => [ + { + id: 'token-transaction-id', + chainId: '1', + status: TransactionStatus.confirmed, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '624874', + gasPrice: '20000000000', + gasUsed: undefined, + nonce: '0x12', + to: '0x881d40237659c251811cec9c364ef91dc08d300c', + value: '0x0', + }, + transactionHash: tokenTxHash, + toSmartContract: true, + }, + { + id: 'eth-transaction-id', + chainId: '1', + status: TransactionStatus.confirmed, + time: 1615497996125, + transaction: { + from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + data: '0x', + gas: '0x51d68', + gasPrice: '0x2540be400', + gasUsed: undefined, + nonce: '0x12', + to: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', + value: '100000000000000000', + }, + transactionHash: ethTxHash, + toSmartContract: false, + }, +]; + +export const txsInStateWithOutdatedStatusAndGasDataMock = ( + ethTxHash: string, + tokenTxHash: string, ): TransactionMeta[] => [ { id: 'token-transaction-id', From 3341b593e3f376efdb81052c857629da0e5580bd Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 11:10:12 -0300 Subject: [PATCH 32/41] fix(TransactionController): Remove console.log --- src/transaction/TransactionController.ts | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index be1d5062a6..066cf64cf7 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -701,11 +701,6 @@ export class TransactionController extends BaseController< this.updateTransaction(transactionMeta); const rawTransaction = bufferToHex(signedTx.serialize()); - console.log( - 'Controller Log @ 635 -> rawTransaction in approveTransaction method', - rawTransaction, - ); - transactionMeta.rawTransaction = rawTransaction; this.updateTransaction(transactionMeta); const transactionHash = await query(this.ethQuery, 'sendRawTransaction', [ @@ -1077,10 +1072,6 @@ export class TransactionController extends BaseController< ), ); /* istanbul ignore else */ - console.log( - 'Controller Log @ 1104 queryTransactionStatuses gotUpdates', - gotUpdates, - ); if (gotUpdates) { this.update({ transactions: this.trimTransactionsForState(transactions), @@ -1159,15 +1150,6 @@ export class TransactionController extends BaseController< etherscanTokenResponse, ] = await handleTransactionFetch(networkType, address, opt); - console.log( - 'Controller Log @ 1238 fetchAll etherscanTxResponse', - etherscanTxResponse, - ); - console.log( - 'Controller Log @ 1238 fetchAll etherscanTokenResponse', - etherscanTokenResponse, - ); - const normalizedTxs = etherscanTxResponse.result.map( (tx: EtherscanTransactionMeta) => this.normalizeTx(tx, currentNetworkID, currentChainId), @@ -1221,14 +1203,10 @@ export class TransactionController extends BaseController< } }); // Update state only if new transactions were fetched or - // the status of a transaction has changed + // the status or gas data of a transaction has changed if (updateTxs) { this.update({ transactions: this.trimTransactionsForState(allTxs) }); } - console.log( - 'Controller Log @ 1250 fetchAll this.state.transactions', - this.state.transactions, - ); return latestIncomingTxBlockNumber; } From 86e3638362fba86ab494841df90ae3294f68cc9e Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 14:25:22 -0300 Subject: [PATCH 33/41] docs(TransactionController): Add gasUsed property --- src/transaction/TransactionController.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 066cf64cf7..92af491873 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -65,6 +65,7 @@ export interface FetchAllOptions { * @property from - Address to send this transaction from * @property gas - Gas to send with this transaction * @property gasPrice - Price of gas with this transaction + * @property gasUsed - Gas used in the transaction * @property nonce - Unique number to prevent replay attacks * @property to - Address to send this transaction to * @property value - Value associated with this transaction From 525319e4d29bb1d4de5e48a8498d5786f9192ce5 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 17:11:35 -0300 Subject: [PATCH 34/41] fix(TransactionController): Add small updates --- src/transaction/TransactionController.ts | 16 +++++++++------- src/transaction/mocks/txsMock.ts | 8 ++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 92af491873..f409ed6d9f 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -104,7 +104,6 @@ export enum TransactionStatus { cancelled = 'cancelled', confirmed = 'confirmed', failed = 'failed', - failedBeforeChain = 'failedBeforeChain', rejected = 'rejected', signed = 'signed', submitted = 'submitted', @@ -546,7 +545,7 @@ export class TransactionController extends BaseController< try { const { gas } = await this.estimateGas(transaction); transaction.gas = gas; - } catch (error) { + } catch (error: any) { this.failTransaction(transactionMeta, error); return Promise.reject(error); } @@ -711,7 +710,7 @@ export class TransactionController extends BaseController< transactionMeta.status = TransactionStatus.submitted; this.updateTransaction(transactionMeta); this.hub.emit(`${transactionMeta.id}:finished`, transactionMeta); - } catch (error) { + } catch (error: any) { this.failTransaction(transactionMeta, error); } finally { releaseLock(); @@ -1151,15 +1150,18 @@ export class TransactionController extends BaseController< etherscanTokenResponse, ] = await handleTransactionFetch(networkType, address, opt); - const normalizedTxs = etherscanTxResponse.result.map( + let normalizedTxs = etherscanTxResponse.result.map( (tx: EtherscanTransactionMeta) => this.normalizeTx(tx, currentNetworkID, currentChainId), ); - const normalizedTokenTxs = etherscanTokenResponse.result.map( + let normalizedTokenTxs = etherscanTokenResponse.result.map( (tx: EtherscanTransactionMeta) => this.normalizeTokenTx(tx, currentNetworkID, currentChainId), ); + normalizedTxs = this.trimTransactionsForState(normalizedTxs); + normalizedTokenTxs = this.trimTransactionsForState(normalizedTokenTxs); + const [updateTxs, allTxs] = this.transactionStateReconciler( [...normalizedTxs, ...normalizedTokenTxs], transactions, @@ -1251,7 +1253,7 @@ export class TransactionController extends BaseController< } /** - * Resolves the locally stored transactions with the blockchain or etherscan. Then updated TransactionController State + * Resolves the locally stored transactions with the blockchain or etherscan to update TransactionController State * @param remoteTxs - Array of transactions fetched from etherscan, the blockchain or other source * @param localTxs - Array of transactions currently stored in the state of the controller * @param stateReconcileMethod - Strategy used to reconcile the transactions @@ -1271,7 +1273,7 @@ export class TransactionController extends BaseController< } /** - * Function to determine if the transaction is in a final state + * Method to determine if the transaction is in a final state * @param status - Transaction status * @returns boolean if the transaction is in a final state */ diff --git a/src/transaction/mocks/txsMock.ts b/src/transaction/mocks/txsMock.ts index 204abcdf37..61b435f1a0 100644 --- a/src/transaction/mocks/txsMock.ts +++ b/src/transaction/mocks/txsMock.ts @@ -416,7 +416,7 @@ export const txsInStateWithOutdatedStatusMock = ( { id: 'token-transaction-id', chainId: '1', - status: TransactionStatus.failedBeforeChain, + status: TransactionStatus.rejected, time: 1615497996125, transaction: { from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', @@ -434,7 +434,7 @@ export const txsInStateWithOutdatedStatusMock = ( { id: 'eth-transaction-id', chainId: '1', - status: TransactionStatus.failedBeforeChain, + status: TransactionStatus.rejected, time: 1615497996125, transaction: { from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', @@ -500,7 +500,7 @@ export const txsInStateWithOutdatedStatusAndGasDataMock = ( { id: 'token-transaction-id', chainId: '1', - status: TransactionStatus.failedBeforeChain, + status: TransactionStatus.rejected, time: 1615497996125, transaction: { from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', @@ -518,7 +518,7 @@ export const txsInStateWithOutdatedStatusAndGasDataMock = ( { id: 'eth-transaction-id', chainId: '1', - status: TransactionStatus.failedBeforeChain, + status: TransactionStatus.rejected, time: 1615497996125, transaction: { from: '0x6bf137f335ea1b8f193b8f6ea92561a60d23a207', From a289caf16d360a524648a1e9783b046b191389fd Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 17:17:25 -0300 Subject: [PATCH 35/41] fix(TransactionController): Add small updates --- src/transaction/TransactionController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index f409ed6d9f..a63e2adcce 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1208,7 +1208,7 @@ export class TransactionController extends BaseController< // Update state only if new transactions were fetched or // the status or gas data of a transaction has changed if (updateTxs) { - this.update({ transactions: this.trimTransactionsForState(allTxs) }); + this.update({ transactions: allTxs }); } return latestIncomingTxBlockNumber; } From d2c0bbcf378e9a49e2d47f6ae387b1e7f862b9d3 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 17:33:17 -0300 Subject: [PATCH 36/41] fix(TransactionController): Remove unused method --- src/transaction/TransactionController.ts | 14 --------- src/util.ts | 39 ------------------------ 2 files changed, 53 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index a63e2adcce..84d2a64779 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -110,20 +110,6 @@ export enum TransactionStatus { unapproved = 'unapproved', } -/** - * Status of a transaction according to Etherscan. - * According to the documentation: "The status field returns - * 0 for failed transactions and 1 for successful transactions" - * successful: 1 - * failed: 0 - * error: Indicates an error while fetching the data - */ -export enum EtherscanTransactionStatus { - successful = 'successful', - failed = 'failed', - error = 'error', -} - /** * Options for wallet device. */ diff --git a/src/util.ts b/src/util.ts index 2e9b73ed37..94b9444762 100644 --- a/src/util.ts +++ b/src/util.ts @@ -17,7 +17,6 @@ import { FetchAllOptions, GasPriceValue, FeeMarketEIP1559Values, - EtherscanTransactionStatus, } from './transaction/TransactionController'; import { MessageParams } from './message-manager/MessageManager'; import { PersonalMessageParams } from './message-manager/PersonalMessageManager'; @@ -230,44 +229,6 @@ export async function handleTransactionFetch( return [etherscanTxResponse, etherscanTokenResponse]; } -/** - * Method to fetch tHe status of a single transaction in Etherscan, - * from the Etherscan docs: "The status field returns 0 for failed transactions - * and 1 for successful transactions." - * @param networkType - Network type of desired network - * @param transactionHash - Hash of the required transaction - * @param opt? - Object that can contain fromBlock and Etherscan service API key - * @returns Promise with the status of the transaction - */ -export async function handletransationStatusFetch( - networkType: string, - transactionHash: string, - opt?: FetchAllOptions, -): Promise { - const urlParams = { - module: 'transaction', - action: 'gettxreceiptstatus', - txhash: transactionHash, - apikey: opt?.etherscanApiKey, - }; - const etherscanTxUrl = getEtherscanApiUrl(networkType, urlParams); - - try { - const response = await handleFetch(etherscanTxUrl); - const { status, result } = response; - - if (status === '0') { - return EtherscanTransactionStatus.error; - } - - return result.status === '1' - ? EtherscanTransactionStatus.successful - : EtherscanTransactionStatus.failed; - } catch (e) { - return EtherscanTransactionStatus.error; - } -} - /** * Converts a hex string to a BN object * From 142a11e4690a3af7d3e9bf608051db166c7329cd Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 18:11:03 -0300 Subject: [PATCH 37/41] fix(TransactionController): Address review comments --- src/transaction/TransactionController.ts | 12 ++++++------ src/util.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 84d2a64779..061b98fdc1 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1148,7 +1148,7 @@ export class TransactionController extends BaseController< normalizedTxs = this.trimTransactionsForState(normalizedTxs); normalizedTokenTxs = this.trimTransactionsForState(normalizedTokenTxs); - const [updateTxs, allTxs] = this.transactionStateReconciler( + const [updateRequired, allTxs] = this.transactionStateReconciler( [...normalizedTxs, ...normalizedTokenTxs], transactions, StateReconcileMethod.ETHERSCAN, @@ -1193,7 +1193,7 @@ export class TransactionController extends BaseController< }); // Update state only if new transactions were fetched or // the status or gas data of a transaction has changed - if (updateTxs) { + if (updateRequired) { this.update({ transactions: allTxs }); } return latestIncomingTxBlockNumber; @@ -1293,9 +1293,9 @@ export class TransactionController extends BaseController< return txIdx === -1 ? tx : outdatedTxs[txIdx]; }); - const update = newTxs.length > 0 || updatedLocalTxs.length > 0; + const updateRequired = newTxs.length > 0 || updatedLocalTxs.length > 0; - return [update, [...newTxs, ...updatedLocalTxs]]; + return [updateRequired, [...newTxs, ...updatedLocalTxs]]; } /** @@ -1318,8 +1318,8 @@ export class TransactionController extends BaseController< } /** - * Get all the transactions that are locally outdated respect a - * remote source (etherscan or blockchain). The returned array + * Get all the transactions that are locally outdated with respect + * to a remote source (etherscan or blockchain). The returned array * contains the transactions with the updated data. * @param remoteTxs - Array of transactions from remote source * @param localTxs - Array of transactions stored locally diff --git a/src/util.ts b/src/util.ts index 94b9444762..732eaa3b1a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -183,7 +183,7 @@ export async function handleTransactionFetch( networkType: string, address: string, opt?: FetchAllOptions, -): Promise { +): Promise<[{ [result: string]: [] }, { [result: string]: [] }]> { // transactions const urlParams = { module: 'account', From 05fd2c8e775af3f9384095ec729b470e1423b6f4 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 18:13:29 -0300 Subject: [PATCH 38/41] fix(TransactionController): Address review comments --- src/transaction/TransactionController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 061b98fdc1..7add92b68a 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -125,7 +125,6 @@ export enum WalletDevice { export enum StateReconcileMethod { ETHERSCAN = 'etherscan', BLOCKCHAIN = 'blockchain', - OTHER = 'other', } type TransactionMetaBase = { From 1af39dd08d512e2d278d6d6d979d58e4d3e93385 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 18:55:59 -0300 Subject: [PATCH 39/41] fix(TransactionController): Address review comments --- src/transaction/TransactionController.test.ts | 12 +++---- src/transaction/TransactionController.ts | 35 +++++-------------- src/util.ts | 1 + 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/src/transaction/TransactionController.test.ts b/src/transaction/TransactionController.test.ts index 37c97cb009..7d53c7bfde 100644 --- a/src/transaction/TransactionController.test.ts +++ b/src/transaction/TransactionController.test.ts @@ -205,12 +205,12 @@ const ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND = { }; const MOCK_FETCH_TX_HISTORY_DATA_OK = { - 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&limit=50&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&limit=50&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA_FROM_BLOCK, }; const MOCK_FETCH_TX_HISTORY_DATA_ERROR = { diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 7add92b68a..86fb485ccc 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1135,18 +1135,15 @@ export class TransactionController extends BaseController< etherscanTokenResponse, ] = await handleTransactionFetch(networkType, address, opt); - let normalizedTxs = etherscanTxResponse.result.map( + const normalizedTxs = etherscanTxResponse.result.map( (tx: EtherscanTransactionMeta) => this.normalizeTx(tx, currentNetworkID, currentChainId), ); - let normalizedTokenTxs = etherscanTokenResponse.result.map( + const normalizedTokenTxs = etherscanTokenResponse.result.map( (tx: EtherscanTransactionMeta) => this.normalizeTokenTx(tx, currentNetworkID, currentChainId), ); - normalizedTxs = this.trimTransactionsForState(normalizedTxs); - normalizedTokenTxs = this.trimTransactionsForState(normalizedTokenTxs); - const [updateRequired, allTxs] = this.transactionStateReconciler( [...normalizedTxs, ...normalizedTokenTxs], transactions, @@ -1193,7 +1190,7 @@ export class TransactionController extends BaseController< // Update state only if new transactions were fetched or // the status or gas data of a transaction has changed if (updateRequired) { - this.update({ transactions: allTxs }); + this.update({ transactions: this.trimTransactionsForState(allTxs) }); } return latestIncomingTxBlockNumber; } @@ -1275,7 +1272,7 @@ export class TransactionController extends BaseController< remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], ): [boolean, TransactionMeta[]] { - const outdatedTxs: TransactionMeta[] = this.getOutdatedTransactions( + const updatedTxs: TransactionMeta[] = this.getUpdatedTransactions( remoteTxs, localTxs, ); @@ -1286,10 +1283,10 @@ export class TransactionController extends BaseController< ); const updatedLocalTxs = localTxs.map((tx: TransactionMeta) => { - const txIdx = outdatedTxs.findIndex( + const txIdx = updatedTxs.findIndex( ({ transactionHash }) => transactionHash === tx.transactionHash, ); - return txIdx === -1 ? tx : outdatedTxs[txIdx]; + return txIdx === -1 ? tx : updatedTxs[txIdx]; }); const updateRequired = newTxs.length > 0 || updatedLocalTxs.length > 0; @@ -1324,7 +1321,7 @@ export class TransactionController extends BaseController< * @param localTxs - Array of transactions stored locally * @returns TransactionMeta array */ - private getOutdatedTransactions( + private getUpdatedTransactions( remoteTxs: TransactionMeta[], localTxs: TransactionMeta[], ): TransactionMeta[] { @@ -1356,11 +1353,7 @@ export class TransactionController extends BaseController< localTx.status, ); const gasDataOutdated = this.isGasDataOutdated( - remoteTx.transaction.gas, - remoteTx.transaction.gasPrice, remoteTx.transaction.gasUsed, - localTx.transaction.gas, - localTx.transaction.gasPrice, localTx.transaction.gasUsed, ); return statusOutdated || gasDataOutdated; @@ -1385,27 +1378,15 @@ export class TransactionController extends BaseController< /** * Verifies if the gas data of a local transaction is outdated in respect the remote transaction - * @param remoteGas - Remote gas - * @param remoteGasPrice - Remote gas price * @param remoteGasUsed - Remote gas used in the transaction - * @param localGas - Local gas - * @param localGasPrice - Local gas price * @param localGasUsed - Local gas used in the transaction * @returns boolean */ private isGasDataOutdated( - remoteGas: string | undefined, - remoteGasPrice: string | undefined, remoteGasUsed: string | undefined, - localGas: string | undefined, - localGasPrice: string | undefined, localGasUsed: string | undefined, ): boolean { - return ( - remoteGas !== localGas || - remoteGasPrice !== localGasPrice || - remoteGasUsed !== localGasUsed - ); + return remoteGasUsed !== localGasUsed; } } diff --git a/src/util.ts b/src/util.ts index 732eaa3b1a..4359c0f9b9 100644 --- a/src/util.ts +++ b/src/util.ts @@ -190,6 +190,7 @@ export async function handleTransactionFetch( address, startBlock: opt?.fromBlock, apikey: opt?.etherscanApiKey, + limit: '50', }; const etherscanTxUrl = getEtherscanApiUrl(networkType, { ...urlParams, From 0f57c39f5b8ca0e6502db03f978e9664da280f5d Mon Sep 17 00:00:00 2001 From: gantunesr Date: Wed, 8 Sep 2021 19:48:18 -0300 Subject: [PATCH 40/41] fix(TransactionController): Address review comments --- src/transaction/TransactionController.test.ts | 14 ++++++++------ src/transaction/TransactionController.ts | 7 ++++++- src/util.ts | 4 +++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/transaction/TransactionController.test.ts b/src/transaction/TransactionController.test.ts index 7d53c7bfde..a68429b765 100644 --- a/src/transaction/TransactionController.test.ts +++ b/src/transaction/TransactionController.test.ts @@ -205,12 +205,14 @@ const ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND = { }; const MOCK_FETCH_TX_HISTORY_DATA_OK = { - 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&limit=50&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&limit=50&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, - 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&limit=50&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&offset=40&order=desc&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&offset=40&order=desc&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&offset=40&order=desc&action=tokentx&tag=latest&page=1': TOKEN_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&offset=40&order=desc&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&offset=40&order=desc&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, + 'https://api.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&startBlock=999&offset=40&order=desc&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA_FROM_BLOCK, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&offset=2&order=desc&action=tokentx&tag=latest&page=1': ETH_TX_HISTORY_DATA_ROPSTEN_NO_TRANSACTIONS_FOUND, + 'https://api-ropsten.etherscan.io/api?module=account&address=0x6bf137f335ea1b8f193b8f6ea92561a60d23a207&offset=2&order=desc&action=txlist&tag=latest&page=1': ETH_TX_HISTORY_DATA, }; const MOCK_FETCH_TX_HISTORY_DATA_ERROR = { diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 86fb485ccc..124e3954ce 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1133,7 +1133,12 @@ export class TransactionController extends BaseController< const [ etherscanTxResponse, etherscanTokenResponse, - ] = await handleTransactionFetch(networkType, address, opt); + ] = await handleTransactionFetch( + networkType, + address, + this.config.txHistoryLimit, + opt, + ); const normalizedTxs = etherscanTxResponse.result.map( (tx: EtherscanTransactionMeta) => diff --git a/src/util.ts b/src/util.ts index 4359c0f9b9..05ee2699ef 100644 --- a/src/util.ts +++ b/src/util.ts @@ -182,6 +182,7 @@ export function getEtherscanApiUrl( export async function handleTransactionFetch( networkType: string, address: string, + txHistoryLimit: number, opt?: FetchAllOptions, ): Promise<[{ [result: string]: [] }, { [result: string]: [] }]> { // transactions @@ -190,7 +191,8 @@ export async function handleTransactionFetch( address, startBlock: opt?.fromBlock, apikey: opt?.etherscanApiKey, - limit: '50', + offset: txHistoryLimit.toString(), + order: 'desc', }; const etherscanTxUrl = getEtherscanApiUrl(networkType, { ...urlParams, From 33280d8015495cd52c66cc4f100c4a7ca3ddf5b5 Mon Sep 17 00:00:00 2001 From: gantunesr Date: Thu, 9 Sep 2021 11:47:27 -0300 Subject: [PATCH 41/41] docs(TransactionController): fix --- src/transaction/TransactionController.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/transaction/TransactionController.ts b/src/transaction/TransactionController.ts index 124e3954ce..a17aa8c20e 100644 --- a/src/transaction/TransactionController.ts +++ b/src/transaction/TransactionController.ts @@ -1342,7 +1342,7 @@ export class TransactionController extends BaseController< } /** - * Verifies if a local transaction is outdated in respect the remote transaction + * Verifies if a local transaction is outdated with respect to the remote transaction * @param remoteTx - Remote transaction from Etherscan * @param localTx - Local transaction * @returns boolean @@ -1365,7 +1365,7 @@ export class TransactionController extends BaseController< } /** - * Verifies if the status of a local transaction is outdated in respect the remote transaction + * Verifies if the status of a local transaction is outdated with respect to the remote transaction * @param remoteTxHash - Remote transaction hash * @param localTxHash - Local transaction hash * @param remoteTxStatus - Remote transaction status @@ -1382,7 +1382,7 @@ export class TransactionController extends BaseController< } /** - * Verifies if the gas data of a local transaction is outdated in respect the remote transaction + * Verifies if the gas data of a local transaction is outdated with respect to the remote transaction * @param remoteGasUsed - Remote gas used in the transaction * @param localGasUsed - Local gas used in the transaction * @returns boolean