Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
271d096
chore: Remove MM_PER_DAPP_SELECTED_NETWORK feature flag (#21963)
vinnyhoward Nov 10, 2025
55277c9
fix: cp-7.59.0 fix display tabs based on selected networks (#22372)
salimtb Nov 10, 2025
7a3407e
test: disables android perps tests, fixes Card unit test (#22406)
christopherferreira9 Nov 10, 2025
402fccb
feat: metamask pay with send picker (#22363)
matthewwalsh0 Nov 10, 2025
d0c1928
chore: add search tokens hook (#22237)
sahar-fehri Nov 10, 2025
6ace1da
fix: hide predict deposit incoming transactions (#22371)
matthewwalsh0 Nov 10, 2025
84168bf
test: runs detox in detached mode in CI only (#22270)
christopherferreira9 Nov 10, 2025
82e043d
fix: Consider client active once it is open and unlocked (#22385)
FrederikBolding Nov 10, 2025
7e7938a
chore: semver bump to 7.60.0 (#22395)
joaoloureirop Nov 10, 2025
cf57bcc
fix(perps): Resolve 429 errors and improve session performance cp-7.5…
abretonc7s Nov 10, 2025
bb125e4
test: Increase mock server log level (#22404)
christopherferreira9 Nov 10, 2025
1623d46
feat: update notification account settings to use BIP-44 designs (#20…
Prithpal-Sooriya Nov 10, 2025
e9505c6
chore: update assets-controllers@^87.1.1 (#22396)
juanmigdr Nov 10, 2025
1f4fbdf
fix: use METAMASK_ENVIRONMENT instead of NODE_ENV (#22282)
asalsys Nov 10, 2025
54d0bf9
feat: updated currency switch clicked event for deposit and withdrawa…
Matt561 Nov 10, 2025
9ba9c85
chore: cp-7.59.0 bump bitcoin 1.4.5 (#22397)
aganglada Nov 10, 2025
deb715d
fix(ramps): cp-7.59.0 buildquote screen flickering (#22326)
AxelGes Nov 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .detoxrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = {
$0: 'jest',
config: 'e2e/jest.e2e.config.js',
},
detached: true,
detached: process.env.CI ? true : false,
jest: {
setupTimeout: 220000,
teardownTimeout: 60000, // Increase teardown timeout from default 30s to 60s
Expand Down
30 changes: 15 additions & 15 deletions .github/workflows/run-e2e-smoke-tests-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ jobs:
changed_files: ${{ inputs.changed_files }}
secrets: inherit

perps-android-smoke:
strategy:
matrix:
split: [1]
fail-fast: false
uses: ./.github/workflows/run-e2e-workflow.yml
with:
test-suite-name: perps-android-smoke-${{ matrix.split }}
platform: android
test_suite_tag: 'SmokePerps'
split_number: ${{ matrix.split }}
total_splits: 1
changed_files: ${{ inputs.changed_files }}
secrets: inherit
# perps-android-smoke:
# strategy:
# matrix:
# split: [1]
# fail-fast: false
# uses: ./.github/workflows/run-e2e-workflow.yml
# with:
# test-suite-name: perps-android-smoke-${{ matrix.split }}
# platform: android
# test_suite_tag: 'SmokePerps'
# split_number: ${{ matrix.split }}
# total_splits: 1
# changed_files: ${{ inputs.changed_files }}
# secrets: inherit

wallet-platform-android-smoke:
strategy:
Expand Down Expand Up @@ -170,7 +170,7 @@ jobs:
if: ${{ !cancelled() }}
needs:
- trade-android-smoke
- perps-android-smoke
# - perps-android-smoke
- wallet-platform-android-smoke
- identity-android-smoke
- accounts-android-smoke
Expand Down
3 changes: 0 additions & 3 deletions .js.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,6 @@ export MM_SAMPLE_FEATURE_COUNTER_ENABLED="true"
# The endpoint used to submit errors and tracing data to Sentry for dev environment.
# export MM_SENTRY_DSN_DEV=

# Per dapp selected network feature flag
export MM_PER_DAPP_SELECTED_NETWORK=""

# Remove global network selector flag
export MM_REMOVE_GLOBAL_NETWORK_SELECTOR=""

Expand Down
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ android {
applicationId "io.metamask"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionName "7.59.0"
versionName "7.60.0"
versionCode 2818
testBuildType System.getProperty('testBuildType', 'debug')
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AccountGroupObject } from '@metamask/account-tree-controller';
import React, { useCallback, useMemo } from 'react';
import { TouchableOpacity, View } from 'react-native';
import { type ImageSourcePropType, TouchableOpacity, View } from 'react-native';
import { useSelector } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { useStyles } from '../../../hooks';
Expand Down Expand Up @@ -36,18 +36,24 @@ interface AccountCellProps {
avatarAccountType: AvatarAccountType;
hideMenu?: boolean;
startAccessory?: React.ReactNode;
endContainer?: React.ReactNode;
chainId?: string;
onSelectAccount?: () => void;
}

const AccountCell = ({
type BalanceEndContainerProps = Pick<
AccountCellProps,
'accountGroup' | 'hideMenu' | 'onSelectAccount'
> & {
networkImageSource?: ImageSourcePropType;
};

const BalanceEndContainer = ({
accountGroup,
avatarAccountType,
hideMenu = false,
startAccessory,
chainId,
hideMenu,
onSelectAccount,
}: AccountCellProps) => {
networkImageSource,
}: BalanceEndContainerProps) => {
const { styles } = useStyles(styleSheet, {});
const { navigate } = useNavigation();

Expand All @@ -63,12 +69,6 @@ const AccountCell = ({
const totalBalance = groupBalance?.totalBalanceInUserCurrency;
const userCurrency = groupBalance?.userCurrency;

const selectEvmAddress = useMemo(
() => selectIconSeedAddressByAccountGroupId(accountGroup.id),
[accountGroup.id],
);
const evmAddress = useSelector(selectEvmAddress);

const displayBalance = useMemo(() => {
if (totalBalance == null || !userCurrency) {
return undefined;
Expand All @@ -79,6 +79,61 @@ const AccountCell = ({
});
}, [totalBalance, userCurrency]);

return (
<>
<TouchableOpacity onPress={onSelectAccount}>
<View style={styles.balanceContainer}>
<Text
variant={TextVariant.BodyMDMedium}
color={TextColor.Default}
testID={AccountCellIds.BALANCE}
>
{totalBalance ? displayBalance : null}
</Text>
{networkImageSource && (
<Avatar
variant={AvatarVariant.Network}
size={AvatarSize.Xs}
style={styles.networkBadge}
imageSource={networkImageSource}
/>
)}
</View>
</TouchableOpacity>
{!hideMenu && (
<TouchableOpacity
testID={AccountCellIds.MENU}
style={styles.menuButton}
onPress={handleMenuPress}
>
<Icon
name={IconName.MoreVertical}
size={IconSize.Md}
color={TextColor.Alternative}
/>
</TouchableOpacity>
)}
</>
);
};

const AccountCell = ({
accountGroup,
avatarAccountType,
hideMenu = false,
startAccessory,
endContainer,
chainId,
onSelectAccount,
}: AccountCellProps) => {
const { styles } = useStyles(styleSheet, {});

const selectEvmAddress = useMemo(
() => selectIconSeedAddressByAccountGroupId(accountGroup.id),
[accountGroup.id],
);
const evmAddress = useSelector(selectEvmAddress);

// Determine which account address and network avatar to display based on the chainId
let networkAccountAddress;
let networkImageSource;
Expand Down Expand Up @@ -138,37 +193,13 @@ const AccountCell = ({
</View>
</TouchableOpacity>
<View style={styles.endContainer}>
<TouchableOpacity onPress={onSelectAccount}>
<View style={styles.balanceContainer}>
<Text
variant={TextVariant.BodyMDMedium}
color={TextColor.Default}
testID={AccountCellIds.BALANCE}
>
{totalBalance ? displayBalance : null}
</Text>
{networkImageSource && (
<Avatar
variant={AvatarVariant.Network}
size={AvatarSize.Xs}
style={styles.networkBadge}
imageSource={networkImageSource}
/>
)}
</View>
</TouchableOpacity>
{!hideMenu && (
<TouchableOpacity
testID={AccountCellIds.MENU}
style={styles.menuButton}
onPress={handleMenuPress}
>
<Icon
name={IconName.MoreVertical}
size={IconSize.Md}
color={TextColor.Alternative}
/>
</TouchableOpacity>
{endContainer || (
<BalanceEndContainer
accountGroup={accountGroup}
hideMenu={hideMenu}
onSelectAccount={onSelectAccount}
networkImageSource={networkImageSource}
/>
)}
</View>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@ import Text, {
import createStyles from '../MultichainAccountSelectorList.styles';
import { AccountListHeaderProps } from './AccountListHeader.types';

const AccountListHeader = memo(({ title }: AccountListHeaderProps) => {
const { styles } = useStyles(createStyles, {});
const AccountListHeader = memo(
({ title, containerStyle }: AccountListHeaderProps) => {
const { styles } = useStyles(createStyles, {});

return (
<View style={styles.sectionHeader}>
<Text
variant={TextVariant.BodyMDMedium}
color={TextColor.Alternative}
style={styles.sectionHeaderText}
>
{title}
</Text>
</View>
);
});
return (
<View style={[styles.sectionHeader, containerStyle]}>
<Text
variant={TextVariant.BodyMDMedium}
color={TextColor.Alternative}
style={styles.sectionHeaderText}
>
{title}
</Text>
</View>
);
},
);

AccountListHeader.displayName = 'AccountListHeader';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { ViewStyle } from 'react-native';

export interface AccountListHeaderProps {
title: string;
containerStyle?: ViewStyle;
}
5 changes: 0 additions & 5 deletions app/components/Nav/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ import { Duration } from '@metamask/utils';
import { selectSeedlessOnboardingLoginFlow } from '../../../selectors/seedlessOnboardingController';
import { SmartAccountUpdateModal } from '../../Views/confirmations/components/smart-account-update-modal';
import { PayWithModal } from '../../Views/confirmations/components/modals/pay-with-modal/pay-with-modal';
import { PayWithNetworkModal } from '../../Views/confirmations/components/modals/pay-with-network-modal/pay-with-network-modal';
import { useMetrics } from '../../hooks/useMetrics';
import { State2AccountConnectWrapper } from '../../Views/MultichainAccounts/MultichainAccountConnect/State2AccountConnectWrapper';
import { SmartAccountModal } from '../../Views/MultichainAccounts/AccountDetails/components/SmartAccountModal/SmartAccountModal';
Expand Down Expand Up @@ -1052,10 +1051,6 @@ const AppFlow = () => {
name={Routes.CONFIRMATION_PAY_WITH_MODAL}
component={PayWithModal}
/>
<Stack.Screen
name={Routes.CONFIRMATION_PAY_WITH_NETWORK_MODAL}
component={PayWithNetworkModal}
/>
</Stack.Navigator>
</>
);
Expand Down
4 changes: 2 additions & 2 deletions app/components/Nav/Main/MainNavigator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import { Image, StyleSheet, Keyboard, Platform } from 'react-native';
import { createStackNavigator } from '@react-navigation/stack';
import { useSelector } from 'react-redux';
Expand Down Expand Up @@ -1192,7 +1192,7 @@ const MainNavigator = () => {
...GeneralSettings.navigationOptions,
}}
/>
{process.env.NODE_ENV !== 'production' && (
{process.env.METAMASK_ENVIRONMENT !== 'production' && (
<Stack.Screen
name={Routes.FEATURE_FLAG_OVERRIDE}
component={FeatureFlagOverride}
Expand Down
43 changes: 43 additions & 0 deletions app/components/Nav/Main/MainNavigator.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,16 @@ jest.mock('@react-navigation/stack', () => ({
}));

describe('MainNavigator', () => {
const originalEnv = process.env.METAMASK_ENVIRONMENT;

beforeEach(() => {
jest.clearAllMocks();
});

afterEach(() => {
process.env.METAMASK_ENVIRONMENT = originalEnv;
});

it('matches rendered snapshot', () => {
// Given the initial app state
// When rendering the MainNavigator
Expand Down Expand Up @@ -60,4 +66,41 @@ describe('MainNavigator', () => {
expect(sampleFeatureScreen).toBeDefined();
expect(sampleFeatureScreen?.component.name).toBe('SampleFeatureFlow');
});

it('includes FeatureFlagOverride screen when METAMASK_ENVIRONMENT is not production', () => {
// Given a non-production environment
process.env.METAMASK_ENVIRONMENT = 'dev';

// When rendering the MainNavigator
const container = renderWithProvider(<MainNavigator />, {
state: initialRootState,
});

// Then it should contain the FeatureFlagOverride screen
interface ScreenChild {
name: string;
component: { name: string };
}
const screenProps: ScreenChild[] = container.root.children
.filter(
(child): child is ReactTestInstance =>
typeof child === 'object' &&
'type' in child &&
'props' in child &&
child.type?.toString() === 'Screen',
)
.map((child) => ({
name: child.props.name,
component: child.props.component,
}));

const featureFlagOverrideScreen = screenProps?.find(
(screen) => screen?.name === Routes.FEATURE_FLAG_OVERRIDE,
);

expect(featureFlagOverrideScreen).toBeDefined();
expect(featureFlagOverrideScreen?.component.name).toBe(
'FeatureFlagOverride',
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import { AccountFromToInfoCardProps } from './AccountFromToInfoCard.types';
import { selectInternalAccounts } from '../../../selectors/accountsController';
import { RootState } from '../../../reducers';
import AddressFrom from './AddressFrom';
import { isPerDappSelectedNetworkEnabled } from '../../../util/networks';

const AccountFromToInfoCard = (props: AccountFromToInfoCardProps) => {
const { internalAccounts, chainId, ticker, transactionState, origin } = props;
Expand Down Expand Up @@ -170,11 +169,7 @@ const AccountFromToInfoCard = (props: AccountFromToInfoCardProps) => {
<View style={styles.container}>
{fromAddress && (
<AddressFrom
chainId={
isPerDappSelectedNetworkEnabled()
? transactionState?.chainId
: undefined
}
chainId={transactionState?.chainId}
asset={selectedAsset}
from={fromAddress}
origin={origin}
Expand Down
Loading
Loading