Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1d72223
fix: use correct order for networks
SteP-n-s Nov 6, 2025
40923eb
Merge branch 'main' into fix/btc_fees_order
SteP-n-s Nov 6, 2025
3ad6fdd
fix: resolve issue with invalid fee format
SteP-n-s Nov 6, 2025
c5f6ac3
chore: update tests
SteP-n-s Nov 7, 2025
9e03fdf
Merge branch 'main' into fix/btc_fees_order
SteP-n-s Nov 7, 2025
946823e
chore: update snapshot
SteP-n-s Nov 7, 2025
10c2c81
Merge branch 'main' into fix/btc_fees_order
SteP-n-s Nov 7, 2025
8744011
chore: further snapshot updates
SteP-n-s Nov 7, 2025
4c537ba
Merge branch 'main' into fix/btc_fees_order
SteP-n-s Nov 7, 2025
cf8e554
Merge branch 'main' into fix/btc_fees_order
SteP-n-s Nov 7, 2025
773c404
chore: further test coverage
SteP-n-s Nov 7, 2025
7ce0332
fix: resolve issue with compilation directive
SteP-n-s Nov 7, 2025
5ce566f
Merge branch 'main' into fix/btc_fees_order
SteP-n-s Nov 7, 2025
23128f3
fix: resolve e2e flakiness
SteP-n-s Nov 7, 2025
1530c5d
chore: further updates on e2e
SteP-n-s Nov 7, 2025
d465cd1
chore: revert network selection in e2e
SteP-n-s Nov 7, 2025
b9256e6
Merge branch 'main' into fix/btc_fees_order
bfullam Nov 9, 2025
5b43965
test: add ChainPopularity fallback test coverage
bfullam Nov 10, 2025
8c71cba
Merge branch 'main' into fix/btc_fees_order
bfullam Nov 10, 2025
977dc0f
Merge branch 'main' into fix/btc_fees_order
bfullam Nov 10, 2025
7237827
test: more branch coverage
bfullam Nov 10, 2025
7eb7ea5
test: fix e2e
bfullam Nov 10, 2025
aef9855
test: fix e2e
bfullam Nov 10, 2025
fc761a6
Merge branch 'main' into fix/btc_fees_order
bfullam 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
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,105 @@ describe('BridgeDestNetworkSelector', () => {
expect(queryByText('Optimism')).toBeTruthy();
});
});

