Skip to content

Commit 2476027

Browse files
Merge branch 'release/7.64.0' into upd-764-stable
2 parents 74ca9ca + 125a4ca commit 2476027

8 files changed

Lines changed: 191 additions & 71 deletions

File tree

android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ android {
188188
minSdkVersion rootProject.ext.minSdkVersion
189189
targetSdkVersion rootProject.ext.targetSdkVersion
190190
versionName "7.64.0"
191-
versionCode 3627
191+
versionCode 3630
192192
testBuildType System.getProperty('testBuildType', 'debug')
193193
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
194194
manifestPlaceholders.MM_BRANCH_KEY_TEST = "$System.env.MM_BRANCH_KEY_TEST"

app/components/Nav/Main/__snapshots__/MainNavigator.test.tsx.snap

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,39 @@ exports[`MainNavigator Tab Bar Visibility hides tab bar when browser is active 1
253253
}
254254
}
255255
/>
256+
<Screen
257+
component={[Function]}
258+
name="ExploreSearch"
259+
options={
260+
{
261+
"animationEnabled": true,
262+
"cardStyleInterpolator": [Function],
263+
"headerShown": false,
264+
}
265+
}
266+
/>
267+
<Screen
268+
component={[Function]}
269+
name="SitesFullView"
270+
options={
271+
{
272+
"animationEnabled": true,
273+
"cardStyleInterpolator": [Function],
274+
"headerShown": false,
275+
}
276+
}
277+
/>
278+
<Screen
279+
component={[Function]}
280+
name="BrowserTabHome"
281+
options={
282+
{
283+
"animationEnabled": true,
284+
"cardStyleInterpolator": [Function],
285+
"headerShown": false,
286+
}
287+
}
288+
/>
256289
<Screen
257290
component={[Function]}
258291
headerStyle={
@@ -571,6 +604,39 @@ exports[`MainNavigator Tab Bar Visibility shows tab bar when not in browser 1`]
571604
}
572605
}
573606
/>
607+
<Screen
608+
component={[Function]}
609+
name="ExploreSearch"
610+
options={
611+
{
612+
"animationEnabled": true,
613+
"cardStyleInterpolator": [Function],
614+
"headerShown": false,
615+
}
616+
}
617+
/>
618+
<Screen
619+
component={[Function]}
620+
name="SitesFullView"
621+
options={
622+
{
623+
"animationEnabled": true,
624+
"cardStyleInterpolator": [Function],
625+
"headerShown": false,
626+
}
627+
}
628+
/>
629+
<Screen
630+
component={[Function]}
631+
name="BrowserTabHome"
632+
options={
633+
{
634+
"animationEnabled": true,
635+
"cardStyleInterpolator": [Function],
636+
"headerShown": false,
637+
}
638+
}
639+
/>
574640
<Screen
575641
component={[Function]}
576642
headerStyle={
@@ -889,6 +955,39 @@ exports[`MainNavigator matches rendered snapshot 1`] = `
889955
}
890956
}
891957
/>
958+
<Screen
959+
component={[Function]}
960+
name="ExploreSearch"
961+
options={
962+
{
963+
"animationEnabled": true,
964+
"cardStyleInterpolator": [Function],
965+
"headerShown": false,
966+
}
967+
}
968+
/>
969+
<Screen
970+
component={[Function]}
971+
name="SitesFullView"
972+
options={
973+
{
974+
"animationEnabled": true,
975+
"cardStyleInterpolator": [Function],
976+
"headerShown": false,
977+
}
978+
}
979+
/>
980+
<Screen
981+
component={[Function]}
982+
name="BrowserTabHome"
983+
options={
984+
{
985+
"animationEnabled": true,
986+
"cardStyleInterpolator": [Function],
987+
"headerShown": false,
988+
}
989+
}
990+
/>
892991
<Screen
893992
component={[Function]}
894993
headerStyle={

app/selectors/assets/assets-list.test.ts

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { AccountGroupType, AccountWalletType } from '@metamask/account-api';
1+
import {
2+
AccountGroupId,
3+
AccountGroupType,
4+
AccountWalletType,
5+
} from '@metamask/account-api';
26
import {
37
EthAccountType,
48
SolAccountType,
@@ -733,25 +737,37 @@ describe('selectAsset', () => {
733737
});
734738
});
735739

