Skip to content

Commit 5180a8c

Browse files
authored
chore: remove MM_REMOVE_GLOBAL_NETWORK_SELECTOR from hooks, lists, and control bars (MetaMask#22574)
## **Description** This is part of a series of PRs removing the `MM_REMOVE_GLOBAL_NETWORK_SELECTOR` feature flag. **Master PR for reference:** MetaMask#22067 This PR removes the feature flag from hooks, list components, control bars, and navigation components. The changes enable Network Manager behavior by default across all affected components. #### Key Changes: **Hooks:** - `useTransactionConfirm` - Now always calls `tryEnableEvmNetwork` after transaction confirmation - `useExistingAddress` - Always filters addresses across all enabled networks - `useSelectedAccountMultichainBalances` - Uses `selectEVMEnabledNetworks` to calculate balances - `useNetworkSwitch` - Removed feature flag from test mocks **Control Bars:** - `BaseControlBar` - Removed feature flag logic, always navigates to Network Manager - `TokenListControlBar` - Removed conditional navigation, always shows enabled networks - `DeFiPositionsControlBar` - Always navigates to Network Manager instead of TokenFilter **List Components:** - `DeFiPositionsList` - Always uses `selectDefiPositionsByEnabledNetworks` selector - `TokenFilterBottomSheet` - Always calls `selectNetwork` for Network Manager integration **Navigation:** - `Navbar` - Removed old `PickerNetwork` component and feature flag checks - `ActivityView` - Removed feature flag import and conditional logic - `Wallet` - Updated to use Network Manager behavior #### Test Updates: - Removed all `isRemoveGlobalNetworkSelectorEnabled` feature flag mocks - Removed obsolete test cases that covered old behavior (flag OFF) - Updated test descriptions from "when feature flag is enabled/disabled" to describe actual behavior - Fixed duplicate test in `useExistingAddress.test.ts` with stale feature flag reference #### Behavior Change: The default behavior is now equivalent to the feature flag being ON. All components use Network Manager with `NetworkEnablementController` to determine enabled networks instead of relying on the feature flag or legacy network selection logic. ## **Changelog** CHANGELOG entry: Removed `MM_REMOVE_GLOBAL_NETWORK_SELECTOR` feature flag from hooks, list components, control bars, and navigation. Components now use Network Manager behavior by default. ## **Related issues** Fixes: Fixes: https://consensyssoftware.atlassian.net/browse/MUL-1132 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** `~` ### **Before** `~` ### **After** `~` ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Removes the MM_REMOVE_GLOBAL_NETWORK_SELECTOR flag and makes Network Manager the default across hooks, lists, navbars, and activity view, updating logic, styles, and tests accordingly. > > - **Network Manager as default**: > - Navigation and UI now always route filter actions to `NetworkManager` (replaces `TokenFilter` flows). > - Removed `PickerNetwork` usage and related flag checks in `Navbar` and `ActivityView`. > - **Hooks**: > - `useTransactionConfirm`: always calls `tryEnableEvmNetwork(chainId)` post-confirm. > - `useExistingAddress`: always aggregates `AddressBook` across networks. > - `useSelectedAccountMultichainBalances`: aggregates via `selectEVMEnabledNetworks` and always across enabled EVM chains. > - `useNetworkSwitch` tests simplified to remove flag logic. > - **Lists and Filters**: > - `DeFiPositionsList`: always uses `selectDefiPositionsByEnabledNetworks` for data. > - `TokenFilterBottomSheet`: always updates Preferences and calls `selectNetwork`. > - **Control Bars**: > - `BaseControlBar`, `TokenListControlBar`, `DeFiPositionsControlBar`: remove flag branches; always show enabled networks label and navigate to `NetworkManager`. > - **Styles**: > - Control bar button styles standardized (always bordered, rounded, padded). > - **Tests/Snapshots**: > - Removed flag mocks and obsolete cases; updated expectations to `NetworkManager` navigation and new labels/styles. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 750c2cd. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 27e3f35 commit 5180a8c

22 files changed

Lines changed: 299 additions & 931 deletions

app/components/Nav/Main/index.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,8 @@ import { useConnectionHandler } from '../../../util/navigation/useConnectionHand
8383
import { getGlobalEthQuery } from '../../../util/networks/global-network';
8484
import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetworkController';
8585
import { selectEVMEnabledNetworks } from '../../../selectors/networkEnablementController';
86-
import { isRemoveGlobalNetworkSelectorEnabled } from '../../../util/networks';
8786
import { useIdentityEffects } from '../../../util/identity/hooks/useIdentityEffects/useIdentityEffects';
8887
import ProtectWalletMandatoryModal from '../../Views/ProtectWalletMandatoryModal/ProtectWalletMandatoryModal';
89-
import InfoNetworkModal from '../../Views/InfoNetworkModal/InfoNetworkModal';
9088
import { selectIsSeedlessPasswordOutdated } from '../../../selectors/seedlessOnboardingController';
9189
import { Authentication } from '../../../core';
9290
import { IconName } from '../../../component-library/components/Icons/Icon';
@@ -98,7 +96,6 @@ import {
9896
} from '../../hooks/useNetworksByNamespace/useNetworksByNamespace';
9997
import { useNetworkSelection } from '../../hooks/useNetworkSelection/useNetworkSelection';
10098
import { useIsOnBridgeRoute } from '../../UI/Bridge/hooks/useIsOnBridgeRoute';
101-
import { handleShowNetworkActiveToast } from './utils';
10299
import { CardVerification } from '../../UI/Card/sdk';
103100

104101
const Stack = createStackNavigator();
@@ -301,10 +298,7 @@ const Main = (props) => {
301298
[chainId]: true,
302299
});
303300
}
304-
if (
305-
isRemoveGlobalNetworkSelectorEnabled() &&
306-
enabledEVMNetworks.length === 0
307-
) {
301+
if (enabledEVMNetworks.length === 0) {
308302
selectNetwork(chainId);
309303
}
310304
}

