diff --git a/packages/transaction-controller/src/TransactionController.test.ts b/packages/transaction-controller/src/TransactionController.test.ts index 305168da70c..3ef74ed6db9 100644 --- a/packages/transaction-controller/src/TransactionController.test.ts +++ b/packages/transaction-controller/src/TransactionController.test.ts @@ -221,7 +221,7 @@ function waitForTransactionFinished( }); } -const MOCK_PRFERENCES = { state: { selectedAddress: 'foo' } }; +const MOCK_PREFERENCES = { state: { selectedAddress: 'foo' } }; const INFURA_PROJECT_ID = '341eacb578dd44a1a049cbc5f6fd4035'; const GOERLI_PROVIDER = new HttpProvider( `https://goerli.infura.io/v3/${INFURA_PROJECT_ID}`, @@ -1039,7 +1039,7 @@ describe('TransactionController', () => { controller.wipeTransactions(); controller.state.transactions.push({ - from: MOCK_PRFERENCES.state.selectedAddress, + from: MOCK_PREFERENCES.state.selectedAddress, id: 'foo', networkID: '5', status: TransactionStatus.submitted, @@ -1050,6 +1050,68 @@ describe('TransactionController', () => { expect(controller.state.transactions).toHaveLength(0); }); + + it('removes only txs with given address', async () => { + const controller = newController(); + + controller.wipeTransactions(); + + const mockFromAccount1 = '0x1bf137f335ea1b8f193b8f6ea92561a60d23a207'; + const mockFromAccount2 = '0x2bf137f335ea1b8f193b8f6ea92561a60d23a207'; + const mockCurrentChainId = toHex(5); + + controller.state.transactions.push({ + id: '1', + chainId: mockCurrentChainId, + transaction: { + from: mockFromAccount1, + }, + } as any); + + controller.state.transactions.push({ + id: '2', + chainId: mockCurrentChainId, + transaction: { + from: mockFromAccount2, + }, + } as any); + + controller.wipeTransactions(true, mockFromAccount2); + + expect(controller.state.transactions).toHaveLength(1); + expect(controller.state.transactions[0].id).toBe('1'); + }); + + it('removes only txs with given address only on current network', async () => { + const controller = newController(); + + controller.wipeTransactions(); + + const mockFromAccount1 = '0x1bf137f335ea1b8f193b8f6ea92561a60d23a207'; + const mockDifferentChainId = toHex(1); + const mockCurrentChainId = toHex(5); + + controller.state.transactions.push({ + id: '1', + chainId: mockCurrentChainId, + transaction: { + from: mockFromAccount1, + }, + } as any); + + controller.state.transactions.push({ + id: '4', + chainId: mockDifferentChainId, + transaction: { + from: mockFromAccount1, + }, + } as any); + + controller.wipeTransactions(false, mockFromAccount1); + + expect(controller.state.transactions).toHaveLength(1); + expect(controller.state.transactions[0].id).toBe('4'); + }); }); describe('queryTransactionStatus', () => { @@ -1057,7 +1119,7 @@ describe('TransactionController', () => { const controller = newController(); controller.state.transactions.push({ - from: MOCK_PRFERENCES.state.selectedAddress, + from: MOCK_PREFERENCES.state.selectedAddress, id: 'foo', networkID: '5', chainId: toHex(5), @@ -1083,7 +1145,7 @@ describe('TransactionController', () => { const controller = newController(); controller.state.transactions.push({ - from: MOCK_PRFERENCES.state.selectedAddress, + from: MOCK_PREFERENCES.state.selectedAddress, id: 'foo', networkID: '5', status: TransactionStatus.submitted, @@ -1106,7 +1168,7 @@ describe('TransactionController', () => { const controller = newController(); controller.state.transactions.push({ - from: MOCK_PRFERENCES.state.selectedAddress, + from: MOCK_PREFERENCES.state.selectedAddress, id: 'foo', networkID: '5', status: TransactionStatus.submitted, @@ -1123,7 +1185,7 @@ describe('TransactionController', () => { const controller = newController(); controller.state.transactions.push({ - from: MOCK_PRFERENCES.state.selectedAddress, + from: MOCK_PREFERENCES.state.selectedAddress, id: 'foo', networkID: '5', chainId: toHex(5), diff --git a/packages/transaction-controller/src/TransactionController.ts b/packages/transaction-controller/src/TransactionController.ts index 22ad692a323..c20a993625c 100644 --- a/packages/transaction-controller/src/TransactionController.ts +++ b/packages/transaction-controller/src/TransactionController.ts @@ -789,10 +789,12 @@ export class TransactionController extends BaseController< * * @param ignoreNetwork - Determines whether to wipe all transactions, or just those on the * current network. If `true`, all transactions are wiped. + * @param address - If specified, only transactions originating from this address will be + * wiped on current network. */ - wipeTransactions(ignoreNetwork?: boolean) { + wipeTransactions(ignoreNetwork?: boolean, address?: string) { /* istanbul ignore next */ - if (ignoreNetwork) { + if (ignoreNetwork && !address) { this.update({ transactions: [] }); return; } @@ -800,12 +802,21 @@ export class TransactionController extends BaseController< this.getNetworkState(); const { chainId: currentChainId } = providerConfig; const newTransactions = this.state.transactions.filter( - ({ networkID, chainId }) => { + ({ networkID, chainId, transaction }) => { // Using fallback to networkID only when there is no chainId present. Should be removed when networkID is completely removed. - const isCurrentNetwork = + const isMatchingNetwork = + ignoreNetwork || chainId === currentChainId || (!chainId && networkID === currentNetworkID); - return !isCurrentNetwork; + + if (!isMatchingNetwork) { + return true; + } + + const isMatchingAddress = + !address || transaction.from?.toLowerCase() === address.toLowerCase(); + + return !isMatchingAddress; }, );