Skip to content

Commit e7dcf8b

Browse files
n3psCopilot
andcommitted
cleanup
Co-authored-by: Copilot <copilot@github.com>
1 parent 308115d commit e7dcf8b

4 files changed

Lines changed: 84 additions & 76 deletions

File tree

app/components/Views/UnifiedTransactionsView/UnifiedTransactionsView.tsx

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,6 @@ const UnifiedTransactionsView = ({
138138
const selectedAccountGroupInternalAccounts = useSelector(
139139
selectSelectedAccountGroupInternalAccounts,
140140
);
141-
const selectedAccountGroupInternalAccountsAddresses =
142-
selectedAccountGroupInternalAccounts.map((account) => account.address);
143141
const selectedAccountGroupEvmAddress = useMemo(() => {
144142
const evmAccount = selectedAccountGroupInternalAccounts.find(
145143
(account) =>
@@ -181,52 +179,36 @@ const UnifiedTransactionsView = ({
181179
evmConfirmedItems: UnifiedItem[];
182180
chainFilteredNonEvmTransactionsForSelectedChain: NonEvmTransaction[];
183181
}>(() => {
184-
// Deduplicate submitted by (address + chain + nonce) and drop if already confirmed
185-
const seenSubmittedNonces = new Set<string>();
186-
const submittedTxsFiltered = submittedTxs.filter((tx): tx is EvmTransaction => {
187-
if (!isEvmTransaction(tx)) {
188-
return false;
189-
}
190-
191-
const { chainId: _chainId, txParams } = tx;
192-
const hash = 'hash' in tx ? tx.hash : undefined;
193-
const { from, nonce, actionId } = txParams || {};
194-
// Some txs don't have nonce, like intent based swaps
195-
const hasNonce = nonce !== undefined && nonce !== null;
196-
if (
197-
!selectedAccountGroupInternalAccountsAddresses.some((addr) =>
198-
areAddressesEqual(from, addr),
199-
)
200-
) {
201-
return false;
202-
}
203-
const dedupeKeyPrefix = `${_chainId}-${String(from).toLowerCase()}`;
204-
const dedupeKey = hasNonce
205-
? `${dedupeKeyPrefix}-${nonce}`
206-
: `${dedupeKeyPrefix}-${actionId}`;
207-
if (seenSubmittedNonces.has(dedupeKey)) {
208-
return false;
209-
}
182+
const submittedTxsFiltered = submittedTxs.filter(
183+
(tx): tx is EvmTransaction => {
184+
if (!isEvmTransaction(tx)) {
185+
return false;
186+
}
210187

211-
const alreadyConfirmed = allConfirmedFiltered.find(
212-
(confirmedTx) =>
213-
(typeof hash === 'string' &&
214-
confirmedTx.hash.toLowerCase() === hash.toLowerCase() &&
215-
confirmedTx.txChainId === _chainId) ||
216-
(hasNonce &&
217-
confirmedTx.nonce === nonce &&
218-
confirmedTx.txChainId === _chainId &&
219-
Boolean(from) &&
220-
areAddressesEqual(confirmedTx.from, from)),
221-
);
188+
const { chainId: _chainId, txParams } = tx;
189+
const hash = 'hash' in tx ? tx.hash : undefined;
190+
const { from, nonce } = txParams || {};
191+
const hasNonce = nonce !== undefined && nonce !== null;
192+
193+
const alreadyConfirmed = allConfirmedFiltered.find(
194+
(confirmedTx) =>
195+
(typeof hash === 'string' &&
196+
confirmedTx.hash.toLowerCase() === hash.toLowerCase() &&
197+
confirmedTx.txChainId === _chainId) ||
198+
(hasNonce &&
199+
confirmedTx.nonce === nonce &&
200+
confirmedTx.txChainId === _chainId &&
201+
Boolean(from) &&
202+
areAddressesEqual(confirmedTx.from, from)),
203+
);
222204

223-
if (alreadyConfirmed) {
224-
return false;
225-
}
205+
if (alreadyConfirmed) {
206+
return false;
207+
}
226208

227-
seenSubmittedNonces.add(dedupeKey);
228-
return true;
229-
});
209+
return true;
210+
},
211+
);
230212

231213
// EVM: pending/submitted first (desc), then confirmed (dedup outgoing)
232214
const evmPendingFirst = [...submittedTxsFiltered].sort(
@@ -271,7 +253,6 @@ const UnifiedTransactionsView = ({
271253
allConfirmedFiltered,
272254
submittedTxs,
273255
nonEvmTransactions,
274-
selectedAccountGroupInternalAccountsAddresses,
275256
enabledEVMChainIds,
276257
enabledNonEVMChainIds,
277258
bridgeHistory,

app/selectors/multichainAccounts/accountTreeController.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -430,13 +430,13 @@ export const selectAccountGroupEvmAccountAddresses = createSelector(
430430
[selectSelectedInternalAccount, selectAccountGroupEvmInternalAccounts],
431431
(selectedInternalAccount, groupEvmAccounts) => {
432432
const selectedEvmAccount =
433-
selectedInternalAccount &&
434-
isEvmAccountType(selectedInternalAccount.type)
435-
? selectedInternalAccount
436-
: (groupEvmAccounts.find(
437-
(account) =>
438-
account.type === 'eip155:eoa' || account.type === 'eip155:erc4337',
439-
) ?? groupEvmAccounts[0]);
433+
selectedInternalAccount && isEvmAccountType(selectedInternalAccount.type)
434+
? selectedInternalAccount
435+
: (groupEvmAccounts.find(
436+
(account) =>
437+
account.type === 'eip155:eoa' ||
438+
account.type === 'eip155:erc4337',
439+
) ?? groupEvmAccounts[0]);
440440

441441
if (!selectedEvmAccount?.address) {
442442
return EMPTY_ARR as readonly CaipAccountId[];
@@ -470,6 +470,6 @@ export const selectSelectedAccountGroupWithInternalAccountsAddresses =
470470
}
471471
return null;
472472
})
473-
.filter(Boolean);
473+
.filter((address): address is string => Boolean(address));
474474
},
475475
);

app/selectors/transactionController.ts

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import {
55
selectPendingSmartTransactionsBySender,
66
selectPendingSmartTransactionsForSelectedAccountGroup,
77
} from './smartTransactionsController';
8-
import { selectSelectedAccountGroupInternalAccounts } from './multichainAccounts/accountTreeController';
8+
import { selectSelectedAccountGroupWithInternalAccountsAddresses } from './multichainAccounts/accountTreeController';
99
import {
1010
TransactionMeta,
1111
TransactionType,
1212
} from '@metamask/transaction-controller';
13+
import { SmartTransaction } from '@metamask/smart-transactions-controller';
1314
import { Hex } from '@metamask/utils';
1415
import { areAddressesEqual } from '../util/address';
1516

@@ -18,14 +19,49 @@ interface MetaMaskPayToken {
1819
chainId: Hex;
1920
}
2021

21-
const PENDING_EVM_TRANSACTION_STATUSES = new Set([
22+
type LocalTransaction = TransactionMeta | SmartTransaction;
23+
24+
const transactionPendingStatuses = new Set([
2225
'submitted',
2326
'signed',
2427
'unapproved',
2528
'approved',
2629
'pending',
2730
]);
2831

32+
function dedupeTransactions(
33+
transactions: LocalTransaction[],
34+
addresses: readonly string[],
35+
) {
36+
const seenTransactions = new Set<string>();
37+
38+
return transactions.filter((transaction) => {
39+
const { chainId, txParams } = transaction;
40+
const { from, nonce, actionId } = txParams || {};
41+
const hasNonce = nonce !== undefined && nonce !== null;
42+
43+
if (
44+
!from ||
45+
!addresses.some((address) => areAddressesEqual(from, address || ''))
46+
) {
47+
return false;
48+
}
49+
50+
// Extracted from UnifiedTransactionsView
51+
const dedupeKeyPrefix = `${chainId}-${String(from).toLowerCase()}`;
52+
const dedupeKey = hasNonce
53+
? `${dedupeKeyPrefix}-${nonce}`
54+
: `${dedupeKeyPrefix}-${actionId}`;
55+
56+
if (seenTransactions.has(dedupeKey)) {
57+
return false;
58+
}
59+
60+
seenTransactions.add(dedupeKey);
61+
return true;
62+
});
63+
}
64+
2965
function getNestedTransactionTypes(
3066
transaction: TransactionMeta,
3167
): TransactionType[] {
@@ -139,20 +175,13 @@ export const selectLocalTransactions = createDeepEqualSelector(
139175
[
140176
selectNonReplacedTransactions,
141177
selectPendingSmartTransactionsForSelectedAccountGroup,
142-
selectSelectedAccountGroupInternalAccounts,
178+
selectSelectedAccountGroupWithInternalAccountsAddresses,
143179
],
144-
(
145-
nonReplacedTransactions,
146-
pendingSmartTransactions,
147-
selectedAccountGroupInternalAccounts,
148-
) => {
149-
const selectedAddresses = selectedAccountGroupInternalAccounts
150-
.map((account) => account.address)
151-
.filter(Boolean);
152-
180+
(nonReplacedTransactions, pendingSmartTransactions, addresses) => {
153181
const pendingTransactions = nonReplacedTransactions.filter(
154182
(transaction) => {
155-
if (!PENDING_EVM_TRANSACTION_STATUSES.has(transaction.status)) {
183+
// Extracted from UnifiedTransactionsView submittedTxs filter
184+
if (!transactionPendingStatuses.has(transaction.status)) {
156185
return false;
157186
}
158187

@@ -161,15 +190,17 @@ export const selectLocalTransactions = createDeepEqualSelector(
161190
return false;
162191
}
163192

164-
return selectedAddresses.some((address) =>
193+
// Extracted from UnifiedTransactionsView submittedTxsFiltered filter
194+
return addresses.some((address) =>
165195
areAddressesEqual(fromAddress, address),
166196
);
167197
},
168198
);
169199

170-
return [...pendingTransactions, ...pendingSmartTransactions].sort(
171-
(a, b) => (b?.time ?? 0) - (a?.time ?? 0),
172-
);
200+
return dedupeTransactions(
201+
[...pendingTransactions, ...pendingSmartTransactions],
202+
addresses,
203+
).sort((a, b) => (b?.time ?? 0) - (a?.time ?? 0));
173204
},
174205
);
175206

tests/api-mocking/helpers/mockHelpers.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,17 +465,13 @@ export async function setupAccountsV2SupportedNetworksMock(
465465

466466
/**
467467
* Registers a default empty history response for Accounts API v4 transactions.
468-
* Tests that need activity rows can override this with a test-specific mock.
469468
*/
470-
export async function setupAccountsV4TransactionsMock(
471-
server: Mockttp,
472-
): Promise<void> {
469+
export async function setupAccountsV4TransactionsMock(server: Mockttp) {
473470
await setupMockRequest(server, {
474471
requestMethod: 'GET',
475472
url: /^https:\/\/accounts\.api\.cx\.metamask\.io\/v4\/multiaccount\/transactions(\?.*)?$/,
476473
response: {
477474
data: [],
478-
unprocessedNetworks: [],
479475
pageInfo: {
480476
count: 0,
481477
hasNextPage: false,

0 commit comments

Comments
 (0)