Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d24d24e
refactor: simplify bridge network type
micaelae Nov 26, 2025
e89411f
fix: infer non-evm balance type
micaelae Nov 26, 2025
0294b9f
refactor: remove unused getToTokenConversionRate selector
micaelae Nov 26, 2025
d8bced7
refactor: deprecate getIsBridgeTx selector
micaelae Nov 27, 2025
9a8eb30
refactor: deprecate token.string usages
micaelae Nov 27, 2025
a651ddb
test: fix featureFlagOverrides type
micaelae Nov 28, 2025
94976c4
test: fix bridgeStateOverrides mocks
micaelae Nov 28, 2025
31288a4
Merge branch 'main' into swaps-refactor-rm-unused-selectors
micaelae Dec 1, 2025
6598337
fix: lint errors
micaelae Dec 1, 2025
bd81e44
fix: lint errors
micaelae Dec 1, 2025
a51b7d8
Merge branch 'main' into swaps-refactor-rm-unused-selectors
micaelae Dec 1, 2025
f762b69
fix: lint error
micaelae Dec 1, 2025
ae45132
fix: e2e test
micaelae Dec 1, 2025
de91a29
fix: state-logs e2e test
micaelae Dec 1, 2025
992820d
fix: set EVM network
micaelae Dec 1, 2025
a7c3212
chore: update types
micaelae Dec 1, 2025
b4a84dc
fix: optional chaining
micaelae Dec 1, 2025
d884a21
Merge branch 'main' into swaps-refactor-rm-unused-selectors
micaelae Dec 2, 2025
b97ef32
fix: lint
micaelae Dec 2, 2025
e4d03e8
fix: e2e test
micaelae Dec 2, 2025
6026ed8
chore: rm native balance fetch on fromChain update
micaelae Dec 2, 2025
ecbf219
Merge branch 'main' into swaps-refactor-rm-unused-selectors
micaelae Dec 2, 2025
1450d09
fix: getFromChains
micaelae Dec 2, 2025
d64acea
chore: add constant for slip44
micaelae Dec 2, 2025
92155e9
chore: rm unused useSolanaBridgeTransactionMapping hook
micaelae Dec 2, 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 shared/constants/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ALLOWED_BRIDGE_CHAIN_IDS = [
///: BEGIN:ONLY_INCLUDE_IF(tron)
MultichainNetworks.TRON,
///: END:ONLY_INCLUDE_IF
];
] as const;

export const ALLOWED_BRIDGE_CHAIN_IDS_IN_CAIP =
ALLOWED_EVM_BRIDGE_CHAIN_IDS.map(toEvmCaipChainId).concat(
Expand Down
17 changes: 6 additions & 11 deletions test/data/bridge/mock-bridge-store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
getDefaultBridgeControllerState,
formatChainIdToCaip,
FeatureFlagResponse,
BridgeControllerState,
} from '@metamask/bridge-controller';
import { DEFAULT_BRIDGE_STATUS_CONTROLLER_STATE } from '@metamask/bridge-status-controller';
import { AVAILABLE_MULTICHAIN_NETWORK_CONFIGURATIONS } from '@metamask/multichain-network-controller';
Expand Down Expand Up @@ -118,25 +120,21 @@ export const MOCK_EVM_ACCOUNT_2 = {
};

