Skip to content

Commit 8b535db

Browse files
committed
refactor: update multichain address sorting logic and tests
1 parent 1cda10b commit 8b535db

File tree

4 files changed

+102
-18
lines changed

4 files changed

+102
-18
lines changed

app/component-library/components-temp/MultichainAccounts/MultichainAddressRowsList/MultichainAddressRowsList.utils.test.ts

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { InternalAccount } from '@metamask/keyring-internal-api';
22
import { CHAIN_IDS } from '@metamask/transaction-controller';
3-
import { SolScope } from '@metamask/keyring-api';
3+
import { SolScope, BtcScope, TrxScope } from '@metamask/keyring-api';
44
import { CaipChainId } from '@metamask/utils';
55
import {
66
sortNetworkAddressItems,
@@ -62,7 +62,7 @@ describe('MultichainAddressRowsList Utils', () => {
6262
expect(sorted[0].chainId).toBe(`eip155:${CHAIN_IDS.MAINNET}`);
6363
});
6464

65-
it('sorts networks with Solana second after Ethereum', () => {
65+
it('sorts networks with Bitcoin second and Solana third after Ethereum', () => {
6666
const items: NetworkAddressItem[] = [
6767
{ chainId: 'eip155:0x89', networkName: 'Polygon', address: '0x123' },
6868
{ chainId: SolScope.Mainnet, networkName: 'Solana', address: '0x123' },
@@ -71,11 +71,59 @@ describe('MultichainAddressRowsList Utils', () => {
7171
networkName: 'Ethereum',
7272
address: '0x123',
7373
},
74+
{ chainId: BtcScope.Mainnet, networkName: 'Bitcoin', address: '0x123' },
7475
];
7576

7677
const sorted = sortNetworkAddressItems(items);
7778
expect(sorted[0].chainId).toBe(`eip155:${CHAIN_IDS.MAINNET}`);
78-
expect(sorted[1].chainId).toBe(SolScope.Mainnet);
79+
expect(sorted[1].chainId).toBe(BtcScope.Mainnet);
80+
expect(sorted[2].chainId).toBe(SolScope.Mainnet);
81+
});
82+
83+
it('sorts networks with Tron fourth after Ethereum, Bitcoin, and Solana', () => {
84+
const items: NetworkAddressItem[] = [
85+
{ chainId: TrxScope.Mainnet, networkName: 'Tron', address: '0x123' },
86+
{ chainId: 'eip155:0x89', networkName: 'Polygon', address: '0x123' },
87+
{ chainId: SolScope.Mainnet, networkName: 'Solana', address: '0x123' },
88+
{
89+
chainId: `eip155:${CHAIN_IDS.MAINNET}`,
90+
networkName: 'Ethereum',
91+
address: '0x123',
92+
},
93+
{ chainId: BtcScope.Mainnet, networkName: 'Bitcoin', address: '0x123' },
94+
];
95+
96+
const sorted = sortNetworkAddressItems(items);
97+
expect(sorted[0].chainId).toBe(`eip155:${CHAIN_IDS.MAINNET}`);
98+
expect(sorted[1].chainId).toBe(BtcScope.Mainnet);
99+
expect(sorted[2].chainId).toBe(SolScope.Mainnet);
100+
expect(sorted[3].chainId).toBe(TrxScope.Mainnet);
101+
});
102+
103+
it('sorts networks with Linea fifth after Ethereum, Bitcoin, Solana, and Tron', () => {
104+
const items: NetworkAddressItem[] = [
105+
{
106+
chainId: `eip155:${CHAIN_IDS.LINEA_MAINNET}`,
107+
networkName: 'Linea',
108+
address: '0x123',
109+
},
110+
{ chainId: TrxScope.Mainnet, networkName: 'Tron', address: '0x123' },
111+
{ chainId: 'eip155:0x89', networkName: 'Polygon', address: '0x123' },
112+
{ chainId: SolScope.Mainnet, networkName: 'Solana', address: '0x123' },
113+
{
114+
chainId: `eip155:${CHAIN_IDS.MAINNET}`,
115+
networkName: 'Ethereum',
116+
address: '0x123',
117+
},
118+
{ chainId: BtcScope.Mainnet, networkName: 'Bitcoin', address: '0x123' },
119+
];
120+
121+
const sorted = sortNetworkAddressItems(items);
122+
expect(sorted[0].chainId).toBe(`eip155:${CHAIN_IDS.MAINNET}`);
123+
expect(sorted[1].chainId).toBe(BtcScope.Mainnet);
124+
expect(sorted[2].chainId).toBe(SolScope.Mainnet);
125+
expect(sorted[3].chainId).toBe(TrxScope.Mainnet);
126+
expect(sorted[4].chainId).toBe(`eip155:${CHAIN_IDS.LINEA_MAINNET}`);
79127
});
80128

81129
it('sorts test networks last', () => {

app/component-library/components-temp/MultichainAccounts/MultichainAddressRowsList/MultichainAddressRowsList.utils.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { InternalAccount } from '@metamask/keyring-internal-api';
22
import { CHAIN_IDS } from '@metamask/transaction-controller';
3-
import { SolScope } from '@metamask/keyring-api';
3+
import { SolScope, BtcScope, TrxScope } from '@metamask/keyring-api';
44
import { CaipChainId } from '@metamask/utils';
55
import { TEST_NETWORK_IDS } from '../../../../constants/network';
66
import { PopularList } from '../../../../util/networks/customNetworks';
@@ -18,7 +18,12 @@ export interface NetworkAddressItem {
1818
*/
1919
const extractHexChainId = (chainId: CaipChainId): string => {
2020
if (chainId.startsWith('eip155:')) {
21-
return chainId.split(':')[1];
21+
const chainIdPart = chainId.split(':')[1];
22+
// Convert decimal to hex format if needed (CAIP format uses decimal)
23+
if (!chainIdPart.startsWith('0x')) {
24+
return `0x${parseInt(chainIdPart, 10).toString(16)}`;
25+
}
26+
return chainIdPart;
2227
}
2328
return chainId;
2429
};
@@ -33,30 +38,40 @@ const getNetworkPriority = (chainId: CaipChainId): number => {
3338
// For EVM networks, extract hex chain ID for comparison
3439
const hexChainId = extractHexChainId(chainId);
3540

41+
// Hardcoded order for top networks
3642
if (hexChainId === CHAIN_IDS.MAINNET) {
3743
return 0;
3844
} // Ethereum first
39-
if (chainId === SolScope.Mainnet) {
45+
if (chainId === BtcScope.Mainnet) {
4046
return 1;
41-
} // Solana second
47+
} // Bitcoin second
48+
if (chainId === SolScope.Mainnet) {
49+
return 2;
50+
} // Solana third
51+
if (chainId === TrxScope.Mainnet) {
52+
return 3;
53+
} // Tron fourth
54+
if (hexChainId === CHAIN_IDS.LINEA_MAINNET) {
55+
return 4;
56+
} // Linea fifth
4257
if (
4358
TEST_NETWORK_IDS.includes(hexChainId as (typeof TEST_NETWORK_IDS)[number])
4459
) {
45-
return 4;
60+
return 7;
4661
} // Test networks last
4762

4863
// Featured networks (popular networks)
4964
const popularChainIds = PopularList.map((network) => network.chainId);
5065
if (popularChainIds.includes(hexChainId as `0x${string}`)) {
51-
return 2;
66+
return 5;
5267
}
5368

54-
return 3; // Other custom networks
69+
return 6; // Other custom networks
5570
};
5671

5772
/**
5873
* Sorts network address items according to priority:
59-
* 1. Ethereum first, 2. Solana second, 3. Featured networks, 4. Other custom networks, 5. Test networks last
74+
* 1. Ethereum, 2. Bitcoin, 3. Solana, 4. Tron, 5. Linea, 6. Featured networks, 7. Other custom networks, 8. Test networks last
6075
*
6176
* @param items - Array of NetworkAddressItem objects to sort
6277
* @returns Sorted array of NetworkAddressItem objects

app/selectors/multichainAccounts/accounts.test.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,26 +1393,27 @@ describe('accounts selectors', () => {
13931393
selectInternalAccountListSpreadByScopesByGroupId(mockState)(
13941394
ENTROPY_GROUP_ID,
13951395
);
1396+
// Results should be sorted: Ethereum (priority 0), Solana (priority 2), then other networks alphabetically
13961397
expect(result).toEqual([
13971398
{
13981399
account: mockEvmAccount,
13991400
scope: 'eip155:1',
14001401
networkName: 'Ethereum',
14011402
},
14021403
{
1403-
account: mockEvmAccount,
1404-
scope: 'eip155:33875',
1405-
networkName: 'Base',
1404+
account: mockSolanaAccount,
1405+
scope: SOLANA_MAINNET_SCOPE,
1406+
networkName: 'Solana Mainnet',
14061407
},
14071408
{
14081409
account: mockEvmAccount,
14091410
scope: 'eip155:270689',
14101411
networkName: 'Arbitrum One',
14111412
},
14121413
{
1413-
account: mockSolanaAccount,
1414-
scope: SOLANA_MAINNET_SCOPE,
1415-
networkName: 'Solana Mainnet',
1414+
account: mockEvmAccount,
1415+
scope: 'eip155:33875',
1416+
networkName: 'Base',
14161417
},
14171418
]);
14181419
});

app/selectors/multichainAccounts/accounts.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
} from '../networkController';
2222
import { TEST_NETWORK_IDS } from '../../constants/network';
2323
import type { AccountGroupWithInternalAccounts } from './accounts.type';
24+
import { sortNetworkAddressItems } from '../../component-library/components-temp/MultichainAccounts/MultichainAddressRowsList/MultichainAddressRowsList.utils';
2425

2526
/**
2627
* Extracts the wallet ID from an account group ID.
@@ -282,7 +283,7 @@ export const selectInternalAccountListSpreadByScopesByGroupId =
282283
return (groupId: AccountGroupId) => {
283284
const accounts = internalAccounts(groupId);
284285

285-
return accounts.flatMap((account) => {
286+
const items = accounts.flatMap((account) => {
286287
// Determine scopes based on account type
287288
const scopes =
288289
account.type === EthAccountType.Eoa
@@ -299,6 +300,25 @@ export const selectInternalAccountListSpreadByScopesByGroupId =
299300
networkConfigurations[scope]?.name || 'Unknown Network',
300301
}));
301302
});
303+
304+
// Sort items using the same sorting logic as MultichainAddressRowsList
305+
const sortedItems = sortNetworkAddressItems(
306+
items.map((item) => ({
307+
chainId: item.scope,
308+
networkName: item.networkName,
309+
address: item.account.address,
310+
})),
311+
);
312+
313+
// Map back to the original format with sorted order
314+
return sortedItems.map((sortedItem) => {
315+
const originalItem = items.find(
316+
(item) =>
317+
item.scope === sortedItem.chainId &&
318+
item.account.address === sortedItem.address,
319+
);
320+
return originalItem ?? sortedItem;
321+
});
302322
};
303323
},
304324
);

0 commit comments

Comments
 (0)