From 833f82cd66bf153e347b0880f7c333614d2a7990 Mon Sep 17 00:00:00 2001 From: PatrykLucka Date: Wed, 21 Apr 2021 09:07:12 +0200 Subject: [PATCH 1/4] replace incoming with external transactions --- app/_locales/en/messages.json | 9 + ...ansactions.js => external-transactions.js} | 68 +-- ....test.js => external-transactions.test.js} | 392 +++++++++++------- app/scripts/controllers/preferences.js | 2 +- app/scripts/lib/setupSentry.js | 2 +- app/scripts/metamask-controller.js | 14 +- app/scripts/migrations/058.js | 40 ++ app/scripts/migrations/058.test.js | 99 +++++ app/scripts/migrations/index.js | 1 + shared/constants/transaction.js | 2 + test/data/mock-state.json | 4 +- test/e2e/fixtures/address-entry/state.json | 8 +- test/e2e/fixtures/connected-state/state.json | 8 +- test/e2e/fixtures/imported-account/state.json | 8 +- test/e2e/fixtures/localization/state.json | 8 +- test/e2e/fixtures/metrics-enabled/state.json | 8 +- test/e2e/fixtures/send-edit/state.json | 8 +- test/e2e/fixtures/threebox-enabled/state.json | 8 +- ui/app/hooks/useTransactionDisplayData.js | 4 + .../security-tab/security-tab.component.js | 20 +- .../security-tab/security-tab.container.js | 8 +- .../security-tab.container.test.js | 12 +- ui/app/selectors/transactions.js | 22 +- ui/app/selectors/transactions.test.js | 14 +- 24 files changed, 512 insertions(+), 257 deletions(-) rename app/scripts/controllers/{incoming-transactions.js => external-transactions.js} (83%) rename app/scripts/controllers/{incoming-transactions.test.js => external-transactions.test.js} (74%) create mode 100644 app/scripts/migrations/058.js create mode 100644 app/scripts/migrations/058.test.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index d77ad124f992..1cdcf8e09aa8 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -700,6 +700,9 @@ "externalExtension": { "message": "External Extension" }, + "externalSend": { + "message": "External Send" + }, "extraApprovalGas": { "message": "+$1 approval gas", "description": "Expresses an additional gas amount the user will have to pay, on top of some other displayed amount. $1 is a decimal amount of gas" @@ -1587,6 +1590,12 @@ "showAdvancedGasInlineDescription": { "message": "Select this to show gas price and limit controls directly on the send and confirm screens." }, + "showExternalTransactions": { + "message": "Show External Transactions" + }, + "showExternalTransactionsDescription": { + "message": "Select this to use Etherscan to show external transactions (incoming and originated from external wallets) in the transactions list" + }, "showFiatConversionInTestnets": { "message": "Show Conversion on Testnets" }, diff --git a/app/scripts/controllers/incoming-transactions.js b/app/scripts/controllers/external-transactions.js similarity index 83% rename from app/scripts/controllers/incoming-transactions.js rename to app/scripts/controllers/external-transactions.js index 7aa621898da6..68ad49a3014c 100644 --- a/app/scripts/controllers/incoming-transactions.js +++ b/app/scripts/controllers/external-transactions.js @@ -44,11 +44,11 @@ const fetchWithTimeout = getFetchWithTimeout(30000); */ /** - * This controller is responsible for retrieving incoming transactions. Etherscan is polled once every block to check - * for new incoming transactions for the current selected account on the current network + * This controller is responsible for retrieving external transactions. Etherscan is polled once every block to check + * for new external transactions for the current selected account on the current network * * Note that only the built-in Infura networks are supported (i.e. anything in `INFURA_PROVIDER_TYPES`). We will not - * attempt to retrieve incoming transactions on any custom RPC endpoints. + * attempt to retrieve external transactions on any custom RPC endpoints. */ const etherscanSupportedNetworks = [ GOERLI_CHAIN_ID, @@ -58,7 +58,7 @@ const etherscanSupportedNetworks = [ ROPSTEN_CHAIN_ID, ]; -export default class IncomingTransactionsController { +export default class ExternalTransactionsController { constructor(opts = {}) { const { blockTracker, @@ -77,8 +77,8 @@ export default class IncomingTransactionsController { }; const initState = { - incomingTransactions: {}, - incomingTxLastFetchedBlockByChainId: { + externalTransactions: {}, + externalTxLastFetchedBlockByChainId: { [GOERLI_CHAIN_ID]: null, [KOVAN_CHAIN_ID]: null, [MAINNET_CHAIN_ID]: null, @@ -93,20 +93,20 @@ export default class IncomingTransactionsController { previousValueComparator((prevState, currState) => { const { featureFlags: { - showIncomingTransactions: prevShowIncomingTransactions, + showExternalTransactions: prevShowExternalTransactions, } = {}, } = prevState; const { featureFlags: { - showIncomingTransactions: currShowIncomingTransactions, + showExternalTransactions: currShowExternalTransactions, } = {}, } = currState; - if (currShowIncomingTransactions === prevShowIncomingTransactions) { + if (currShowExternalTransactions === prevShowExternalTransactions) { return; } - if (prevShowIncomingTransactions && !currShowIncomingTransactions) { + if (prevShowExternalTransactions && !currShowExternalTransactions) { this.stop(); return; } @@ -135,9 +135,9 @@ export default class IncomingTransactionsController { start() { const { featureFlags = {} } = this.preferencesController.store.getState(); - const { showIncomingTransactions } = featureFlags; + const { showExternalTransactions } = featureFlags; - if (!showIncomingTransactions) { + if (!showExternalTransactions) { return; } @@ -169,11 +169,11 @@ export default class IncomingTransactionsController { const currentBlock = parseInt(this.blockTracker.getCurrentBlock(), 16); const mostRecentlyFetchedBlock = - currentState.incomingTxLastFetchedBlockByChainId[chainId]; + currentState.externalTxLastFetchedBlockByChainId[chainId]; const blockToFetchFrom = mostRecentlyFetchedBlock ?? newBlockNumberDec ?? currentBlock; - const newIncomingTxs = await this._getNewIncomingTransactions( + const newExternalTxs = await this._getNewExternalTransactions( address, blockToFetchFrom, chainId, @@ -181,7 +181,7 @@ export default class IncomingTransactionsController { let newMostRecentlyFetchedBlock = blockToFetchFrom; - newIncomingTxs.forEach((tx) => { + newExternalTxs.forEach((tx) => { if ( tx.blockNumber && parseInt(newMostRecentlyFetchedBlock, 10) < @@ -192,17 +192,17 @@ export default class IncomingTransactionsController { }); this.store.updateState({ - incomingTxLastFetchedBlockByChainId: { - ...currentState.incomingTxLastFetchedBlockByChainId, + externalTxLastFetchedBlockByChainId: { + ...currentState.externalTxLastFetchedBlockByChainId, [chainId]: newMostRecentlyFetchedBlock + 1, }, - incomingTransactions: newIncomingTxs.reduce( + externalTransactions: newExternalTxs.reduce( (transactions, tx) => { transactions[tx.hash] = tx; return transactions; }, { - ...currentState.incomingTransactions, + ...currentState.externalTransactions, }, ), }); @@ -221,7 +221,7 @@ export default class IncomingTransactionsController { * @param {string} [chainId] - The chainId for the current network * @returns {TransactionMeta[]} */ - async _getNewIncomingTransactions(address, fromBlock, chainId) { + async _getNewExternalTransactions(address, fromBlock, chainId) { const etherscanSubdomain = chainId === MAINNET_CHAIN_ID ? 'api' @@ -235,32 +235,31 @@ export default class IncomingTransactionsController { } const response = await fetchWithTimeout(url); const { status, result } = await response.json(); - let newIncomingTxs = []; + const newExternalTxs = []; if (status === '1' && Array.isArray(result) && result.length > 0) { - const remoteTxList = {}; - const remoteTxs = []; + const externalTxList = {}; result.forEach((tx) => { - if (!remoteTxList[tx.hash]) { - remoteTxs.push(this._normalizeTxFromEtherscan(tx, chainId)); - remoteTxList[tx.hash] = 1; + if (!externalTxList[tx.hash]) { + newExternalTxs.push( + this._normalizeTxFromEtherscan(tx, chainId, address), + ); + externalTxList[tx.hash] = 1; } }); - newIncomingTxs = remoteTxs.filter( - (tx) => tx.txParams?.to?.toLowerCase() === address.toLowerCase(), - ); - newIncomingTxs.sort((a, b) => (a.time < b.time ? -1 : 1)); + newExternalTxs.sort((a, b) => (a.time < b.time ? -1 : 1)); } - return newIncomingTxs; + return newExternalTxs; } /** * Transmutes a EtherscanTransaction into a TransactionMeta * @param {EtherscanTransaction} etherscanTransaction - the transaction to normalize * @param {string} chainId - The chainId of the current network + * @param {string} address - Selected address * @returns {TransactionMeta} */ - _normalizeTxFromEtherscan(etherscanTransaction, chainId) { + _normalizeTxFromEtherscan(etherscanTransaction, chainId, address) { const time = parseInt(etherscanTransaction.timeStamp, 10) * 1000; const status = etherscanTransaction.isError === '0' @@ -282,7 +281,10 @@ export default class IncomingTransactionsController { value: bnToHex(new BN(etherscanTransaction.value)), }, hash: etherscanTransaction.hash, - type: TRANSACTION_TYPES.INCOMING, + type: + etherscanTransaction.from.toLowerCase() === address?.toLowerCase() + ? TRANSACTION_TYPES.SENT + : TRANSACTION_TYPES.INCOMING, }; } } diff --git a/app/scripts/controllers/incoming-transactions.test.js b/app/scripts/controllers/external-transactions.test.js similarity index 74% rename from app/scripts/controllers/incoming-transactions.test.js rename to app/scripts/controllers/external-transactions.test.js index 74aaad78ce33..b62ade14b52c 100644 --- a/app/scripts/controllers/incoming-transactions.test.js +++ b/app/scripts/controllers/external-transactions.test.js @@ -20,7 +20,7 @@ import { TRANSACTION_STATUSES, } from '../../../shared/constants/transaction'; -const IncomingTransactionsController = proxyquire('./incoming-transactions', { +const ExternalTransactionsController = proxyquire('./external-transactions', { '../../../shared/modules/random-id': { default: () => 54321 }, }).default; @@ -49,15 +49,15 @@ const EMPTY_BLOCKS_BY_NETWORK = { function getEmptyInitState() { return { - incomingTransactions: {}, - incomingTxLastFetchedBlockByChainId: EMPTY_BLOCKS_BY_NETWORK, + externalTransactions: {}, + externalTxLastFetchedBlockByChainId: EMPTY_BLOCKS_BY_NETWORK, }; } function getNonEmptyInitState() { return { - incomingTransactions: PREPOPULATED_INCOMING_TXS_BY_HASH, - incomingTxLastFetchedBlockByChainId: PREPOPULATED_BLOCKS_BY_NETWORK, + externalTransactions: PREPOPULATED_INCOMING_TXS_BY_HASH, + externalTxLastFetchedBlockByChainId: PREPOPULATED_BLOCKS_BY_NETWORK, }; } @@ -69,14 +69,14 @@ function getMockNetworkControllerMethods(chainId = FAKE_CHAIN_ID) { } function getMockPreferencesController({ - showIncomingTransactions = true, + showExternalTransactions = true, } = {}) { return { getSelectedAddress: sinon.stub().returns(MOCK_SELECTED_ADDRESS), store: { getState: sinon.stub().returns({ featureFlags: { - showIncomingTransactions, + showExternalTransactions, }, }), subscribe: sinon.spy(), @@ -95,7 +95,7 @@ function getMockBlockTracker() { /** * @typedef {import( - * '../../../../app/scripts/controllers/incoming-transactions' + * '../../../../app/scripts/controllers/external-transactions' * ).EtherscanTransaction} EtherscanTransaction */ @@ -125,6 +125,32 @@ const getFakeEtherscanTransaction = ( }; }; +/** + * Returns a transaction object matching the expected format returned + * by the Etherscan API + * + * @param {string} [fromAddress] - The hex-prefixed address of the sender + * @param {number} [blockNumber] - The block number for the transaction + * @returns {EtherscanTransaction} + */ +const getFakeEtherscanSendTransaction = ( + fromAddress = MOCK_SELECTED_ADDRESS, + blockNumber = 10, +) => { + return { + blockNumber: blockNumber.toString(), + from: fromAddress, + gas: '0', + gasPrice: '0', + hash: '0xfakeSend', + isError: '0', + nonce: '100', + timeStamp: '16000000000000', + to: '0xfake', + value: '0', + }; +}; + function nockEtherscanApiForAllChains(mockResponse) { for (const chainId of [ GOERLI_CHAIN_ID, @@ -144,7 +170,7 @@ function nockEtherscanApiForAllChains(mockResponse) { } } -describe('IncomingTransactionsController', function () { +describe('ExternalTransactionsController', function () { afterEach(function () { sinon.restore(); nock.cleanAll(); @@ -153,7 +179,7 @@ describe('IncomingTransactionsController', function () { describe('constructor', function () { it('should set up correct store, listeners and properties in the constructor', function () { const mockedNetworkMethods = getMockNetworkControllerMethods(); - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...mockedNetworkMethods, @@ -161,10 +187,10 @@ describe('IncomingTransactionsController', function () { initState: {}, }, ); - sinon.spy(incomingTransactionsController, '_update'); + sinon.spy(externalTransactionsController, '_update'); assert.deepStrictEqual( - incomingTransactionsController.store.getState(), + externalTransactionsController.store.getState(), getEmptyInitState(), ); @@ -172,19 +198,19 @@ describe('IncomingTransactionsController', function () { const networkControllerListenerCallback = mockedNetworkMethods.onNetworkDidChange.getCall( 0, ).args[0]; - assert.strictEqual(incomingTransactionsController._update.callCount, 0); + assert.strictEqual(externalTransactionsController._update.callCount, 0); networkControllerListenerCallback('testNetworkType'); - assert.strictEqual(incomingTransactionsController._update.callCount, 1); + assert.strictEqual(externalTransactionsController._update.callCount, 1); assert.deepStrictEqual( - incomingTransactionsController._update.getCall(0).args[0], + externalTransactionsController._update.getCall(0).args[0], '0x0101', ); - incomingTransactionsController._update.resetHistory(); + externalTransactionsController._update.resetHistory(); }); it('should set the store to a provided initial state', function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(), @@ -194,7 +220,7 @@ describe('IncomingTransactionsController', function () { ); assert.deepStrictEqual( - incomingTransactionsController.store.getState(), + externalTransactionsController.store.getState(), getNonEmptyInitState(), ); }); @@ -202,7 +228,7 @@ describe('IncomingTransactionsController', function () { describe('update events', function () { it('should set up a listener for the latest block', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(), @@ -211,20 +237,20 @@ describe('IncomingTransactionsController', function () { }, ); - incomingTransactionsController.start(); + externalTransactionsController.start(); assert( - incomingTransactionsController.blockTracker.addListener.calledOnce, + externalTransactionsController.blockTracker.addListener.calledOnce, ); assert.strictEqual( - incomingTransactionsController.blockTracker.addListener.getCall(0) + externalTransactionsController.blockTracker.addListener.getCall(0) .args[0], 'latest', ); }); it('should update upon latest block when started and on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -233,7 +259,7 @@ describe('IncomingTransactionsController', function () { }, ); const startBlock = getNonEmptyInitState() - .incomingTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID]; + .externalTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID]; nock('https://api-ropsten.etherscan.io') .get( `/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`, @@ -246,22 +272,22 @@ describe('IncomingTransactionsController', function () { }), ); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); - incomingTransactionsController.start(); + externalTransactionsController.start(); await updateStateCalled(); - const actualState = incomingTransactionsController.store.getState(); - const generatedTxId = actualState?.incomingTransactions?.['0xfake']?.id; + const actualState = externalTransactionsController.store.getState(); + const generatedTxId = actualState?.externalTransactions?.['0xfake']?.id; const actualStateWithoutGenerated = cloneDeep(actualState); - delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id; + delete actualStateWithoutGenerated?.externalTransactions?.['0xfake']?.id; assert.ok( typeof generatedTxId === 'number' && generatedTxId > 0, @@ -270,8 +296,8 @@ describe('IncomingTransactionsController', function () { assert.deepStrictEqual( actualStateWithoutGenerated, { - incomingTransactions: { - ...getNonEmptyInitState().incomingTransactions, + externalTransactions: { + ...getNonEmptyInitState().externalTransactions, '0xfake': { blockNumber: '10', hash: '0xfake', @@ -290,8 +316,8 @@ describe('IncomingTransactionsController', function () { }, }, }, - incomingTxLastFetchedBlockByChainId: { - ...getNonEmptyInitState().incomingTxLastFetchedBlockByChainId, + externalTxLastFetchedBlockByChainId: { + ...getNonEmptyInitState().externalTxLastFetchedBlockByChainId, [ROPSTEN_CHAIN_ID]: 11, }, }, @@ -300,7 +326,7 @@ describe('IncomingTransactionsController', function () { }); it('should not update upon latest block when started and not on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(), @@ -315,23 +341,23 @@ describe('IncomingTransactionsController', function () { }); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const putStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'putState', ); const putStateCalled = waitUntilCalled( putStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); - incomingTransactionsController.start(); + externalTransactionsController.start(); try { await Promise.race([ @@ -347,13 +373,13 @@ describe('IncomingTransactionsController', function () { } }); - it('should not update upon latest block when started and incoming transactions disabled', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + it('should not update upon latest block when started and external transactions disabled', async function () { + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(), preferencesController: getMockPreferencesController({ - showIncomingTransactions: false, + showExternalTransactions: false, }), initState: getNonEmptyInitState(), }, @@ -364,23 +390,23 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction()], }); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const putStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'putState', ); const putStateCalled = waitUntilCalled( putStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); - incomingTransactionsController.start(); + externalTransactionsController.start(); try { await Promise.race([ @@ -397,7 +423,7 @@ describe('IncomingTransactionsController', function () { }); it('should not update upon latest block when not started', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -411,20 +437,20 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction()], }); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const putStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'putState', ); const putStateCalled = waitUntilCalled( putStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); try { @@ -442,7 +468,7 @@ describe('IncomingTransactionsController', function () { }); it('should not update upon latest block when stopped', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -456,23 +482,23 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction()], }); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const putStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'putState', ); const putStateCalled = waitUntilCalled( putStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); - incomingTransactionsController.stop(); + externalTransactionsController.stop(); try { await Promise.race([ @@ -489,7 +515,7 @@ describe('IncomingTransactionsController', function () { }); it('should update when the selected address changes and on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -499,7 +525,7 @@ describe('IncomingTransactionsController', function () { ); const NEW_MOCK_SELECTED_ADDRESS = `${MOCK_SELECTED_ADDRESS}9`; const startBlock = getNonEmptyInitState() - .incomingTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID]; + .externalTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID]; nock('https://api-ropsten.etherscan.io') .get( `/api?module=account&action=txlist&address=${NEW_MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`, @@ -512,29 +538,29 @@ describe('IncomingTransactionsController', function () { }), ); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); - const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall( + const subscription = externalTransactionsController.preferencesController.store.subscribe.getCall( 1, ).args[0]; - // The incoming transactions controller will always skip the first event + // The external transactions controller will always skip the first event // We need to call subscription twice to test the event handling // TODO: stop skipping the first event await subscription({ selectedAddress: MOCK_SELECTED_ADDRESS }); await subscription({ selectedAddress: NEW_MOCK_SELECTED_ADDRESS }); await updateStateCalled(); - const actualState = incomingTransactionsController.store.getState(); - const generatedTxId = actualState?.incomingTransactions?.['0xfake']?.id; + const actualState = externalTransactionsController.store.getState(); + const generatedTxId = actualState?.externalTransactions?.['0xfake']?.id; const actualStateWithoutGenerated = cloneDeep(actualState); - delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id; + delete actualStateWithoutGenerated?.externalTransactions?.['0xfake']?.id; assert.ok( typeof generatedTxId === 'number' && generatedTxId > 0, @@ -543,8 +569,8 @@ describe('IncomingTransactionsController', function () { assert.deepStrictEqual( actualStateWithoutGenerated, { - incomingTransactions: { - ...getNonEmptyInitState().incomingTransactions, + externalTransactions: { + ...getNonEmptyInitState().externalTransactions, '0xfake': { blockNumber: '10', hash: '0xfake', @@ -563,8 +589,8 @@ describe('IncomingTransactionsController', function () { }, }, }, - incomingTxLastFetchedBlockByChainId: { - ...getNonEmptyInitState().incomingTxLastFetchedBlockByChainId, + externalTxLastFetchedBlockByChainId: { + ...getNonEmptyInitState().externalTxLastFetchedBlockByChainId, [ROPSTEN_CHAIN_ID]: 11, }, }, @@ -573,7 +599,7 @@ describe('IncomingTransactionsController', function () { }); it('should not update when the selected address changes and not on supported network', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: { ...getMockBlockTracker() }, ...getMockNetworkControllerMethods(), @@ -588,26 +614,26 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction(NEW_MOCK_SELECTED_ADDRESS)], }); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const putStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'putState', ); const putStateCalled = waitUntilCalled( putStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); - const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall( + const subscription = externalTransactionsController.preferencesController.store.subscribe.getCall( 1, ).args[0]; - // The incoming transactions controller will always skip the first event + // The external transactions controller will always skip the first event // We need to call subscription twice to test the event handling // TODO: stop skipping the first event await subscription({ selectedAddress: MOCK_SELECTED_ADDRESS }); @@ -631,7 +657,7 @@ describe('IncomingTransactionsController', function () { const mockedNetworkMethods = getMockNetworkControllerMethods( ROPSTEN_CHAIN_ID, ); - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...mockedNetworkMethods, @@ -640,7 +666,7 @@ describe('IncomingTransactionsController', function () { }, ); const startBlock = getNonEmptyInitState() - .incomingTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID]; + .externalTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID]; nock('https://api-ropsten.etherscan.io') .get( `/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`, @@ -653,12 +679,12 @@ describe('IncomingTransactionsController', function () { }), ); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const subscription = mockedNetworkMethods.onNetworkDidChange.getCall(0) @@ -666,11 +692,11 @@ describe('IncomingTransactionsController', function () { await subscription(ROPSTEN_CHAIN_ID); await updateStateCalled(); - const actualState = incomingTransactionsController.store.getState(); - const generatedTxId = actualState?.incomingTransactions?.['0xfake']?.id; + const actualState = externalTransactionsController.store.getState(); + const generatedTxId = actualState?.externalTransactions?.['0xfake']?.id; const actualStateWithoutGenerated = cloneDeep(actualState); - delete actualStateWithoutGenerated?.incomingTransactions?.['0xfake']?.id; + delete actualStateWithoutGenerated?.externalTransactions?.['0xfake']?.id; assert.ok( typeof generatedTxId === 'number' && generatedTxId > 0, @@ -679,8 +705,8 @@ describe('IncomingTransactionsController', function () { assert.deepStrictEqual( actualStateWithoutGenerated, { - incomingTransactions: { - ...getNonEmptyInitState().incomingTransactions, + externalTransactions: { + ...getNonEmptyInitState().externalTransactions, '0xfake': { blockNumber: '10', hash: '0xfake', @@ -699,8 +725,8 @@ describe('IncomingTransactionsController', function () { }, }, }, - incomingTxLastFetchedBlockByChainId: { - ...getNonEmptyInitState().incomingTxLastFetchedBlockByChainId, + externalTxLastFetchedBlockByChainId: { + ...getNonEmptyInitState().externalTxLastFetchedBlockByChainId, [ROPSTEN_CHAIN_ID]: 11, }, }, @@ -712,7 +738,7 @@ describe('IncomingTransactionsController', function () { const mockedNetworkMethods = getMockNetworkControllerMethods( ROPSTEN_CHAIN_ID, ); - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...mockedNetworkMethods, @@ -726,26 +752,26 @@ describe('IncomingTransactionsController', function () { result: [getFakeEtherscanTransaction()], }); const updateStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'updateState', ); const updateStateCalled = waitUntilCalled( updateStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const putStateStub = sinon.stub( - incomingTransactionsController.store, + externalTransactionsController.store, 'putState', ); const putStateCalled = waitUntilCalled( putStateStub, - incomingTransactionsController.store, + externalTransactionsController.store, ); const subscription = mockedNetworkMethods.onNetworkDidChange.getCall(0) .args[0]; - incomingTransactionsController.getCurrentChainId = () => FAKE_CHAIN_ID; + externalTransactionsController.getCurrentChainId = () => FAKE_CHAIN_ID; await subscription(); try { @@ -766,7 +792,7 @@ describe('IncomingTransactionsController', function () { describe('_update', function () { describe('when state is empty (initialized)', function () { it('should use provided block number and update the latest block seen', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -775,35 +801,35 @@ describe('IncomingTransactionsController', function () { getCurrentChainId: () => ROPSTEN_CHAIN_ID, }, ); - sinon.spy(incomingTransactionsController.store, 'updateState'); + sinon.spy(externalTransactionsController.store, 'updateState'); - incomingTransactionsController._getNewIncomingTransactions = sinon + externalTransactionsController._getNewExternalTransactions = sinon .stub() .returns([]); - await incomingTransactionsController._update('fakeAddress', 999); + await externalTransactionsController._update('fakeAddress', 999); assert( - incomingTransactionsController._getNewIncomingTransactions.calledOnce, + externalTransactionsController._getNewExternalTransactions.calledOnce, ); assert.deepStrictEqual( - incomingTransactionsController._getNewIncomingTransactions.getCall(0) + externalTransactionsController._getNewExternalTransactions.getCall(0) .args, ['fakeAddress', 999, ROPSTEN_CHAIN_ID], ); assert.deepStrictEqual( - incomingTransactionsController.store.updateState.getCall(0).args[0], + externalTransactionsController.store.updateState.getCall(0).args[0], { - incomingTxLastFetchedBlockByChainId: { + externalTxLastFetchedBlockByChainId: { ...EMPTY_BLOCKS_BY_NETWORK, [ROPSTEN_CHAIN_ID]: 1000, }, - incomingTransactions: {}, + externalTransactions: {}, }, ); }); - it('should update the last fetched block for network to highest block seen in incoming txs', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + it('should update the last fetched block for network to highest block seen in external txs', async function () { + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -824,29 +850,29 @@ describe('IncomingTransactionsController', function () { blockNumber: 443, }; - sinon.spy(incomingTransactionsController.store, 'updateState'); + sinon.spy(externalTransactionsController.store, 'updateState'); - incomingTransactionsController._getNewIncomingTransactions = sinon + externalTransactionsController._getNewExternalTransactions = sinon .stub() .returns([NEW_TRANSACTION_ONE, NEW_TRANSACTION_TWO]); - await incomingTransactionsController._update('fakeAddress', 10); + await externalTransactionsController._update('fakeAddress', 10); - assert(incomingTransactionsController.store.updateState.calledOnce); + assert(externalTransactionsController.store.updateState.calledOnce); assert.deepStrictEqual( - incomingTransactionsController._getNewIncomingTransactions.getCall(0) + externalTransactionsController._getNewExternalTransactions.getCall(0) .args, ['fakeAddress', 10, ROPSTEN_CHAIN_ID], ); assert.deepStrictEqual( - incomingTransactionsController.store.updateState.getCall(0).args[0], + externalTransactionsController.store.updateState.getCall(0).args[0], { - incomingTxLastFetchedBlockByChainId: { + externalTxLastFetchedBlockByChainId: { ...EMPTY_BLOCKS_BY_NETWORK, [ROPSTEN_CHAIN_ID]: 445, }, - incomingTransactions: { + externalTransactions: { [NEW_TRANSACTION_ONE.hash]: NEW_TRANSACTION_ONE, [NEW_TRANSACTION_TWO.hash]: NEW_TRANSACTION_TWO, }, @@ -857,7 +883,7 @@ describe('IncomingTransactionsController', function () { describe('when state is populated with prior data for network', function () { it('should use the last fetched block for the current network and increment by 1 in state', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -866,39 +892,39 @@ describe('IncomingTransactionsController', function () { getCurrentChainId: () => ROPSTEN_CHAIN_ID, }, ); - sinon.spy(incomingTransactionsController.store, 'updateState'); - incomingTransactionsController._getNewIncomingTransactions = sinon + sinon.spy(externalTransactionsController.store, 'updateState'); + externalTransactionsController._getNewExternalTransactions = sinon .stub() .returns([]); - await incomingTransactionsController._update('fakeAddress', 999); + await externalTransactionsController._update('fakeAddress', 999); assert( - incomingTransactionsController._getNewIncomingTransactions.calledOnce, + externalTransactionsController._getNewExternalTransactions.calledOnce, ); assert.deepStrictEqual( - incomingTransactionsController._getNewIncomingTransactions.getCall(0) + externalTransactionsController._getNewExternalTransactions.getCall(0) .args, ['fakeAddress', 4, ROPSTEN_CHAIN_ID], ); assert.deepStrictEqual( - incomingTransactionsController.store.updateState.getCall(0).args[0], + externalTransactionsController.store.updateState.getCall(0).args[0], { - incomingTxLastFetchedBlockByChainId: { + externalTxLastFetchedBlockByChainId: { ...PREPOPULATED_BLOCKS_BY_NETWORK, [ROPSTEN_CHAIN_ID]: PREPOPULATED_BLOCKS_BY_NETWORK[ROPSTEN_CHAIN_ID] + 1, }, - incomingTransactions: PREPOPULATED_INCOMING_TXS_BY_HASH, + externalTransactions: PREPOPULATED_INCOMING_TXS_BY_HASH, }, ); }); }); - it('should update the last fetched block for network to highest block seen in incoming txs', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + it('should update the last fetched block for network to highest block seen in external txs', async function () { + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -919,29 +945,29 @@ describe('IncomingTransactionsController', function () { blockNumber: 443, }; - sinon.spy(incomingTransactionsController.store, 'updateState'); + sinon.spy(externalTransactionsController.store, 'updateState'); - incomingTransactionsController._getNewIncomingTransactions = sinon + externalTransactionsController._getNewExternalTransactions = sinon .stub() .returns([NEW_TRANSACTION_ONE, NEW_TRANSACTION_TWO]); - await incomingTransactionsController._update('fakeAddress', 10); + await externalTransactionsController._update('fakeAddress', 10); - assert(incomingTransactionsController.store.updateState.calledOnce); + assert(externalTransactionsController.store.updateState.calledOnce); assert.deepStrictEqual( - incomingTransactionsController._getNewIncomingTransactions.getCall(0) + externalTransactionsController._getNewExternalTransactions.getCall(0) .args, ['fakeAddress', 4, ROPSTEN_CHAIN_ID], ); assert.deepStrictEqual( - incomingTransactionsController.store.updateState.getCall(0).args[0], + externalTransactionsController.store.updateState.getCall(0).args[0], { - incomingTxLastFetchedBlockByChainId: { + externalTxLastFetchedBlockByChainId: { ...PREPOPULATED_BLOCKS_BY_NETWORK, [ROPSTEN_CHAIN_ID]: 445, }, - incomingTransactions: { + externalTransactions: { ...PREPOPULATED_INCOMING_TXS_BY_HASH, [NEW_TRANSACTION_ONE.hash]: NEW_TRANSACTION_ONE, [NEW_TRANSACTION_TWO.hash]: NEW_TRANSACTION_TWO, @@ -951,12 +977,19 @@ describe('IncomingTransactionsController', function () { }); }); - describe('_getNewIncomingTransactions', function () { + describe('_getNewExternalTransactions', function () { const ADDRESS_TO_FETCH_FOR = '0xfakeaddress'; const FETCHED_TX = getFakeEtherscanTransaction(ADDRESS_TO_FETCH_FOR); + const FETCHED_SEND_TX = getFakeEtherscanSendTransaction( + ADDRESS_TO_FETCH_FOR, + ); const mockFetch = sinon.stub().returns( Promise.resolve({ - json: () => Promise.resolve({ status: '1', result: [FETCHED_TX] }), + json: () => + Promise.resolve({ + status: '1', + result: [FETCHED_TX, FETCHED_SEND_TX], + }), }), ); let tempFetch; @@ -971,7 +1004,7 @@ describe('IncomingTransactionsController', function () { }); it('should call fetch with the expected url when passed an address, block number and supported chainId', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -980,7 +1013,7 @@ describe('IncomingTransactionsController', function () { }, ); - await incomingTransactionsController._getNewIncomingTransactions( + await externalTransactionsController._getNewExternalTransactions( ADDRESS_TO_FETCH_FOR, '789', ROPSTEN_CHAIN_ID, @@ -994,7 +1027,7 @@ describe('IncomingTransactionsController', function () { }); it('should call fetch with the expected url when passed an address, block number and MAINNET chainId', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(MAINNET_CHAIN_ID), @@ -1003,7 +1036,7 @@ describe('IncomingTransactionsController', function () { }, ); - await incomingTransactionsController._getNewIncomingTransactions( + await externalTransactionsController._getNewExternalTransactions( ADDRESS_TO_FETCH_FOR, '789', MAINNET_CHAIN_ID, @@ -1017,7 +1050,7 @@ describe('IncomingTransactionsController', function () { }); it('should call fetch with the expected url when passed an address and supported chainId, but a falsy block number', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -1026,7 +1059,7 @@ describe('IncomingTransactionsController', function () { }, ); - await incomingTransactionsController._getNewIncomingTransactions( + await externalTransactionsController._getNewExternalTransactions( ADDRESS_TO_FETCH_FOR, null, ROPSTEN_CHAIN_ID, @@ -1040,7 +1073,7 @@ describe('IncomingTransactionsController', function () { }); it('should return an array of normalized transactions', async function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -1049,7 +1082,7 @@ describe('IncomingTransactionsController', function () { }, ); - const result = await incomingTransactionsController._getNewIncomingTransactions( + const result = await externalTransactionsController._getNewExternalTransactions( ADDRESS_TO_FETCH_FOR, '789', ROPSTEN_CHAIN_ID, @@ -1057,9 +1090,15 @@ describe('IncomingTransactionsController', function () { assert(mockFetch.calledOnce); assert.deepStrictEqual(result, [ - incomingTransactionsController._normalizeTxFromEtherscan( + externalTransactionsController._normalizeTxFromEtherscan( FETCHED_TX, ROPSTEN_CHAIN_ID, + ADDRESS_TO_FETCH_FOR, + ), + externalTransactionsController._normalizeTxFromEtherscan( + FETCHED_SEND_TX, + ROPSTEN_CHAIN_ID, + ADDRESS_TO_FETCH_FOR, ), ]); }); @@ -1072,7 +1111,7 @@ describe('IncomingTransactionsController', function () { ); const tempFetchStatusZero = window.fetch; window.fetch = mockFetchStatusZero; - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -1081,7 +1120,7 @@ describe('IncomingTransactionsController', function () { }, ); - const result = await incomingTransactionsController._getNewIncomingTransactions( + const result = await externalTransactionsController._getNewExternalTransactions( ADDRESS_TO_FETCH_FOR, '789', ROPSTEN_CHAIN_ID, @@ -1099,7 +1138,7 @@ describe('IncomingTransactionsController', function () { ); const tempFetchEmptyResult = window.fetch; window.fetch = mockFetchEmptyResult; - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -1108,7 +1147,7 @@ describe('IncomingTransactionsController', function () { }, ); - const result = await incomingTransactionsController._getNewIncomingTransactions( + const result = await externalTransactionsController._getNewExternalTransactions( ADDRESS_TO_FETCH_FOR, '789', ROPSTEN_CHAIN_ID, @@ -1121,7 +1160,7 @@ describe('IncomingTransactionsController', function () { describe('_normalizeTxFromEtherscan', function () { it('should return the expected data when the tx is in error', function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -1130,7 +1169,7 @@ describe('IncomingTransactionsController', function () { }, ); - const result = incomingTransactionsController._normalizeTxFromEtherscan( + const result = externalTransactionsController._normalizeTxFromEtherscan( { timeStamp: '4444', isError: '1', @@ -1167,7 +1206,7 @@ describe('IncomingTransactionsController', function () { }); it('should return the expected data when the tx is not in error', function () { - const incomingTransactionsController = new IncomingTransactionsController( + const externalTransactionsController = new ExternalTransactionsController( { blockTracker: getMockBlockTracker(), ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), @@ -1176,7 +1215,7 @@ describe('IncomingTransactionsController', function () { }, ); - const result = incomingTransactionsController._normalizeTxFromEtherscan( + const result = externalTransactionsController._normalizeTxFromEtherscan( { timeStamp: '4444', isError: '0', @@ -1211,5 +1250,52 @@ describe('IncomingTransactionsController', function () { type: TRANSACTION_TYPES.INCOMING, }); }); + + it('should return the expected data when the tx is outgoing transactions', function () { + const externalTransactionsController = new ExternalTransactionsController( + { + blockTracker: getMockBlockTracker(), + ...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID), + preferencesController: getMockPreferencesController(), + initState: getNonEmptyInitState(), + }, + ); + + const result = externalTransactionsController._normalizeTxFromEtherscan( + { + timeStamp: '4444', + isError: '0', + blockNumber: 333, + from: '0xa', + gas: '11', + gasPrice: '12', + nonce: '13', + to: '0xe', + value: '15', + hash: '0xg', + }, + ROPSTEN_CHAIN_ID, + '0xa', + ); + + assert.deepStrictEqual(result, { + blockNumber: 333, + id: 54321, + metamaskNetworkId: ROPSTEN_NETWORK_ID, + chainId: ROPSTEN_CHAIN_ID, + status: TRANSACTION_STATUSES.CONFIRMED, + time: 4444000, + txParams: { + from: '0xa', + gas: '0xb', + gasPrice: '0xc', + nonce: '0xd', + to: '0xe', + value: '0xf', + }, + hash: '0xg', + type: TRANSACTION_TYPES.SENT, + }); + }); }); }); diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 9470df50c54a..07f2f99cb500 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -49,7 +49,7 @@ export default class PreferencesController { // for convenient testing of pre-release features, and should never // perform sensitive operations. featureFlags: { - showIncomingTransactions: true, + showExternalTransactions: true, }, knownMethodData: {}, firstTimeFlowType: null, diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index 09482d24b9d5..ed99ef1c1565 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -31,7 +31,7 @@ export const SENTRY_STATE = { featureFlags: true, firstTimeFlowType: true, forgottenPassword: true, - incomingTxLastFetchedBlockByChainId: true, + externalTxLastFetchedBlockByChainId: true, ipfsGateway: true, isAccountMenuOpen: true, isInitialized: true, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6d4c45ea0198..51fed67b46b3 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -41,7 +41,7 @@ import CachedBalancesController from './controllers/cached-balances'; import AlertController from './controllers/alert'; import OnboardingController from './controllers/onboarding'; import ThreeBoxController from './controllers/threebox'; -import IncomingTransactionsController from './controllers/incoming-transactions'; +import ExternalTransactionsController from './controllers/external-transactions'; import MessageManager from './lib/message-manager'; import DecryptMessageManager from './lib/decrypt-message-manager'; import EncryptionPublicKeyManager from './lib/encryption-public-key-manager'; @@ -186,7 +186,7 @@ export default class MetamaskController extends EventEmitter { ), }); - this.incomingTransactionsController = new IncomingTransactionsController({ + this.externalTransactionsController = new ExternalTransactionsController({ blockTracker: this.blockTracker, onNetworkDidChange: this.networkController.on.bind( this.networkController, @@ -196,7 +196,7 @@ export default class MetamaskController extends EventEmitter { this.networkController, ), preferencesController: this.preferencesController, - initState: initState.IncomingTransactionsController, + initState: initState.ExternalTransactionsController, }); // account tracker watches balances, nonces, and any code at their address @@ -212,11 +212,11 @@ export default class MetamaskController extends EventEmitter { this.on('controllerConnectionChanged', (activeControllerConnections) => { if (activeControllerConnections > 0) { this.accountTracker.start(); - this.incomingTransactionsController.start(); + this.externalTransactionsController.start(); this.tokenRatesController.start(); } else { this.accountTracker.stop(); - this.incomingTransactionsController.stop(); + this.externalTransactionsController.stop(); this.tokenRatesController.stop(); } }); @@ -423,7 +423,7 @@ export default class MetamaskController extends EventEmitter { CachedBalancesController: this.cachedBalancesController.store, AlertController: this.alertController.store, OnboardingController: this.onboardingController.store, - IncomingTransactionsController: this.incomingTransactionsController.store, + ExternalTransactionsController: this.externalTransactionsController.store, PermissionsController: this.permissionsController.permissions, PermissionsMetadata: this.permissionsController.store, ThreeBoxController: this.threeBoxController.store, @@ -448,7 +448,7 @@ export default class MetamaskController extends EventEmitter { CurrencyController: this.currencyRateController, AlertController: this.alertController.store, OnboardingController: this.onboardingController.store, - IncomingTransactionsController: this.incomingTransactionsController.store, + ExternalTransactionsController: this.externalTransactionsController.store, PermissionsController: this.permissionsController.permissions, PermissionsMetadata: this.permissionsController.store, ThreeBoxController: this.threeBoxController.store, diff --git a/app/scripts/migrations/058.js b/app/scripts/migrations/058.js new file mode 100644 index 000000000000..ee5c63f4d2b2 --- /dev/null +++ b/app/scripts/migrations/058.js @@ -0,0 +1,40 @@ +import { cloneDeep } from 'lodash'; + +const version = 58; + +/** + * replace IncomingTransactionsController with ExternalTransactionsController + * replace showIncomingTransactions with showExternalTransactions + */ +export default { + version, + async migrate(originalVersionedData) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + const state = versionedData.data; + versionedData.data = transformState(state); + return versionedData; + }, +}; + +function transformState(state) { + if (state?.IncomingTransactionsController) { + state.ExternalTransactionsController = state.IncomingTransactionsController; + state.ExternalTransactionsController.externalTransactions = + state.IncomingTransactionsController.incomingTransactions; + state.ExternalTransactionsController.externalTxLastFetchedBlockByChainId = + state.IncomingTransactionsController.incomingTxLastFetchedBlockByChainId; + + delete state.IncomingTransactionsController; + delete state.ExternalTransactionsController.incomingTransactions; + delete state.ExternalTransactionsController + .incomingTxLastFetchedBlockByChainId; + } + + if (state?.PreferencesController) { + state.PreferencesController.featureFlags.showExternalTransactions = + state.PreferencesController.featureFlags?.showIncomingTransactions; + delete state.PreferencesController.featureFlags.showIncomingTransactions; + } + return state; +} diff --git a/app/scripts/migrations/058.test.js b/app/scripts/migrations/058.test.js new file mode 100644 index 000000000000..9baa726d45c5 --- /dev/null +++ b/app/scripts/migrations/058.test.js @@ -0,0 +1,99 @@ +import { strict as assert } from 'assert'; +import { + GOERLI_CHAIN_ID, + KOVAN_CHAIN_ID, + MAINNET_CHAIN_ID, + RINKEBY_CHAIN_ID, + ROPSTEN_CHAIN_ID, +} from '../../../shared/constants/network'; +import migration58 from './058'; + +describe('migration #58', function () { + it('should update the version metadata', async function () { + const oldStorage = { + meta: { + version: 57, + }, + data: {}, + }; + + const newStorage = await migration58.migrate(oldStorage); + assert.deepEqual(newStorage.meta, { + version: 58, + }); + }); + + it('should replace IncomingTransactionsController with ExternalTransactionsController, and carry over old values', async function () { + const oldStorage = { + meta: {}, + data: { + IncomingTransactionsController: { + incomingTransactions: { + test: { + transactionCategory: 'incoming', + txParams: { + foo: 'bar', + }, + }, + }, + incomingTxLastFetchedBlocksByNetwork: { + [MAINNET_CHAIN_ID]: 1, + [ROPSTEN_CHAIN_ID]: 2, + [RINKEBY_CHAIN_ID]: 3, + [GOERLI_CHAIN_ID]: 4, + [KOVAN_CHAIN_ID]: 5, + }, + }, + foo: 'bar', + }, + }; + + const newStorage = await migration58.migrate(oldStorage); + assert.deepEqual(newStorage.data, { + ExternalTransactionsController: { + externalTransactions: + oldStorage.data.IncomingTransactionsController.incomingTransactions, + externalTxLastFetchedBlockByChainId: { + [MAINNET_CHAIN_ID]: 1, + [ROPSTEN_CHAIN_ID]: 2, + [RINKEBY_CHAIN_ID]: 3, + [GOERLI_CHAIN_ID]: 4, + [KOVAN_CHAIN_ID]: 5, + }, + }, + foo: 'bar', + }); + }); + + it('should do nothing if state is empty', async function () { + const oldStorage = { + meta: {}, + data: {}, + }; + + const newStorage = await migration58.migrate(oldStorage); + assert.deepEqual(oldStorage.data, newStorage.data); + }); + + it('should replace showIncomingTransactions with showExternalTransactions', async function () { + const oldStorage = { + meta: {}, + data: { + PreferencesController: { + featureFlags: { + showIncomingTransactions: true, + }, + }, + }, + }; + + const newStorage = await migration58.migrate(oldStorage); + assert.deepEqual(newStorage.data, { + PreferencesController: { + featureFlags: { + showExternalTransactions: true, + }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 8d56dcc85bf2..b0c1716f5310 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -62,6 +62,7 @@ const migrations = [ require('./055').default, require('./056').default, require('./057').default, + require('./058').default, ]; export default migrations; diff --git a/shared/constants/transaction.js b/shared/constants/transaction.js index 44a777a94864..c60151851646 100644 --- a/shared/constants/transaction.js +++ b/shared/constants/transaction.js @@ -9,6 +9,7 @@ * @property {'approve'} TOKEN_METHOD_APPROVE - A token transaction requesting an * allowance of the token to spend on behalf of the user * @property {'incoming'} INCOMING - An incoming (deposit) transaction + * @property {'sent'} SENT - A transaction sent from external source (other than MetaMask) * @property {'sentEther'} SENT_ETHER - A transaction sending ether to a recipient * @property {'contractInteraction'} CONTRACT_INTERACTION - A transaction that is * interacting with a smart contract's methods that we have not treated as a special @@ -46,6 +47,7 @@ export const TRANSACTION_TYPES = { TOKEN_METHOD_TRANSFER_FROM: 'transferfrom', TOKEN_METHOD_APPROVE: 'approve', INCOMING: 'incoming', + SENT: 'sent', SENT_ETHER: 'sentEther', CONTRACT_INTERACTION: 'contractInteraction', DEPLOY_CONTRACT: 'contractDeployment', diff --git a/test/data/mock-state.json b/test/data/mock-state.json index 412892d9a193..67de06f9e2c7 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -9,7 +9,7 @@ }, "metamask": { "featureFlags": { - "showIncomingTransactions": true + "showExternalTransactions": true }, "network": "4", "provider": { @@ -26,7 +26,7 @@ } }, "cachedBalances": {}, - "incomingTransactions": {}, + "externalTransactions": {}, "unapprovedTxs": { "8393540981007587": { "id": 8393540981007587, diff --git a/test/e2e/fixtures/address-entry/state.json b/test/e2e/fixtures/address-entry/state.json index 26da39502601..c9c4573e7004 100644 --- a/test/e2e/fixtures/address-entry/state.json +++ b/test/e2e/fixtures/address-entry/state.json @@ -28,9 +28,9 @@ "currentCurrency": "usd", "nativeCurrency": "ETH" }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlocksByNetwork": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlocksByNetwork": { "goerli": null, "kovan": null, "mainnet": null, @@ -97,7 +97,7 @@ "completedOnboarding": true, "currentLocale": "en", "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "firstTimeFlowType": "create", diff --git a/test/e2e/fixtures/connected-state/state.json b/test/e2e/fixtures/connected-state/state.json index dcf4624c8233..554646f4f2ac 100644 --- a/test/e2e/fixtures/connected-state/state.json +++ b/test/e2e/fixtures/connected-state/state.json @@ -18,9 +18,9 @@ "currentCurrency": "usd", "nativeCurrency": "ETH" }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlocksByNetwork": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlocksByNetwork": { "goerli": null, "kovan": null, "mainnet": null, @@ -103,7 +103,7 @@ "useNonceField": false, "usePhishDetect": true, "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "knownMethodData": {}, diff --git a/test/e2e/fixtures/imported-account/state.json b/test/e2e/fixtures/imported-account/state.json index 1af251b51b1d..34b9fb1b4183 100644 --- a/test/e2e/fixtures/imported-account/state.json +++ b/test/e2e/fixtures/imported-account/state.json @@ -15,9 +15,9 @@ "currentCurrency": "usd", "nativeCurrency": "ETH" }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlocksByNetwork": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlocksByNetwork": { "goerli": null, "kovan": null, "mainnet": null, @@ -84,7 +84,7 @@ "completedOnboarding": true, "currentLocale": "en", "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "firstTimeFlowType": "create", diff --git a/test/e2e/fixtures/localization/state.json b/test/e2e/fixtures/localization/state.json index 8b60ffc9df0d..a7cd4ad8d199 100644 --- a/test/e2e/fixtures/localization/state.json +++ b/test/e2e/fixtures/localization/state.json @@ -15,9 +15,9 @@ "currentCurrency": "php", "nativeCurrency": "ETH" }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlocksByNetwork": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlocksByNetwork": { "goerli": null, "kovan": null, "mainnet": null, @@ -84,7 +84,7 @@ "completedOnboarding": true, "currentLocale": "en", "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "firstTimeFlowType": "create", diff --git a/test/e2e/fixtures/metrics-enabled/state.json b/test/e2e/fixtures/metrics-enabled/state.json index 4b0e52e70d38..9d2694550771 100644 --- a/test/e2e/fixtures/metrics-enabled/state.json +++ b/test/e2e/fixtures/metrics-enabled/state.json @@ -18,9 +18,9 @@ "currentCurrency": "usd", "nativeCurrency": "ETH" }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlocksByNetwork": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlocksByNetwork": { "goerli": null, "kovan": null, "mainnet": null, @@ -103,7 +103,7 @@ "useNonceField": false, "usePhishDetect": true, "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "knownMethodData": {}, diff --git a/test/e2e/fixtures/send-edit/state.json b/test/e2e/fixtures/send-edit/state.json index 77fd20720414..c4dac733f9fa 100644 --- a/test/e2e/fixtures/send-edit/state.json +++ b/test/e2e/fixtures/send-edit/state.json @@ -15,9 +15,9 @@ "currentCurrency": "usd", "nativeCurrency": "ETH" }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlocksByNetwork": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlocksByNetwork": { "goerli": null, "kovan": null, "mainnet": null, @@ -84,7 +84,7 @@ "completedOnboarding": true, "currentLocale": "en", "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "firstTimeFlowType": "create", diff --git a/test/e2e/fixtures/threebox-enabled/state.json b/test/e2e/fixtures/threebox-enabled/state.json index 602b8d94ce44..a6551aa61437 100644 --- a/test/e2e/fixtures/threebox-enabled/state.json +++ b/test/e2e/fixtures/threebox-enabled/state.json @@ -18,9 +18,9 @@ "nativeCurrency": "ETH", "usdConversionRate": 2072.49 }, - "IncomingTransactionsController": { - "incomingTransactions": {}, - "incomingTxLastFetchedBlockByChainId": { + "ExternalTransactionsController": { + "externalTransactions": {}, + "externalTxLastFetchedBlockByChainId": { "0x5": null, "0x2a": null, "0x1": null, @@ -76,7 +76,7 @@ "useNonceField": false, "usePhishDetect": true, "featureFlags": { - "showIncomingTransactions": true, + "showExternalTransactions": true, "transactionTime": false }, "knownMethodData": {}, diff --git a/ui/app/hooks/useTransactionDisplayData.js b/ui/app/hooks/useTransactionDisplayData.js index ffdda4660223..17c9de398b76 100644 --- a/ui/app/hooks/useTransactionDisplayData.js +++ b/ui/app/hooks/useTransactionDisplayData.js @@ -210,6 +210,10 @@ export function useTransactionDisplayData(transactionGroup) { category = TRANSACTION_GROUP_CATEGORIES.SEND; title = t('send'); subtitle = t('toAddress', [shortenAddress(recipientAddress)]); + } else if (type === TRANSACTION_TYPES.SENT) { + category = TRANSACTION_GROUP_CATEGORIES.SEND; + title = t('externalSend'); + subtitle = t('toAddress', [shortenAddress(recipientAddress)]); } const primaryCurrencyPreferences = useUserPreferencedCurrency(PRIMARY); diff --git a/ui/app/pages/settings/security-tab/security-tab.component.js b/ui/app/pages/settings/security-tab/security-tab.component.js index 8eab40ec2ed6..3646d66300c1 100644 --- a/ui/app/pages/settings/security-tab/security-tab.component.js +++ b/ui/app/pages/settings/security-tab/security-tab.component.js @@ -15,8 +15,8 @@ export default class SecurityTab extends PureComponent { history: PropTypes.object, participateInMetaMetrics: PropTypes.bool.isRequired, setParticipateInMetaMetrics: PropTypes.func.isRequired, - showIncomingTransactions: PropTypes.bool.isRequired, - setShowIncomingTransactionsFeatureFlag: PropTypes.func.isRequired, + showExternalTransactions: PropTypes.bool.isRequired, + setShowExternalTransactionsFeatureFlag: PropTypes.func.isRequired, setUsePhishDetect: PropTypes.func.isRequired, usePhishDetect: PropTypes.bool.isRequired, }; @@ -84,27 +84,27 @@ export default class SecurityTab extends PureComponent { ); } - renderIncomingTransactionsOptIn() { + renderExternalTransactionsOptIn() { const { t } = this.context; const { - showIncomingTransactions, - setShowIncomingTransactionsFeatureFlag, + showExternalTransactions, + setShowExternalTransactionsFeatureFlag, } = this.props; return (
- {t('showIncomingTransactions')} + {t('showExternalTransactions')}
- {t('showIncomingTransactionsDescription')} + {t('showExternalTransactionsDescription')}
- setShowIncomingTransactionsFeatureFlag(!value) + setShowExternalTransactionsFeatureFlag(!value) } offLabel={t('off')} onLabel={t('on')} @@ -148,7 +148,7 @@ export default class SecurityTab extends PureComponent {
{warning &&
{warning}
} {this.renderSeedWords()} - {this.renderIncomingTransactionsOptIn()} + {this.renderExternalTransactionsOptIn()} {this.renderPhishingDetectionToggle()} {this.renderMetaMetricsOptIn()}
diff --git a/ui/app/pages/settings/security-tab/security-tab.container.js b/ui/app/pages/settings/security-tab/security-tab.container.js index e6060f45b752..63a87f160cc9 100644 --- a/ui/app/pages/settings/security-tab/security-tab.container.js +++ b/ui/app/pages/settings/security-tab/security-tab.container.js @@ -14,14 +14,14 @@ const mapStateToProps = (state) => { metamask, } = state; const { - featureFlags: { showIncomingTransactions } = {}, + featureFlags: { showExternalTransactions } = {}, participateInMetaMetrics, usePhishDetect, } = metamask; return { warning, - showIncomingTransactions, + showExternalTransactions, participateInMetaMetrics, usePhishDetect, }; @@ -31,8 +31,8 @@ const mapDispatchToProps = (dispatch) => { return { setParticipateInMetaMetrics: (val) => dispatch(setParticipateInMetaMetrics(val)), - setShowIncomingTransactionsFeatureFlag: (shouldShow) => - dispatch(setFeatureFlag('showIncomingTransactions', shouldShow)), + setShowExternalTransactionsFeatureFlag: (shouldShow) => + dispatch(setFeatureFlag('showExternalTransactions', shouldShow)), setUsePhishDetect: (val) => dispatch(setUsePhishDetect(val)), }; }; diff --git a/ui/app/pages/settings/security-tab/security-tab.container.test.js b/ui/app/pages/settings/security-tab/security-tab.container.test.js index 61946ed1884e..4157f28b57c5 100644 --- a/ui/app/pages/settings/security-tab/security-tab.container.test.js +++ b/ui/app/pages/settings/security-tab/security-tab.container.test.js @@ -11,8 +11,8 @@ describe('Security Tab', () => { showClearApprovalModal: sinon.spy(), setParticipateInMetaMetrics: sinon.spy(), displayWarning: sinon.spy(), - showIncomingTransactions: false, - setShowIncomingTransactionsFeatureFlag: sinon.spy(), + showExternalTransactions: false, + setShowExternalTransactionsFeatureFlag: sinon.spy(), history: { push: sinon.spy(), }, @@ -40,11 +40,11 @@ describe('Security Tab', () => { expect(props.history.push.getCall(0).args[0]).toStrictEqual('/seed'); }); - it('toggles incoming txs', () => { - const incomingTxs = wrapper.find({ type: 'checkbox' }).at(0); - incomingTxs.simulate('click'); + it('toggles external txs', () => { + const externalTxs = wrapper.find({ type: 'checkbox' }).at(0); + externalTxs.simulate('click'); expect( - props.setShowIncomingTransactionsFeatureFlag.calledOnce, + props.setShowExternalTransactionsFeatureFlag.calledOnce, ).toStrictEqual(true); }); diff --git a/ui/app/selectors/transactions.js b/ui/app/selectors/transactions.js index 628b856f024e..1832ef6cbd76 100644 --- a/ui/app/selectors/transactions.js +++ b/ui/app/selectors/transactions.js @@ -13,9 +13,9 @@ import { transactionMatchesNetwork } from '../../../shared/modules/transaction.u import { getCurrentChainId, deprecatedGetCurrentNetworkId } from './selectors'; import { getSelectedAddress } from '.'; -export const incomingTxListSelector = (state) => { - const { showIncomingTransactions } = state.metamask.featureFlags; - if (!showIncomingTransactions) { +export const externalTxListSelector = (state) => { + const { showExternalTransactions } = state.metamask.featureFlags; + if (!showExternalTransactions) { return []; } @@ -24,9 +24,10 @@ export const incomingTxListSelector = (state) => { provider: { chainId }, } = state.metamask; const selectedAddress = getSelectedAddress(state); - return Object.values(state.metamask.incomingTransactions).filter( + return Object.values(state.metamask.externalTransactions).filter( (tx) => - tx.txParams.to === selectedAddress && + (tx.txParams.to === selectedAddress || + tx.txParams.from === selectedAddress) && transactionMatchesNetwork(tx, chainId, network), ); }; @@ -83,9 +84,9 @@ export const unapprovedMessagesSelector = createSelector( export const transactionSubSelector = createSelector( unapprovedMessagesSelector, - incomingTxListSelector, - (unapprovedMessages = [], incomingTxList = []) => { - return unapprovedMessages.concat(incomingTxList); + externalTxListSelector, + (unapprovedMessages = [], externalTxList = []) => { + return unapprovedMessages.concat(externalTxList); }, ); @@ -94,8 +95,11 @@ export const transactionsSelector = createSelector( selectedAddressTxListSelector, (subSelectorTxList = [], selectedAddressTxList = []) => { const txsToRender = selectedAddressTxList.concat(subSelectorTxList); + const txsHashes = txsToRender.map((item) => item.hash); - return txsToRender.sort((a, b) => b.time - a.time); + return txsToRender + .filter((item, idx) => txsHashes.indexOf(item.hash) === idx) // deduplicate (outgoing transactions) + .sort((a, b) => b.time - a.time); }, ); diff --git a/ui/app/selectors/transactions.test.js b/ui/app/selectors/transactions.test.js index 4493c3e96991..a9dc3e0e421c 100644 --- a/ui/app/selectors/transactions.test.js +++ b/ui/app/selectors/transactions.test.js @@ -115,13 +115,14 @@ describe('Transaction Selectors', () => { chainId: MAINNET_CHAIN_ID, }, featureFlags: { - showIncomingTransactions: false, + showExternalTransactions: false, }, selectedAddress: '0xAddress', currentNetworkTxList: [ { id: 0, time: 0, + hash: '0', txParams: { from: '0xAddress', to: '0xRecipient', @@ -130,6 +131,7 @@ describe('Transaction Selectors', () => { { id: 1, time: 1, + hash: '1', txParams: { from: '0xAddress', to: '0xRecipient', @@ -155,6 +157,7 @@ describe('Transaction Selectors', () => { const tx1 = { id: 0, time: 0, + hash: '0', txParams: { from: '0xAddress', to: '0xRecipient', @@ -165,6 +168,7 @@ describe('Transaction Selectors', () => { const tx2 = { id: 1, time: 1, + hash: '1', txParams: { from: '0xAddress', to: '0xRecipient', @@ -180,7 +184,7 @@ describe('Transaction Selectors', () => { }, selectedAddress: '0xAddress', featureFlags: { - showIncomingTransactions: false, + showExternalTransactions: false, }, currentNetworkTxList: [tx1, tx2], }, @@ -215,6 +219,7 @@ describe('Transaction Selectors', () => { const submittedTx = { id: 0, time: 0, + hash: '0', txParams: { from: '0xAddress', to: '0xRecipient', @@ -226,6 +231,7 @@ describe('Transaction Selectors', () => { const unapprovedTx = { id: 1, time: 1, + hash: '1', txParams: { from: '0xAddress', to: '0xRecipient', @@ -237,6 +243,7 @@ describe('Transaction Selectors', () => { const approvedTx = { id: 2, time: 2, + hash: '2', txParams: { from: '0xAddress', to: '0xRecipient', @@ -248,6 +255,7 @@ describe('Transaction Selectors', () => { const confirmedTx = { id: 3, time: 3, + hash: '3', txParams: { from: '0xAddress', to: '0xRecipient', @@ -264,7 +272,7 @@ describe('Transaction Selectors', () => { }, selectedAddress: '0xAddress', featureFlags: { - showIncomingTransactions: false, + showExternalTransactions: false, }, currentNetworkTxList: [ submittedTx, From 6c759131f746a1546c7086ba88a01ac7280cc816 Mon Sep 17 00:00:00 2001 From: PatrykLucka Date: Wed, 21 Apr 2021 09:55:47 +0200 Subject: [PATCH 2/4] fix migration unit test --- app/scripts/migrations/058.js | 2 +- app/scripts/migrations/058.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/migrations/058.js b/app/scripts/migrations/058.js index ee5c63f4d2b2..5eda7db6ab34 100644 --- a/app/scripts/migrations/058.js +++ b/app/scripts/migrations/058.js @@ -31,7 +31,7 @@ function transformState(state) { .incomingTxLastFetchedBlockByChainId; } - if (state?.PreferencesController) { + if (state?.PreferencesController?.featureFlags) { state.PreferencesController.featureFlags.showExternalTransactions = state.PreferencesController.featureFlags?.showIncomingTransactions; delete state.PreferencesController.featureFlags.showIncomingTransactions; diff --git a/app/scripts/migrations/058.test.js b/app/scripts/migrations/058.test.js index 9baa726d45c5..5992693607d4 100644 --- a/app/scripts/migrations/058.test.js +++ b/app/scripts/migrations/058.test.js @@ -36,7 +36,7 @@ describe('migration #58', function () { }, }, }, - incomingTxLastFetchedBlocksByNetwork: { + incomingTxLastFetchedBlockByChainId: { [MAINNET_CHAIN_ID]: 1, [ROPSTEN_CHAIN_ID]: 2, [RINKEBY_CHAIN_ID]: 3, From 2a71e4b116c3c290a037ac3dcd12330e6280dd9c Mon Sep 17 00:00:00 2001 From: PatrykLucka Date: Wed, 21 Apr 2021 10:01:24 +0200 Subject: [PATCH 3/4] remove unused messages --- app/_locales/en/messages.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 1cdcf8e09aa8..a661b714c784 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1608,12 +1608,6 @@ "showHexDataDescription": { "message": "Select this to show the hex data field on the send screen" }, - "showIncomingTransactions": { - "message": "Show Incoming Transactions" - }, - "showIncomingTransactionsDescription": { - "message": "Select this to use Etherscan to show incoming transactions in the transactions list" - }, "showPermissions": { "message": "Show permissions" }, From 58b6df98bc9bf25a1912be8e894afeaba916d129 Mon Sep 17 00:00:00 2001 From: PatrykLucka Date: Wed, 21 Apr 2021 10:08:04 +0200 Subject: [PATCH 4/4] verify-locales:fix --- app/_locales/es/messages.json | 6 ------ app/_locales/es_419/messages.json | 6 ------ app/_locales/hi/messages.json | 6 ------ app/_locales/id/messages.json | 6 ------ app/_locales/it/messages.json | 6 ------ app/_locales/ja/messages.json | 6 ------ app/_locales/ko/messages.json | 6 ------ app/_locales/ru/messages.json | 6 ------ app/_locales/tl/messages.json | 6 ------ app/_locales/vi/messages.json | 6 ------ app/_locales/zh_CN/messages.json | 6 ------ 11 files changed, 66 deletions(-) diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index f64a79cddb5d..f9505ed9853e 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1437,12 +1437,6 @@ "showHexDataDescription": { "message": "Seleccionar esto para mostrar el campo de los datos en formato hex en la pantalla de mandar" }, - "showIncomingTransactions": { - "message": "Mostrar transacciones entrantes" - }, - "showIncomingTransactionsDescription": { - "message": "Seleccione esto para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones" - }, "showPermissions": { "message": "Mostrar permisos" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 53ec7392960c..b0733fc9357b 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -1437,12 +1437,6 @@ "showHexDataDescription": { "message": "Selecciona esto para mostrar el campo de datos hexadecimales en la pantalla de envío" }, - "showIncomingTransactions": { - "message": "Mostrar transacciones entrantes" - }, - "showIncomingTransactionsDescription": { - "message": "Seleccione esto para usar Etherscan para mostrar las transacciones entrantes en la lista de transacciones" - }, "showPermissions": { "message": "Mostrar permisos" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 1c3a279f0fe1..787bab89060b 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1428,12 +1428,6 @@ "showHexDataDescription": { "message": "भेजने की स्क्रीन पर हेक्स डेटा फ़ील्ड दिखाने के लिए इसका चयन करें" }, - "showIncomingTransactions": { - "message": "आने वाले लेनदेन दिखाएँ" - }, - "showIncomingTransactionsDescription": { - "message": "लेनदेन सूची में आने वाले लेनदेन को दिखाने के लिए Etherscan का उपयोग करने के लिए इसका चयन करें" - }, "showPermissions": { "message": "अनुमतियाँ दिखाएँ" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index e1ad9ea77f2c..840d4a264884 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1428,12 +1428,6 @@ "showHexDataDescription": { "message": "Pilih ini untuk menampilkan bidang data hex di layar kirim" }, - "showIncomingTransactions": { - "message": "Menampilkan Transaksi yang Masuk" - }, - "showIncomingTransactionsDescription": { - "message": "Pilih ini untuk menggunakan Etherscan untuk menampilkan transaksi yang masuk di daftar transaksi" - }, "showPermissions": { "message": "Tampilkan Izin" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 4afac1dd9dac..4520294efe70 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -1443,12 +1443,6 @@ "showHexDataDescription": { "message": "Seleziona per mostrare il campo dei dati hex nella schermata di invio" }, - "showIncomingTransactions": { - "message": "Mostra Transazioni in Ingresso" - }, - "showIncomingTransactionsDescription": { - "message": "Usa Etherscan per visualizzare le transazioni in ingresso nella lista delle transazioni" - }, "showPermissions": { "message": "Mostra permessi" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index cae60ac8273f..27a841792a7a 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1437,12 +1437,6 @@ "showHexDataDescription": { "message": "オンにすると、送金画面に16進データフィールドを表示します" }, - "showIncomingTransactions": { - "message": "着信したトランザクションの表示" - }, - "showIncomingTransactionsDescription": { - "message": "オンにすると、Etherscanを使用して、着信トランザクションをトランザクションリストに表示します" - }, "showPermissions": { "message": "権限の表示" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 0a68ef634c92..6ea61305f645 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1428,12 +1428,6 @@ "showHexDataDescription": { "message": "이 항목을 선택하면 보내기 화면에 16진수 데이터 필드가 표시됩니다." }, - "showIncomingTransactions": { - "message": "수신 거래 표시" - }, - "showIncomingTransactionsDescription": { - "message": "이 항목을 선택하면 Etherscan을 사용하여 거래 목록에 수신 거래를 표시합니다." - }, "showPermissions": { "message": "권한 표시" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 6ecdcd9daeea..1785a198f91a 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1428,12 +1428,6 @@ "showHexDataDescription": { "message": "Выберите эту опцию, чтобы отобразить поле шестнадцатеричных данных на экране отправки" }, - "showIncomingTransactions": { - "message": "Показать входящие транзакции" - }, - "showIncomingTransactionsDescription": { - "message": "Выберите это, чтобы использовать Etherscan для отображения входящих транзакций в списке транзакций" - }, "showPermissions": { "message": "Показать разрешения" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 2b536c1b0b35..86c01d2765a5 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -1425,12 +1425,6 @@ "showHexDataDescription": { "message": "Piliin ito para ipakita ang field ng hex data sa screen ng pagpapadala" }, - "showIncomingTransactions": { - "message": "Ipakita ang Mga Papasok na Transaksyon" - }, - "showIncomingTransactionsDescription": { - "message": "Piliin ito para gamitin ang Etherscan sa pagpapakita ng mga papasok na transaksyon sa listahan ng mga transaksyon" - }, "showPermissions": { "message": "Ipakita ang mga pahintulot" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 00fd633df604..29515b7427cc 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1428,12 +1428,6 @@ "showHexDataDescription": { "message": "Chọn tùy chọn này để hiển thị trường dữ liệu thập lục phân trên màn hình gửi" }, - "showIncomingTransactions": { - "message": "Hiển thị các giao dịch đến" - }, - "showIncomingTransactionsDescription": { - "message": "Chọn tùy chọn này nếu bạn muốn dùng Etherscan để hiển thị các giao dịch đến trong danh sách giao dịch" - }, "showPermissions": { "message": "Hiển thị quyền" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index d043cbe9752f..f4f51cee791a 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1437,12 +1437,6 @@ "showHexDataDescription": { "message": "请选择该选项,在发送页面显示十六进制数据字域" }, - "showIncomingTransactions": { - "message": "显示收到的交易" - }, - "showIncomingTransactionsDescription": { - "message": "选择该选项可使用 Etherscan(以太坊浏览器)(以太坊浏览器)在交易列表中显示收到的交易。" - }, "showPermissions": { "message": "显示权限" },