describe('BridgeDestNetworkSelector - ChainPopularity fallback', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('assigns Infinity to chains without defined popularity', () => {
// Add networks with and without defined popularity to test all branch combinations:
// - Optimism: HAS defined popularity (10 in ChainPopularity)
// - Palm: NO defined popularity (triggers ?? Infinity)
// - zkSync Era: NO defined popularity (triggers ?? Infinity)
// This ensures all branch combinations are tested:
// 1. Both have defined popularity (Optimism already tested in existing tests)
// 2. Both lack defined popularity (Palm vs zkSync Era)
// 3. One has, one doesn't (Optimism vs Palm/zkSync)
const stateWithMultipleNetworks = {
...initialState,
engine: {
...initialState.engine,
backgroundState: {
...initialState.engine.backgroundState,
RemoteFeatureFlagController: {
remoteFeatureFlags: {
bridgeConfig: {
minimumVersion: '0.0.0',
maxRefreshCount: 5,
refreshRate: 30000,
support: true,
chains: {
'eip155:1': {
isActiveSrc: true,
isActiveDest: true,
},
'eip155:10': {
// Optimism - HAS defined popularity
isActiveSrc: true,
isActiveDest: true,
},
'eip155:11297108109': {
// Palm - NOT in ChainPopularity
isActiveSrc: true,
isActiveDest: true,
},
'eip155:324': {
// zkSync Era - NOT in ChainPopularity
isActiveSrc: true,
isActiveDest: true,
},
},
},
bridgeConfigV2: {
minimumVersion: '0.0.0',
maxRefreshCount: 5,
refreshRate: 30000,
support: true,
chains: {
'eip155:1': {
isActiveSrc: true,
isActiveDest: true,
isGaslessSwapEnabled: true,
},
'eip155:10': {
// Optimism
isActiveSrc: true,
isActiveDest: true,
isGaslessSwapEnabled: false,
},
'eip155:11297108109': {
// Palm
isActiveSrc: true,
isActiveDest: true,
isGaslessSwapEnabled: false,
},
'eip155:324': {
// zkSync Era
isActiveSrc: true,
isActiveDest: true,
isGaslessSwapEnabled: false,
},
},
},
},
},
},
},
};

const { getByText } = renderScreen(
BridgeDestNetworkSelector,
{
name: Routes.BRIDGE.MODALS.DEST_NETWORK_SELECTOR,
},
{ state: stateWithMultipleNetworks },
);

// All three networks should be visible and sorted by popularity
// Optimism (popularity 10) should appear before Palm and zkSync Era (both Infinity)
expect(getByText('Optimism')).toBeTruthy();
expect(getByText('Palm')).toBeTruthy();
expect(getByText('zkSync Era')).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ exports[`BridgeDestNetworkSelector renders with initial state and displays netwo
}
}
>
Optimism
Bitcoin
</Text>
</View>
</View>
Expand Down Expand Up @@ -831,7 +831,7 @@ exports[`BridgeDestNetworkSelector renders with initial state and displays netwo
}
}
>
Bitcoin
Optimism
</Text>
</View>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { NetworkRow } from '../NetworkRow';
import Routes from '../../../../../constants/navigation/Routes';
import { selectChainId } from '../../../../../selectors/networkController';
import { BridgeViewMode } from '../../types';
import { ChainPopularity } from '../BridgeDestNetworksBar';

export interface BridgeDestNetworkSelectorRouteParams {
shouldGoToTokens?: boolean;
Expand Down Expand Up @@ -68,6 +69,11 @@ export const BridgeDestNetworkSelector: React.FC = () => {
}
return chain.chainId !== currentChainId;
})
.sort((a, b) => {
const aPopularity = ChainPopularity[a.chainId] ?? Infinity;
const bPopularity = ChainPopularity[b.chainId] ?? Infinity;
return aPopularity - bPopularity;
})
.map((chain) => (
<TouchableOpacity
key={chain.chainId}
Expand Down
25 changes: 13 additions & 12 deletions app/components/UI/Bridge/components/BridgeDestNetworksBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { selectChainId } from '../../../../selectors/networkController';
// Using ScrollView from react-native-gesture-handler to fix scroll issues with the bottom sheet
import { ScrollView } from 'react-native-gesture-handler';
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
import { SolScope } from '@metamask/keyring-api';
import { BtcScope, SolScope } from '@metamask/keyring-api';
import { BridgeViewMode } from '../types';
///: END:ONLY_INCLUDE_IF
const createStyles = (params: { theme: Theme }) => {
Expand Down Expand Up @@ -72,21 +72,22 @@ const createStyles = (params: { theme: Theme }) => {
* 1 = most popular
* Infinity = least popular
*/
const ChainPopularity: Record<Hex | CaipChainId, number> = {
export const ChainPopularity: Record<Hex | CaipChainId, number> = {
[ETH_CHAIN_ID]: 1,
[BSC_CHAIN_ID]: 2,
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
[SolScope.Mainnet]: 2,
[BtcScope.Mainnet]: 3,
[SolScope.Mainnet]: 4,
///: END:ONLY_INCLUDE_IF
[BASE_CHAIN_ID]: 3,
[BSC_CHAIN_ID]: 4,
[LINEA_CHAIN_ID]: 5,
[OPTIMISM_CHAIN_ID]: 6,
[ARBITRUM_CHAIN_ID]: 7,
[AVALANCHE_CHAIN_ID]: 9,
[BASE_CHAIN_ID]: 5,
[ARBITRUM_CHAIN_ID]: 6,
[LINEA_CHAIN_ID]: 7,
[POLYGON_CHAIN_ID]: 8,
[ZKSYNC_ERA_CHAIN_ID]: 10,
[NETWORKS_CHAIN_ID.SEI]: 11,
[NETWORKS_CHAIN_ID.MONAD]: 12,
[AVALANCHE_CHAIN_ID]: 9,
[OPTIMISM_CHAIN_ID]: 10,
[ZKSYNC_ERA_CHAIN_ID]: 11,
[NETWORKS_CHAIN_ID.SEI]: 12,
[NETWORKS_CHAIN_ID.MONAD]: 13,
};

const ShortChainNames: Record<Hex | CaipChainId, string> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ exports[`BridgeDestTokenSelector renders with initial state and displays tokens
}
}
>
Solana
Bitcoin
</Text>
</View>
</TouchableOpacity>
Expand Down Expand Up @@ -717,7 +717,7 @@ exports[`BridgeDestTokenSelector renders with initial state and displays tokens
}
}
>
Optimism
Solana
</Text>
</View>
</TouchableOpacity>
Expand Down Expand Up @@ -771,7 +771,7 @@ exports[`BridgeDestTokenSelector renders with initial state and displays tokens
}
}
>
Bitcoin
Optimism
</Text>
</View>
</TouchableOpacity>
Expand Down
16 changes: 2 additions & 14 deletions app/components/UI/Bridge/hooks/useBridgeQuoteData/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ import {
fromTokenMinimalUnit,
isNumberValue,
} from '../../../../../util/number';
import { selectPrimaryCurrency } from '../../../../../selectors/settings';
import {
isQuoteExpired,
getQuoteRefreshRate,
shouldRefreshQuote,
} from '../../utils/quoteUtils';

import { selectTicker } from '../../../../../selectors/networkController';
import { BigNumber } from 'bignumber.js';
import I18n from '../../../../../../locales/i18n';
import useFiatFormatter from '../../../SimulationDetails/FiatDisplay/useFiatFormatter';
Expand All @@ -51,8 +49,6 @@ export const useBridgeQuoteData = ({
const isSubmittingTx = useSelector(selectIsSubmittingTx);
const locale = I18n.locale;
const fiatFormatter = useFiatFormatter();
const primaryCurrency = useSelector(selectPrimaryCurrency) ?? 'ETH';
const ticker = useSelector(selectTicker);
const quotes = useSelector(selectBridgeQuotes);
const bridgeFeatureFlags = useSelector(selectBridgeFeatureFlags);
const isSolanaSwap = useSelector(selectIsSolanaSwap);
Expand Down Expand Up @@ -123,20 +119,12 @@ export const useBridgeQuoteData = ({
return '-';
}

const networkFeeFormatter = getIntlNumberFormatter(locale, {
maximumFractionDigits: 6,
});
const formattedAmount = `${networkFeeFormatter.format(
Number(amount),
)} ${ticker}`;
const formattedValueInCurrency = fiatFormatter(
new BigNumber(valueInCurrency),
);

return primaryCurrency === 'ETH'
? formattedAmount
: formattedValueInCurrency;
}, [activeQuote, locale, ticker, fiatFormatter, primaryCurrency]);
return formattedValueInCurrency;
}, [activeQuote, fiatFormatter]);

const formattedQuoteData = useMemo(() => {
if (!activeQuote) return undefined;
Expand Down
Loading