export const createBridgeMockStore = ({
featureFlagOverrides = {},
featureFlagOverrides = { bridgeConfig: {} },
bridgeSliceOverrides = {},
bridgeStateOverrides = {},
bridgeStatusStateOverrides = {},
metamaskStateOverrides = {},
stateOverrides = {},
}: {
// featureFlagOverrides?: Partial<BridgeControllerState['bridgeFeatureFlags']>;
// bridgeStateOverrides?: Partial<BridgeControllerState>;
featureFlagOverrides?: { bridgeConfig: Partial<FeatureFlagResponse> };
bridgeStateOverrides?: Partial<BridgeControllerState>;
// bridgeStatusStateOverrides?: Partial<BridgeStatusState>;
// metamaskStateOverrides?: Partial<BridgeAppState['metamask']>;
// TODO replace these with correct types
// eslint-disable-next-line @typescript-eslint/no-explicit-any
featureFlagOverrides?: Record<string, any>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
bridgeSliceOverrides?: Record<string, any>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
bridgeStateOverrides?: Record<string, any>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
bridgeStatusStateOverrides?: Record<string, any>;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
metamaskStateOverrides?: Record<string, any>;
Expand Down Expand Up @@ -352,7 +350,6 @@ export const createBridgeMockStore = ({
support: false,
refreshRate: 5000,
maxRefreshCount: 5,
...featureFlagOverrides?.extensionConfig,
...featureFlagOverrides?.bridgeConfig,
chains: {
[formatChainIdToCaip('0x1')]: {
Expand All @@ -361,9 +358,7 @@ export const createBridgeMockStore = ({
},
...Object.fromEntries(
Object.entries(
featureFlagOverrides?.extensionConfig?.chains ??
featureFlagOverrides?.bridgeConfig?.chains ??
{},
featureFlagOverrides?.bridgeConfig?.chains ?? {},
).map(([chainId, config]) => [
formatChainIdToCaip(chainId),
config,
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/tests/metrics/bridge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ describe('Bridge tests', function (this: Suite) {
*/

assert(
swapBridgeInputChanged.length === 18,
`Should have 18 input change events, but got ${swapBridgeInputChanged.length}`,
swapBridgeInputChanged.length === 17,
`Should have 17 input change events, but got ${swapBridgeInputChanged.length}`,
);

const swapBridgeInputChangedKeys = new Set(
Expand Down
2 changes: 0 additions & 2 deletions test/e2e/tests/settings/state-logs.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,6 @@
"sortOrder": "string",
"toChainId": "null",
"toToken": "null",
"toTokenExchangeRate": "null",
"toTokenUsdExchangeRate": "null",
"txAlert": "null",
"wasTxDeclined": "boolean"
},
Expand Down
27 changes: 8 additions & 19 deletions ui/ducks/bridge/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ import {
UnifiedSwapBridgeEventName,
} from '@metamask/bridge-controller';
import { type InternalAccount } from '@metamask/keyring-internal-api';
import { type CaipChainId } from '@metamask/utils';
import type {
AddNetworkFields,
NetworkConfiguration,
} from '@metamask/network-controller';
import { trace, TraceName } from '../../../shared/lib/trace';
import {
forceUpdateMetamaskState,
Expand All @@ -23,15 +18,13 @@ import { submitRequestToBackground } from '../../store/background-connection';
import type { MetaMaskReduxDispatch } from '../../store/store';
import {
bridgeSlice,
setDestTokenExchangeRates,
setDestTokenUsdExchangeRates,
setSrcTokenExchangeRates,
setTxAlerts,
setEVMSrcTokenBalance as setEVMSrcTokenBalance_,
setEVMSrcNativeBalance,
} from './bridge';
import type { TokenPayload } from './types';
import { isNetworkAdded, isNonEvmChain } from './utils';
import type { BridgeNetwork, TokenPayload } from './types';
import { isNonEvmChain } from './utils';

const {
setToChainId,
Expand All @@ -52,8 +45,6 @@ export {
setToToken,
setFromToken,
setFromTokenInputValue,
setDestTokenExchangeRates,
setDestTokenUsdExchangeRates,
setSrcTokenExchangeRates,
setSortOrder,
setSelectedQuote,
Expand Down Expand Up @@ -149,10 +140,7 @@ export const setFromChain = ({
selectedAccount,
token = null,
}: {
networkConfig?:
| NetworkConfiguration
| AddNetworkFields
| (Omit<NetworkConfiguration, 'chainId'> & { chainId: CaipChainId });
networkConfig?: BridgeNetwork;
selectedAccount: InternalAccount | null;
token?: TokenPayload['payload'];
}) => {
Expand All @@ -168,10 +156,11 @@ export const setFromChain = ({
if (isNonEvm) {
dispatch(setActiveNetworkWithError(networkConfig.chainId));
} else {
const networkId = isNetworkAdded(networkConfig)
? networkConfig.rpcEndpoints?.[networkConfig.defaultRpcEndpointIndex]
?.networkClientId
: null;
const networkId =
networkConfig.defaultRpcEndpointIndex !== undefined
? networkConfig.rpcEndpoints?.[networkConfig.defaultRpcEndpointIndex]
.networkClientId
: null;
if (networkId) {
dispatch(setActiveNetworkWithError(networkId));
}
Expand Down
113 changes: 0 additions & 113 deletions ui/ducks/bridge/bridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ import {
BridgeBackgroundAction,
BridgeUserAction,
formatChainIdToCaip,
getNativeAssetForChainId,
} from '@metamask/bridge-controller';
import * as controllerUtils from '@metamask/controller-utils';
import { createBridgeMockStore } from '../../../test/data/bridge/mock-bridge-store';
import { toAssetId } from '../../../shared/lib/asset-utils';
import { CHAIN_IDS } from '../../../shared/constants/network';
import { setBackgroundConnection } from '../../store/background-connection';
import { MultichainNetworks } from '../../../shared/constants/multichain/networks';
Expand All @@ -23,7 +20,6 @@ import {
setToChainId,
updateQuoteRequestParams,
resetBridgeState,
setDestTokenExchangeRates,
setWasTxDeclined,
setSlippage,
} from './actions';
Expand Down Expand Up @@ -110,7 +106,6 @@ describe('Ducks - Bridge', () => {
chainId: '0xa',
image:
'https://static.cx.metamask.io/api/v2/tokenIcons/assets/eip155/10/erc20/0x13341431.png',
string: '0',
}),
);
});
Expand Down Expand Up @@ -144,11 +139,9 @@ describe('Ducks - Bridge', () => {
slippage: SlippageValue.BridgeDefault,
fromTokenInputValue: null,
sortOrder: 'cost_ascending',
toTokenExchangeRate: null,
fromTokenExchangeRate: null,
wasTxDeclined: false,
txAlert: null,
toTokenUsdExchangeRate: null,
fromTokenBalance: null,
fromNativeBalance: null,
});
Expand Down Expand Up @@ -245,119 +238,13 @@ describe('Ducks - Bridge', () => {
toChainId: null,
toToken: null,
txAlert: null,
toTokenExchangeRate: null,
wasTxDeclined: false,
toTokenUsdExchangeRate: null,
fromTokenBalance: null,
fromNativeBalance: null,
});
});
});

describe('setDestTokenExchangeRates', () => {
it('fetches token prices and updates dest exchange rates in state, native dest token', async () => {
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31973
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mockStore = configureMockStore<any>(middleware)(
createBridgeMockStore(),
);
const state = mockStore.getState().bridge;
const fetchTokenExchangeRatesSpy = jest
.spyOn(controllerUtils, 'handleFetch')
.mockResolvedValue({
[getNativeAssetForChainId(CHAIN_IDS.LINEA_MAINNET).assetId]: {
price: 0.356628,
},
});

await mockStore.dispatch(
setDestTokenExchangeRates({
chainId: CHAIN_IDS.LINEA_MAINNET,
tokenAddress: zeroAddress(),
currency: 'usd',
}) as never,
);

expect(fetchTokenExchangeRatesSpy).toHaveBeenCalledTimes(1);
expect(fetchTokenExchangeRatesSpy).toHaveBeenCalledWith(
'https://price.api.cx.metamask.io/v3/spot-prices?assetIds=eip155%3A59144%2Fslip44%3A60&includeMarketData=true&vsCurrency=usd',
{
headers: { 'X-Client-Id': 'extension' },
method: 'GET',
signal: undefined,
},
);

const actions = mockStore.getActions();
expect(actions).toHaveLength(2);
expect(actions[0].type).toStrictEqual(
'bridge/setDestTokenExchangeRates/pending',
);
expect(actions[1].type).toStrictEqual(
'bridge/setDestTokenExchangeRates/fulfilled',
);
const newState = bridgeReducer(state, actions[1]);
expect(newState).toStrictEqual({
toChainId: null,
toTokenExchangeRate: 0.356628,
sortOrder: 'cost_ascending',
});
});

it('fetches token prices and updates dest exchange rates in state, erc20 dest token', async () => {
// TODO: Fix in https://github.com/MetaMask/metamask-extension/issues/31973
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mockStore = configureMockStore<any>(middleware)(
createBridgeMockStore(),
);
const state = mockStore.getState().bridge;
const fetchTokenExchangeRatesSpy = jest
.spyOn(controllerUtils, 'handleFetch')
.mockResolvedValue({
[toAssetId(
'0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359'.toLowerCase(),
formatChainIdToCaip(CHAIN_IDS.LINEA_MAINNET),
) as never]: {
price: 0.999881,
},
});

await mockStore.dispatch(
setDestTokenExchangeRates({
chainId: CHAIN_IDS.LINEA_MAINNET,
tokenAddress:
'0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359'.toLowerCase(),
currency: 'usd',
}) as never,
);

expect(fetchTokenExchangeRatesSpy).toHaveBeenCalledTimes(1);
expect(fetchTokenExchangeRatesSpy).toHaveBeenCalledWith(
'https://price.api.cx.metamask.io/v3/spot-prices?assetIds=eip155%3A59144%2Ferc20%3A0x3c499c542cef5e3811e1192ce70d8cc03d5c3359&includeMarketData=true&vsCurrency=usd',
{
headers: { 'X-Client-Id': 'extension' },
method: 'GET',
signal: undefined,
},
);

const actions = mockStore.getActions();
expect(actions).toHaveLength(2);
expect(actions[0].type).toStrictEqual(
'bridge/setDestTokenExchangeRates/pending',
);
expect(actions[1].type).toStrictEqual(
'bridge/setDestTokenExchangeRates/fulfilled',
);
const newState = bridgeReducer(state, actions[1]);
expect(newState).toStrictEqual({
toChainId: null,
toTokenExchangeRate: 0.999881,
sortOrder: 'cost_ascending',
});
});
});

describe('setWasTxDeclined', () => {
it('sets the wasTxDeclined flag to true', () => {
const state = store.getState().bridge;
Expand Down
25 changes: 0 additions & 25 deletions ui/ducks/bridge/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ const initialState: BridgeState = {
toToken: null,
fromTokenInputValue: null,
fromTokenExchangeRate: null,
toTokenExchangeRate: null,
toTokenUsdExchangeRate: null,
fromTokenBalance: null,
fromNativeBalance: null,
sortOrder: SortOrder.COST_ASC,
Expand All @@ -40,16 +38,6 @@ export const setSrcTokenExchangeRates = createAsyncThunk(
getTokenExchangeRate,
);

export const setDestTokenExchangeRates = createAsyncThunk(
'bridge/setDestTokenExchangeRates',
getTokenExchangeRate,
);

export const setDestTokenUsdExchangeRates = createAsyncThunk(
'bridge/setDestTokenUsdExchangeRates',
getTokenExchangeRate,
);

export const setTxAlerts = createAsyncThunk(
'bridge/setTxAlerts',
fetchTxAlerts,
Expand Down Expand Up @@ -110,7 +98,6 @@ const bridgeSlice = createSlice({
if (
state.fromToken?.assetId &&
state.toToken?.assetId &&
// TODO: determine if this is necessary.
state.fromToken.assetId?.toLowerCase() ===
state.toToken.assetId?.toLowerCase()
) {
Expand Down Expand Up @@ -179,21 +166,9 @@ const bridgeSlice = createSlice({
},
},
extraReducers: (builder) => {
builder.addCase(setDestTokenExchangeRates.pending, (state) => {
state.toTokenExchangeRate = null;
});
builder.addCase(setDestTokenUsdExchangeRates.pending, (state) => {
state.toTokenUsdExchangeRate = null;
});
builder.addCase(setSrcTokenExchangeRates.pending, (state) => {
state.fromTokenExchangeRate = null;
});
builder.addCase(setDestTokenExchangeRates.fulfilled, (state, action) => {
state.toTokenExchangeRate = action.payload ?? null;
});
builder.addCase(setDestTokenUsdExchangeRates.fulfilled, (state, action) => {
state.toTokenUsdExchangeRate = action.payload ?? null;
});
builder.addCase(setSrcTokenExchangeRates.fulfilled, (state, action) => {
state.fromTokenExchangeRate = action.payload ?? null;
});
Expand Down
Loading
Loading