app/components/UI/DeFiPositions/DeFiPositionsControlBar.test.tsx

Lines changed: 4 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { CHAIN_IDS } from '@metamask/transaction-controller';
88

99
jest.mock('../../../util/networks', () => ({
1010
...jest.requireActual('../../../util/networks'),
11-
isRemoveGlobalNetworkSelectorEnabled: jest.fn().mockReturnValue(false),
1211
isTestNet: jest.fn().mockReturnValue(false),
1312
}));
1413

@@ -160,60 +159,7 @@ describe('DeFiPositionsControlBar', () => {
160159
expect(getByTestId('defi-positions-network-filter')).toBeDefined();
161160
});
162161

163-
it('should show current network name when isRemoveGlobalNetworkSelectorEnabled is false and single network', () => {
164-
const mockState = createMockState({
165-
engine: {
166-
backgroundState: {
167-
NetworkController: {
168-
provider: {
169-
chainId: CHAIN_IDS.MAINNET,
170-
type: 'mainnet',
171-
},
172-
},
173-
MultichainNetworkController: {
174-
isEvmSelected: true,
175-
},
176-
PreferencesController: {
177-
selectedAddress: '0x123',
178-
},
179-
},
180-
},
181-
});
182-
183-
store = mockStore(mockState);
184-
185-
const { getByText } = render(
186-
<Provider store={store}>
187-
<DeFiPositionsControlBar />
188-
</Provider>,
189-
);
190-
191-
expect(getByText('Ethereum Mainnet')).toBeDefined();
192-
});
193-
194-
it('should show popular networks text when isRemoveGlobalNetworkSelectorEnabled is false and isAllNetworks is true', () => {
195-
const mockState = createMockState();
196-
store = mockStore(mockState);
197-
198-
const networkControllerModule = jest.requireMock(
199-
'../../../selectors/networkController',
200-
);
201-
networkControllerModule.selectIsAllNetworks = () => true;
202-
networkControllerModule.selectIsPopularNetwork = () => true;
203-
204-
const { getByText } = render(
205-
<Provider store={store}>
206-
<DeFiPositionsControlBar />
207-
</Provider>,
208-
);
209-
210-
expect(getByText(strings('wallet.popular_networks'))).toBeDefined();
211-
});
212-
213-
it('should show enabled networks text when isRemoveGlobalNetworkSelectorEnabled is true and multiple networks enabled', () => {
214-
const networksModule = jest.requireMock('../../../util/networks');
215-
networksModule.isRemoveGlobalNetworkSelectorEnabled.mockReturnValue(true);
216-
162+
it('shows enabled networks text when multiple networks enabled', () => {
217163
const mockState = createMockState();
218164
store = mockStore(mockState);
219165

@@ -226,10 +172,7 @@ describe('DeFiPositionsControlBar', () => {
226172
expect(getByText(strings('wallet.popular_networks'))).toBeDefined();
227173
});
228174

229-
it('should show current network name when isRemoveGlobalNetworkSelectorEnabled is true and single network enabled', () => {
230-
const networksModule = jest.requireMock('../../../util/networks');
231-
networksModule.isRemoveGlobalNetworkSelectorEnabled.mockReturnValue(true);
232-
175+
it('shows current network name when single network enabled', () => {
233176
const useCurrentNetworkInfoModule = jest.requireMock(
234177
'../../hooks/useCurrentNetworkInfo',
235178
);
@@ -260,10 +203,7 @@ describe('DeFiPositionsControlBar', () => {
260203
expect(getByText('Ethereum Mainnet')).toBeDefined();
261204
});
262205

263-
it('should show current network fallback when isRemoveGlobalNetworkSelectorEnabled is true and no network name', () => {
264-
const networksModule = jest.requireMock('../../../util/networks');
265-
networksModule.isRemoveGlobalNetworkSelectorEnabled.mockReturnValue(true);
266-
206+
it('shows current network fallback when no network name', () => {
267207
const useCurrentNetworkInfoModule = jest.requireMock(
268208
'../../hooks/useCurrentNetworkInfo',
269209
);
@@ -292,10 +232,7 @@ describe('DeFiPositionsControlBar', () => {
292232
expect(getByText(strings('wallet.current_network'))).toBeDefined();
293233
});
294234

295-
it('should navigate to network manager when isRemoveGlobalNetworkSelectorEnabled is true and filter button is pressed', () => {
296-
const networksModule = jest.requireMock('../../../util/networks');
297-
networksModule.isRemoveGlobalNetworkSelectorEnabled.mockReturnValue(true);
298-
235+
it('navigates to network manager when filter button is pressed', () => {
299236
const mockNavigation = {
300237
navigate: jest.fn(),
301238
};
@@ -323,37 +260,6 @@ describe('DeFiPositionsControlBar', () => {
323260
);
324261
});
325262

326-
it('should navigate to token filter when isRemoveGlobalNetworkSelectorEnabled is false and filter button is pressed', () => {
327-
const networksModule = jest.requireMock('../../../util/networks');
328-
networksModule.isRemoveGlobalNetworkSelectorEnabled.mockReturnValue(false);
329-
330-
const mockNavigation = {
331-
navigate: jest.fn(),
332-
};
333-
334-
const navigationModule = jest.requireMock('@react-navigation/native');
335-
navigationModule.useNavigation = () => mockNavigation;
336-
337-
const mockState = createMockState();
338-
store = mockStore(mockState);
339-
340-
const { getByTestId } = render(
341-
<Provider store={store}>
342-
<DeFiPositionsControlBar />
343-
</Provider>,
344-
);
345-
346-
const filterButton = getByTestId('defi-positions-network-filter');
347-
fireEvent.press(filterButton);
348-
349-
expect(mockNavigation.navigate).toHaveBeenCalledWith(
350-
'RootModalFlow',
351-
expect.objectContaining({
352-
screen: 'TokenFilter',
353-
}),
354-
);
355-
});
356-
357263
it('should be disabled when on testnet', () => {
358264
const networksModule = jest.requireMock('../../../util/networks');
359265
networksModule.isTestNet.mockReturnValue(true);

app/components/UI/DeFiPositions/DeFiPositionsList.test.tsx

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { WalletViewSelectorsIDs } from '../../../../e2e/selectors/wallet/WalletV
77

88
jest.mock('../../../util/networks', () => ({
99
...jest.requireActual('../../../util/networks'),
10-
isRemoveGlobalNetworkSelectorEnabled: jest.fn().mockReturnValue(false),
1110
}));
1211

1312
jest.mock('react-native-device-info', () => ({
@@ -194,17 +193,20 @@ describe('DeFiPositionsList', () => {
194193
beforeEach(() => {
195194
jest.clearAllMocks();
196195

196+
const allPositions =
197+
mockInitialState.engine.backgroundState.DeFiPositionsController
198+
.allDeFiPositions[MOCK_ADDRESS_1] || {};
199+
197200
const defiPositionsModule = jest.requireMock(
198201
'../../../selectors/defiPositionsController',
199202
);
200203
defiPositionsModule.selectDeFiPositionsByAddress.mockReturnValue(
201-
mockInitialState.engine.backgroundState.DeFiPositionsController
202-
.allDeFiPositions[MOCK_ADDRESS_1],
203-
);
204-
defiPositionsModule.selectDefiPositionsByEnabledNetworks.mockReturnValue(
205-
mockInitialState.engine.backgroundState.DeFiPositionsController
206-
.allDeFiPositions[MOCK_ADDRESS_1],
204+
allPositions,
207205
);
206+
// Network Manager is now always enabled, so mock returns only enabled chain (0x1)
207+
defiPositionsModule.selectDefiPositionsByEnabledNetworks.mockReturnValue({
208+
[MOCK_CHAIN_ID_1]: allPositions[MOCK_CHAIN_ID_1],
209+
});
208210
});
209211

210212
it('renders protocol name and aggregated value for selected account and chain', async () => {
@@ -229,6 +231,17 @@ describe('DeFiPositionsList', () => {
229231
});
230232

231233
it('renders protocol name and aggregated value for all chains when all networks is selected', async () => {
234+
// Override mock to return all enabled chains
235+
const allPositions =
236+
mockInitialState.engine.backgroundState.DeFiPositionsController
237+
.allDeFiPositions[MOCK_ADDRESS_1] || {};
238+
const defiPositionsModule = jest.requireMock(
239+
'../../../selectors/defiPositionsController',
240+
);
241+
defiPositionsModule.selectDefiPositionsByEnabledNetworks.mockReturnValue(
242+
allPositions,
243+
);
244+
232245
const { findByTestId, findByText } = renderWithProvider(
233246
<DeFiPositionsList tabLabel="DeFi" />,
234247
{
@@ -344,13 +357,8 @@ describe('DeFiPositionsList', () => {
344357
expect(await findByText(`Explore DeFi`)).toBeOnTheScreen();
345358
});
346359

347-
describe('when isRemoveGlobalNetworkSelectorEnabled is true', () => {
348-
beforeEach(() => {
349-
const networksModule = jest.requireMock('../../../util/networks');
350-
networksModule.isRemoveGlobalNetworkSelectorEnabled.mockReturnValue(true);
351-
});
352-
353-
it('uses defiPositionsByEnabledNetworks selector when feature flag is enabled', async () => {
360+
describe('Network Manager Integration', () => {
361+
it('uses defiPositionsByEnabledNetworks selector', async () => {
354362
const defiPositionsModule = jest.requireMock(
355363
'../../../selectors/defiPositionsController',
356364
);
@@ -463,7 +471,7 @@ describe('DeFiPositionsList', () => {
463471
expect(await findByText(`Explore DeFi`)).toBeOnTheScreen();
464472
});
465473

466-
it('shows control bar with enabled networks text when feature flag is enabled', async () => {
474+
it('shows control bar with enabled networks text', async () => {
467475
const defiPositionsModule = jest.requireMock(
468476
'../../../selectors/defiPositionsController',
469477
);
@@ -629,6 +637,18 @@ describe('DeFiPositionsList', () => {
629637
});
630638

631639
it('renders multiple positions without scroll container when isHomepageRedesignV1Enabled is true', async () => {
640+
// Override mock to return both enabled chains
641+
const allPositions =
642+
mockInitialState.engine.backgroundState.DeFiPositionsController
643+
.allDeFiPositions[MOCK_ADDRESS_1] || {};
644+
const defiPositionsModule = jest.requireMock(
645+
'../../../selectors/defiPositionsController',
646+
);
647+
defiPositionsModule.selectDefiPositionsByEnabledNetworks.mockReturnValue({
648+
[MOCK_CHAIN_ID_1]: allPositions[MOCK_CHAIN_ID_1],
649+
[MOCK_CHAIN_ID_2]: allPositions[MOCK_CHAIN_ID_2],
650+
});
651+
632652
const { findByTestId, findByText, queryByTestId } = renderWithProvider(
633653
<DeFiPositionsList tabLabel="DeFi" />,
634654
{

app/components/UI/DeFiPositions/DeFiPositionsList.tsx

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ import React, { useMemo } from 'react';
22
import { View } from 'react-native';
33
import { strings } from '../../../../locales/i18n';
44
import { useSelector } from 'react-redux';
5-
import {
6-
selectChainId,
7-
selectIsAllNetworks,
8-
} from '../../../selectors/networkController';
95
import { Hex } from '@metamask/utils';
106
import {
117
selectDeFiPositionsByAddress,
@@ -32,7 +28,6 @@ import Icon, {
3228
} from '../../../component-library/components/Icons/Icon';
3329
import { useStyles } from '../../hooks/useStyles';
3430
import { WalletViewSelectorsIDs } from '../../../../e2e/selectors/wallet/WalletView.selectors';
35-
import { isRemoveGlobalNetworkSelectorEnabled } from '../../../util/networks';
3631
import { DefiEmptyState } from '../DefiEmptyState';
3732
import { selectHomepageRedesignV1Enabled } from '../../../selectors/featureFlagController/homepage';
3833
import ConditionalScrollView from '../../../component-library/components-temp/ConditionalScrollView';
@@ -43,8 +38,6 @@ export interface DeFiPositionsListProps {
4338

4439
const DeFiPositionsList: React.FC<DeFiPositionsListProps> = () => {
4540
const { styles } = useStyles(styleSheet, undefined);
46-
const isAllNetworks = useSelector(selectIsAllNetworks);
47-
const currentChainId = useSelector(selectChainId) as Hex;
4841
const tokenSortConfig = useSelector(selectTokenSortConfig);
4942
const defiPositions = useSelector(selectDeFiPositionsByAddress);
5043
const defiPositionsByEnabledNetworks = useSelector(
@@ -60,20 +53,9 @@ const DeFiPositionsList: React.FC<DeFiPositionsListProps> = () => {
6053
return defiPositions;
6154
}
6255

63-
let chainFilteredDeFiPositions: { [key: Hex]: GroupedDeFiPositions };
64-
if (isRemoveGlobalNetworkSelectorEnabled()) {
65-
chainFilteredDeFiPositions = defiPositionsByEnabledNetworks as {
66-
[key: Hex]: GroupedDeFiPositions;
67-
};
68-
} else if (isAllNetworks) {
69-
chainFilteredDeFiPositions = defiPositions;
70-
} else if (currentChainId in defiPositions) {
71-
chainFilteredDeFiPositions = {
72-
[currentChainId]: defiPositions[currentChainId],
73-
};
74-
} else {
75-
return [];
76-
}
56+
const chainFilteredDeFiPositions = defiPositionsByEnabledNetworks as {
57+
[key: Hex]: GroupedDeFiPositions;
58+
};
7759

7860
if (!chainFilteredDeFiPositions) {
7961
return [];
@@ -100,13 +82,7 @@ const DeFiPositionsList: React.FC<DeFiPositionsListProps> = () => {
10082
};
10183

10284
return sortAssets(defiPositionsList, defiSortConfig);
103-
}, [
104-
defiPositions,
105-
isAllNetworks,
106-
currentChainId,
107-
tokenSortConfig,
108-
defiPositionsByEnabledNetworks,
109-
]);
85+
}, [defiPositions, tokenSortConfig, defiPositionsByEnabledNetworks]);
11086

11187
if (!formattedDeFiPositions) {
11288
if (formattedDeFiPositions === undefined) {

0 commit comments

Comments
 (0)