736-
it('scopes native and staked lookups to selected account', () => {
737-
const stateWithSecondEvm = mockState();
738-
const account1Id =
739-
stateWithSecondEvm.engine.backgroundState.AccountsController
740-
.internalAccounts.selectedAccount;
740+
it('scopes native and staked lookups to selected account group', () => {
741+
const baseState = mockState();
742+
743+
// Account 1 info (already exists in mockState)
744+
const account1Id = 'd7f11451-9d79-4df4-a012-afd253443639';
745+
const group1Id = 'entropy:01K1TJY9QPSCKNBSVGZNG510GJ/0';
741746

747+
// Create second account group with different EVM account
742748
const account2Id = '11111111-1111-1111-1111-111111111111';
743749
const account2Address = '0x1111111111111111111111111111111111111111';
744750
const account2AddressLowercased = account2Address.toLowerCase();
751+
const group2Id = 'entropy:01K1TJY9QPSCKNBSVGZNG510GJ/1';
752+
const walletId = 'entropy:01K1TJY9QPSCKNBSVGZNG510GJ';
745753

746-
const withSelectedAccount = (
754+
const withSelectedGroup = (
747755
state: RootState,
756+
selectedGroup: AccountGroupId,
748757
selectedAccount: string,
749758
): RootState => ({
750759
...state,
751760
engine: {
752761
...state.engine,
753762
backgroundState: {
754763
...state.engine.backgroundState,
764+
AccountTreeController: {
765+
...state.engine.backgroundState.AccountTreeController,
766+
accountTree: {
767+
...state.engine.backgroundState.AccountTreeController.accountTree,
768+
selectedAccountGroup: selectedGroup,
769+
},
770+
},
755771
AccountsController: {
756772
...state.engine.backgroundState.AccountsController,
757773
internalAccounts: {
@@ -764,8 +780,8 @@ describe('selectAsset', () => {
764780
},
765781
});
766782

767-
// Add second EVM internal account into the same selected account group
768-
stateWithSecondEvm.engine.backgroundState.AccountsController.internalAccounts.accounts[
783+
// Add second EVM account to AccountsController
784+
baseState.engine.backgroundState.AccountsController.internalAccounts.accounts[
769785
account2Id
770786
] = {
771787
id: account2Id,
@@ -783,73 +799,75 @@ describe('selectAsset', () => {
783799
},
784800
};
785801

786-
const groupId = 'entropy:01K1TJY9QPSCKNBSVGZNG510GJ/0';
787-
const walletId = 'entropy:01K1TJY9QPSCKNBSVGZNG510GJ';
788-
stateWithSecondEvm.engine.backgroundState.AccountTreeController.accountTree.wallets[
802+
// Create second account group with the second EVM account
803+
baseState.engine.backgroundState.AccountTreeController.accountTree.wallets[
789804
walletId
790-
].groups[groupId].accounts = [
791-
...stateWithSecondEvm.engine.backgroundState.AccountTreeController
792-
.accountTree.wallets[walletId].groups[groupId].accounts,
793-
account2Id,
794-
];
805+
].groups[group2Id] = {
806+
id: group2Id,
807+
type: AccountGroupType.MultichainAccount,
808+
accounts: [account2Id],
809+
metadata: {
810+
name: 'Account Group 2',
811+
pinned: false,
812+
hidden: false,
813+
entropy: {
814+
groupIndex: 1,
815+
},
816+
},
817+
};
795818

796-
// Provide AccountTracker balances for second address on mainnet
797-
stateWithSecondEvm.engine.backgroundState.AccountTrackerController.accountsByChainId[
819+
// Provide AccountTracker balances for second account on mainnet
820+
baseState.engine.backgroundState.AccountTrackerController.accountsByChainId[
798821
'0x1'
799822
][account2AddressLowercased] = {
800823
balance: '0x0DE0B6B3A7640000', // 1 ETH
801824
stakedBalance: '0x1BC16D674EC80000', // 2 ETH
802825
};
803826

804-
// Provide empty token lists/balances for second address to keep asset building stable
805-
stateWithSecondEvm.engine.backgroundState.TokensController.allTokens['0x1'][
827+
// Provide empty token lists/balances for second address
828+
baseState.engine.backgroundState.TokensController.allTokens['0x1'][
806829
account2AddressLowercased
807830
] = [];
808-
stateWithSecondEvm.engine.backgroundState.TokensController.allTokens['0xa'][
831+
baseState.engine.backgroundState.TokensController.allTokens['0xa'][
809832
account2AddressLowercased
810833
] = [];
811834
(
812-
stateWithSecondEvm.engine.backgroundState.TokenBalancesController
835+
baseState.engine.backgroundState.TokenBalancesController
813836
.tokenBalances as Record<string, unknown>
814837
)[account2AddressLowercased] = {};
815838

816-
// Sanity check: original account still resolves correctly
817-
const stateForAccount1 = withSelectedAccount(
818-
stateWithSecondEvm,
819-
account1Id,
820-
);
839+
// Test Group 1: should return account 1 balances
840+
const stateForGroup1 = withSelectedGroup(baseState, group1Id, account1Id);
821841

822-
const stakedForAccount1 = selectAsset(stateForAccount1, {
842+
const stakedForGroup1 = selectAsset(stateForGroup1, {
823843
address: '0x0000000000000000000000000000000000000000',
824844
chainId: '0x1',
825845
isStaked: true,
826846
});
827-
expect(stakedForAccount1?.balance).toBe('100');
847+
expect(stakedForGroup1?.balance).toBe('100');
848+
expect(stakedForGroup1?.balanceFiat).toBe('$240,000.00');
828849

829-
// Switch selected account → balances should follow
830-
const stateForAccount2 = withSelectedAccount(
831-
stateWithSecondEvm,
832-
account2Id,
833-
);
850+
// Test Group 2: should return account 2 balances
851+
const stateForGroup2 = withSelectedGroup(baseState, group2Id, account2Id);
834852

835-
const nativeForAccount2 = selectAsset(stateForAccount2, {
853+
const nativeForGroup2 = selectAsset(stateForGroup2, {
836854
address: '0x0000000000000000000000000000000000000000',
837855
chainId: '0x1',
838856
isStaked: false,
839857
});
840-
expect(nativeForAccount2).toMatchObject({
858+
expect(nativeForGroup2).toMatchObject({
841859
name: 'Ethereum',
842860
balance: '1',
843861
balanceFiat: '$2,400.00',
844862
isStaked: false,
845863
});
846864

847-
const stakedForAccount2 = selectAsset(stateForAccount2, {
865+
const stakedForGroup2 = selectAsset(stateForGroup2, {
848866
address: '0x0000000000000000000000000000000000000000',
849867
chainId: '0x1',
850868
isStaked: true,
851869
});
852-
expect(stakedForAccount2).toMatchObject({
870+
expect(stakedForGroup2).toMatchObject({
853871
name: 'Staked Ethereum',
854872
balance: '2',
855873
balanceFiat: '$4,800.00',

app/selectors/assets/assets-list.ts

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@ import {
44
getNativeTokenAddress,
55
TokenListState,
66
} from '@metamask/assets-controllers';
7-
import { MULTICHAIN_NETWORK_DECIMAL_PLACES } from '@metamask/multichain-network-controller';
8-
import { CaipChainId, Hex, hexToBigInt } from '@metamask/utils';
7+
import {
8+
MULTICHAIN_NETWORK_DECIMAL_PLACES,
9+
toEvmCaipChainId,
10+
} from '@metamask/multichain-network-controller';
11+
import { CaipChainId, Hex, hexToBigInt, isCaipChainId } from '@metamask/utils';
912
import { createSelector } from 'reselect';
1013

1114
import I18n from '../../../locales/i18n';
@@ -28,10 +31,8 @@ import {
2831
} from '../../core/Multichain/constants';
2932
import { sortAssetsWithPriority } from '../../components/UI/Tokens/util/sortAssetsWithPriority';
3033
import { selectAllTokens } from '../tokensController';
31-
import {
32-
selectSelectedInternalAccountAddress,
33-
selectSelectedInternalAccountId,
34-
} from '../accountsController';
34+
import { selectSelectedInternalAccountAddress } from '../accountsController';
35+
import { selectSelectedInternalAccountByScope } from '../multichainAccounts/accounts';
3536

3637
const getStateForAssetSelector = (state: RootState) => {
3738
const {
@@ -267,7 +268,7 @@ export const selectAsset = createSelector(
267268
state.engine.backgroundState.TokenListController.tokensChainsCache,
268269
selectAllTokens,
269270
selectSelectedInternalAccountAddress,
270-
selectSelectedInternalAccountId,
271+
selectSelectedInternalAccountByScope,
271272
(
272273
_state: RootState,
273274
params: { address: string; chainId: string; isStaked?: boolean },
@@ -287,37 +288,31 @@ export const selectAsset = createSelector(
287288
tokensChainsCache,
288289
allTokens,
289290
selectedAddress,
290-
selectedAccountId,
291+
getAccountByScope,
291292
address,
292293
chainId,
293294
isStaked,
294295
) => {
295-
/**
296-
* Note: Without this, the selector would return the wrong asset for the selected account on EVM chains.
297-
* This caused Staked Ethereum to not update when switching accounts.
298-
* We want to apply this to EVM chains only.
299-
*/
300-
const shouldScopeToSelectedAccount =
301-
Boolean(selectedAccountId) && typeof chainId === 'string'
302-
? chainId.startsWith('0x')
303-
: false;
296+
const chainIdInCaip = isCaipChainId(chainId)
297+
? chainId
298+
: toEvmCaipChainId(chainId as Hex);
299+
300+
// Get the account for this chain from the selected account group
301+
const scopedAccountId = getAccountByScope(chainIdInCaip)?.id;
304302

305303
const asset = isStaked
306304
? stakedAssets.find(
307305
(item) =>
308306
item.chainId === chainId &&
309-
(!shouldScopeToSelectedAccount ||
310-
item.accountId === selectedAccountId) &&
307+
(!scopedAccountId || item.accountId === scopedAccountId) &&
311308
item.stakedAsset.assetId === address,
312309
)?.stakedAsset
313310
: assets[chainId]?.find((item: Asset & { isStaked?: boolean }) => {
314-
// Normalize isStaked values: treat undefined as false
315311
const itemIsStaked = Boolean(item.isStaked);
316312
const targetIsStaked = Boolean(isStaked);
317313
return (
318314
item.assetId === address &&
319-
(!shouldScopeToSelectedAccount ||
320-
item.accountId === selectedAccountId) &&
315+
(!scopedAccountId || item.accountId === scopedAccountId) &&
321316
itemIsStaked === targetIsStaked
322317
);
323318
});

app/selectors/featureFlagController/assetsTrendingTokens/index.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ jest.mock('../../../core/Engine', () => ({
1212
init: () => mockedEngine.init(),
1313
}));
1414

15+
jest.mock('../../../util/test/utils', () => ({
16+
isE2E: true,
17+
}));
18+
1519
beforeEach(() => {
1620
jest.clearAllMocks();
1721
});

0 commit comments

Comments
 (0)