diff --git a/.eslintrc.js b/.eslintrc.js
index 58a60686452..fe907c50c25 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -83,7 +83,6 @@ const utilNumberImportBurndownFiles = [
'app/components/UI/TransactionElement/utils.js',
'app/components/UI/UrlAutocomplete/Result.tsx',
'app/components/Views/AssetDetails/index.tsx',
- 'app/components/Views/DetectedTokens/components/Token.tsx',
'app/components/Views/GasEducationCarousel/index.js',
'app/components/Views/NetworksManagement/NetworkDetailsView/hooks/useNetworkValidation.ts',
'app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuyBottomSheet/useQuickBuyBottomSheet.ts',
diff --git a/app/components/Nav/App/App.test.tsx b/app/components/Nav/App/App.test.tsx
index d72cd66cf28..fda94b6d6c4 100644
--- a/app/components/Nav/App/App.test.tsx
+++ b/app/components/Nav/App/App.test.tsx
@@ -156,12 +156,6 @@ jest.mock('../../Views/LedgerSelectAccount', () => () => (
jest.mock('../../Views/ConnectHardware/SelectHardware', () => () => (
));
-jest.mock('../../Views/DetectedTokens', () => () => (
-
-));
-jest.mock('../../Views/DetectedTokensConfirmation', () => () => (
-
-));
jest.mock('../../Views/WalletActions', () => () => (
));
@@ -2275,13 +2269,5 @@ describe('App', () => {
expect(getByTestId('mock-trade-actions')).toBeTruthy();
});
});
-
- it('renders DetectedTokens flow', async () => {
- const { getByTestId } = renderAppWithModal('DetectedTokens');
-
- await waitFor(() => {
- expect(getByTestId('mock-detected-tokens')).toBeTruthy();
- });
- });
});
});
diff --git a/app/components/Nav/App/App.tsx b/app/components/Nav/App/App.tsx
index c3ceacfc9aa..8b6626b5871 100644
--- a/app/components/Nav/App/App.tsx
+++ b/app/components/Nav/App/App.tsx
@@ -55,8 +55,6 @@ import ConnectionDetails from '../../../components/Views/AccountPermissions/Conn
import { SRPQuiz } from '../../Views/Quiz';
import { TurnOffRememberMeModal } from '../../../components/UI/TurnOffRememberMeModal';
import AssetHideConfirmation from '../../Views/AssetHideConfirmation';
-import DetectedTokens from '../../Views/DetectedTokens';
-import DetectedTokensConfirmation from '../../Views/DetectedTokensConfirmation';
import AssetOptions from '../../Views/AssetOptions';
import ImportPrivateKey from '../../Views/ImportPrivateKey';
import ImportPrivateKeySuccess from '../../Views/ImportPrivateKeySuccess';
@@ -419,20 +417,6 @@ const AddNetworkFlow = () => {
);
};
-const DetectedTokensFlow = () => (
-
-
-
-
-);
-
interface RootModalFlowProps {
route: {
params: Record;
@@ -596,7 +580,6 @@ const RootModalFlow = (props: RootModalFlowProps) => (
name={'AssetHideConfirmation'}
component={AssetHideConfirmation}
/>
-
diff --git a/app/components/Views/DetectedTokens/DetectedTokensView.testIds.ts b/app/components/Views/DetectedTokens/DetectedTokensView.testIds.ts
deleted file mode 100644
index 61be806bed8..00000000000
--- a/app/components/Views/DetectedTokens/DetectedTokensView.testIds.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export const DetectedTokensSelectorTexts = {
- IMPORT_BUTTON_TEXT: 'Import (1)',
-};
-
-export const DetectedTokensSelectorIDs = {
- IMPORT_BUTTON_ID: 'token-detection-import-button',
-};
diff --git a/app/components/Views/DetectedTokens/components/Token.test.tsx b/app/components/Views/DetectedTokens/components/Token.test.tsx
deleted file mode 100644
index 4c1ade3ac65..00000000000
--- a/app/components/Views/DetectedTokens/components/Token.test.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-import React from 'react';
-import { render, fireEvent } from '@testing-library/react-native';
-import Token from './Token';
-import { useDispatch, useSelector } from 'react-redux';
-import { Token as TokenType } from '@metamask/assets-controllers';
-import { selectEvmChainId } from '../../../../selectors/networkController';
-import { selectTokenMarketData } from '../../../../selectors/tokenRatesController';
-import { selectTokensBalances } from '../../../../selectors/tokenBalancesController';
-import ClipboardManager from '../../../../core/ClipboardManager';
-import { showAlert } from '../../../../actions/alert';
-import {
- selectConversionRateFoAllChains,
- selectCurrentCurrency,
-} from '../../../../selectors/currencyRateController';
-import { selectSelectedInternalAccountAddress } from '../../../../selectors/accountsController';
-
-// Mock dependencies
-jest.mock('react-redux', () => ({
- useDispatch: jest.fn(),
- useSelector: jest.fn(),
- connect: jest.fn(),
-}));
-
-jest.mock('../../../../core/ClipboardManager', () => ({
- setString: jest.fn(),
-}));
-
-jest.mock('../../../UI/TokenImage', () => () => null);
-
-jest.mock('../../../UI/AssetOverview/Balance/Balance', () => ({
- // Mock other exports if needed, or leave empty
- __esModule: true,
- NetworkBadgeSource: jest.fn(() => 'mocked-network-badge-source'),
-}));
-
-describe('Token Component', () => {
- const mockDispatch = jest.fn();
-
- beforeEach(() => {
- jest.clearAllMocks();
- (useDispatch as jest.Mock).mockReturnValue(mockDispatch);
- (useSelector as jest.Mock).mockImplementation((selector) => {
- if (selector === selectSelectedInternalAccountAddress) return '0xAccount';
- if (selector === selectEvmChainId) return '1';
- if (selector === selectTokenMarketData) return {};
- if (selector === selectTokensBalances)
- return {
- '0xAccount': { '1': '1000000000000000000' }, // 1 token
- };
- if (selector === selectConversionRateFoAllChains) return {};
- if (selector === selectCurrentCurrency) return 'USD';
- return {};
- });
- });
-
- const mockToken = {
- address: '0xTokenAddress',
- symbol: 'ABC',
- decimals: 18,
- aggregators: ['Aggregator1', 'Aggregator2', 'Aggregator3'],
- chainId: '1',
- };
-
- const renderComponent = (selected = false) =>
- render(
- ,
- );
-
- it('renders correctly', () => {
- const { getByText } = renderComponent();
-
- expect(getByText('0 ABC')).toBeTruthy();
- expect(getByText('Token address:')).toBeTruthy();
- });
-
- it('renders correctly with token chainId', () => {
- const { getByText } = render(
- ,
- );
-
- expect(getByText('0 ABC')).toBeTruthy();
- expect(getByText('Token address:')).toBeTruthy();
- });
-
- it('expands token aggregator list on "show more" press', () => {
- const { getByText } = renderComponent();
-
- const showMoreButton = getByText('+ 1 more');
- fireEvent.press(showMoreButton);
-
- expect(
- getByText('Token lists: Aggregator1, Aggregator2, Aggregator3'),
- ).toBeTruthy();
- });
-
- it('renders checkbox as checked when token is selected', () => {
- const { getByTestId } = renderComponent(true);
-
- const checkbox = getByTestId('token-select-checkbox');
- expect(checkbox.props.accessibilityState.checked).toBe(true);
- });
-
- it('renders checkbox as unchecked when token is not selected', () => {
- const { getByTestId } = renderComponent(false);
-
- const checkbox = getByTestId('token-select-checkbox');
- expect(checkbox.props.accessibilityState.checked).toBe(false);
- });
-
- it('copies address to clipboard and triggers alert', async () => {
- const { getByText } = renderComponent();
- const copyButton = getByText('0xToken...dress');
-
- ClipboardManager.setString = jest.fn(() => Promise.resolve());
-
- await fireEvent.press(copyButton);
-
- expect(ClipboardManager.setString).toHaveBeenCalledWith('0xTokenAddress');
- expect(mockDispatch).toHaveBeenCalledWith(
- showAlert({
- isVisible: true,
- autodismiss: 1500,
- content: 'clipboard-alert',
- data: { msg: 'Token address copied to clipboard' },
- }),
- );
- });
-});
diff --git a/app/components/Views/DetectedTokens/components/Token.tsx b/app/components/Views/DetectedTokens/components/Token.tsx
deleted file mode 100644
index ee8560b4b3a..00000000000
--- a/app/components/Views/DetectedTokens/components/Token.tsx
+++ /dev/null
@@ -1,245 +0,0 @@
-import React, { useState } from 'react';
-import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
-import {
- MarketDataDetails,
- Token as TokenType,
-} from '@metamask/assets-controllers';
-import EthereumAddress from '../../../UI/EthereumAddress';
-import Icon from 'react-native-vector-icons/Feather';
-import CheckBox from '@react-native-community/checkbox';
-import { strings } from '../../../../../locales/i18n';
-import TokenImage from '../../../UI/TokenImage';
-import { fontStyles } from '../../../../styles/common';
-import { useDispatch, useSelector } from 'react-redux';
-import { showAlert } from '../../../../actions/alert';
-import ClipboardManager from '../../../../core/ClipboardManager';
-import { selectEvmChainId } from '../../../../selectors/networkController';
-import {
- balanceToFiat,
- renderFromTokenMinimalUnit,
-} from '../../../../util/number';
-import { useTheme } from '../../../../util/theme';
-import {
- selectCurrencyRates,
- selectCurrentCurrency,
-} from '../../../../selectors/currencyRateController';
-import { selectTokenMarketData } from '../../../../selectors/tokenRatesController';
-import { selectTokensBalances } from '../../../../selectors/tokenBalancesController';
-import { Colors } from '../../../../util/theme/models';
-import { Hex } from '@metamask/utils';
-import BadgeWrapper, {
- BadgePosition,
-} from '../../../../component-library/components/Badges/BadgeWrapper';
-import Badge, {
- BadgeVariant,
-} from '../../../../component-library/components/Badges/Badge';
-import { NetworkBadgeSource } from '../../../UI/AssetOverview/Balance/Balance';
-import { CURRENCY_SYMBOL_BY_CHAIN_ID } from '../../../../constants/network';
-import { selectSelectedInternalAccountAddress } from '../../../../selectors/accountsController';
-
-const createStyles = (colors: Colors) =>
- StyleSheet.create({
- logo: {
- height: 40,
- width: 40,
- },
- tokenContainer: { flexDirection: 'row', paddingVertical: 16 },
- tokenInfoContainer: { flex: 1, marginLeft: 8, marginRight: 16 },
- tokenUnitLabel: {
- ...fontStyles.normal,
- fontSize: 18,
- color: colors.text.default,
- marginBottom: 4,
- },
- tokenDollarLabel: {
- ...fontStyles.normal,
- fontSize: 14,
- color: colors.text.alternative,
- marginBottom: 4,
- },
- tokenAddressContainer: {
- flexDirection: 'row',
- marginBottom: 4,
- },
- tokenAddressLabel: {
- ...fontStyles.normal,
- fontSize: 14,
- color: colors.text.alternative,
- },
- addressLinkContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- },
- addressLinkLabel: {
- ...fontStyles.normal,
- fontSize: 14,
- color: colors.primary.default,
- },
- copyIcon: {
- marginLeft: 4,
- color: colors.primary.default,
- },
- tokenAggregatorContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- flexWrap: 'wrap',
- },
- tokenAggregatorLabel: {
- ...fontStyles.normal,
- fontSize: 14,
- color: colors.text.default,
- },
- aggregatorLinkLabel: {
- ...fontStyles.normal,
- fontSize: 14,
- color: colors.primary.default,
- },
- checkBox: { height: 18 },
- });
-
-interface Props {
- token: TokenType & { chainId: Hex };
- selected: boolean;
- toggleSelected: (selected: boolean) => void;
-}
-
-const Token = ({ token, selected, toggleSelected }: Props) => {
- const { address, symbol, aggregators = [], decimals } = token;
- const accountAddress = useSelector(selectSelectedInternalAccountAddress);
- const { colors } = useTheme();
- const styles = createStyles(colors);
- const [expandTokenList, setExpandTokenList] = useState(false);
- const tokenExchangeRatesAllChains = useSelector(selectTokenMarketData);
- const currentChainId = useSelector(selectEvmChainId);
- const tokenExchangeRates = tokenExchangeRatesAllChains[token.chainId];
- const tokenBalancesAllChains = useSelector(selectTokensBalances);
- const balanceAllChainsForAccount =
- tokenBalancesAllChains?.[accountAddress as Hex] ?? {};
- const chainIdToUse = token.chainId ?? currentChainId;
- const tokenBalances = balanceAllChainsForAccount?.[chainIdToUse];
- const conversionRateByChainId = useSelector(selectCurrencyRates);
-
- const conversionRate =
- conversionRateByChainId[CURRENCY_SYMBOL_BY_CHAIN_ID[token.chainId]]
- ?.conversionRate;
-
- const currentCurrency = useSelector(selectCurrentCurrency);
-
- const tokenMarketData =
- (tokenExchangeRates as Record)?.[address as Hex] ??
- null;
- const tokenBalance = renderFromTokenMinimalUnit(
- tokenBalances[address as Hex],
- decimals,
- );
- const tokenBalanceWithSymbol = `${
- tokenBalance === undefined ? '' : `${tokenBalance} `
- }${symbol}`;
- const fiatBalance = balanceToFiat(
- tokenBalance,
- conversionRate,
- tokenMarketData?.price || undefined,
- currentCurrency,
- );
-
- const showMoreLink = !expandTokenList && aggregators.length > 2;
- const dispatch = useDispatch();
-
- const triggerShowAlert = () =>
- dispatch(
- showAlert({
- isVisible: true,
- autodismiss: 1500,
- content: 'clipboard-alert',
- data: { msg: strings('detected_tokens.address_copied_to_clipboard') },
- }),
- );
-
- const copyAddressToClipboard = async () => {
- await ClipboardManager.setString(address);
- triggerShowAlert();
- };
-
- const triggerExpandTokenList = () => {
- setExpandTokenList(true);
- };
-
- const triggerToggleSelected = () => {
- toggleSelected(!selected);
- };
-
- return (
-
-
- }
- >
-
-
-
-
- {tokenBalanceWithSymbol}
- {fiatBalance ? (
- {fiatBalance}
- ) : null}
-
-
- {strings('detected_tokens.token_address')}
-
-
-
-
-
-
-
-
- {strings('detected_tokens.token_lists', {
- listNames: aggregators
- .slice(0, expandTokenList ? aggregators.length : 2)
- .join(', '),
- })}
-
- {showMoreLink ? (
-
-
- {strings('detected_tokens.token_more', {
- remainingListCount: aggregators.slice(2, aggregators.length)
- .length,
- })}
-
-
- ) : null}
-
-
-
-
- );
-};
-
-export default Token;
diff --git a/app/components/Views/DetectedTokens/index.test.tsx b/app/components/Views/DetectedTokens/index.test.tsx
deleted file mode 100644
index 965524d4e5e..00000000000
--- a/app/components/Views/DetectedTokens/index.test.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import React from 'react';
-import { fireEvent, render } from '@testing-library/react-native';
-import { useDispatch, useSelector } from 'react-redux';
-import DetectedTokens from '.';
-import {
- selectAllDetectedTokensFlat,
- selectDetectedTokens,
-} from '../../../selectors/tokensController';
-import {
- selectEvmChainId,
- selectEvmNetworkConfigurationsByChainId,
-} from '../../../selectors/networkController';
-import { selectTokensBalances } from '../../../selectors/tokenBalancesController';
-import { selectSelectedInternalAccountAddress } from '../../../selectors/accountsController';
-import { ThemeContext } from '../../../util/theme';
-import { DetectedTokensSelectorIDs } from './DetectedTokensView.testIds';
-
-// Mock dependencies
-jest.mock('react-redux', () => ({
- useDispatch: jest.fn(),
- useSelector: jest.fn(),
-}));
-
-const mockNavigate = jest.fn();
-jest.mock('@react-navigation/native', () => ({
- useNavigation: jest.fn(() => ({
- navigate: mockNavigate,
- })),
-}));
-
-jest.mock('../../../util/theme', () => {
- const { mockTheme } = jest.requireActual('../../../util/theme');
- return {
- useTheme: jest.fn(() => mockTheme),
- };
-});
-
-jest.mock(
- '../../../component-library/components/BottomSheets/BottomSheet',
- () => ({
- __esModule: true,
- default: jest.fn(({ children }) => <>{children}>),
- }),
-);
-
-jest.mock('../../../components/hooks/useAnalytics/useAnalytics', () => ({
- useAnalytics: jest.fn(() => ({
- trackEvent: jest.fn(),
- createEventBuilder: jest.fn(() => ({
- addProperties: jest.fn(() => ({
- build: jest.fn(),
- })),
- })),
- })),
-}));
-
-jest.mock('../../UI/TokenImage', () => () => null);
-
-jest.mock('../../UI/AssetOverview/Balance/Balance', () => ({
- // Mock other exports if needed, or leave empty
- __esModule: true,
- NetworkBadgeSource: jest.fn(() => 'mocked-network-badge-source'),
-}));
-
-const mockTheme = {
- colors: {
- background: { default: 'white' },
- border: { default: 'red' },
- text: { default: 'black' },
- error: { default: 'red' },
- warning: { default: 'yellow' },
- primary: { default: 'blue', inverse: 'orange' },
- overlay: { inverse: 'blue' },
- },
- themeAppearance: 'light',
-};
-
-describe('DetectedTokens Component', () => {
- const mockDispatch = jest.fn();
-
- beforeEach(() => {
- jest.clearAllMocks();
- (useDispatch as jest.Mock).mockReturnValue(mockDispatch);
- (useSelector as jest.Mock).mockImplementation((selector) => {
- if (selector === selectDetectedTokens) {
- return [
- { address: '0xToken1', symbol: 'TKN1', chainId: '1' },
- { address: '0xToken2', symbol: 'TKN2', chainId: '1' },
- ];
- }
- if (selector === selectSelectedInternalAccountAddress) return '0xAccount';
- if (selector === selectTokensBalances)
- return {
- '0xAccount': { '1': '1000000000000000000' }, // 1 token
- };
- if (selector === selectAllDetectedTokensFlat) {
- return [
- { address: '0xToken1', symbol: 'TKN1', chainId: '1' },
- { address: '0xToken2', symbol: 'TKN2', chainId: '1' },
- ];
- }
- if (selector === selectEvmChainId) return '1';
- if (selector === selectEvmNetworkConfigurationsByChainId) return {};
- return {};
- });
- });
-
- it('renders correctly with detected tokens', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- expect(getByText('2 new tokens found')).toBeOnTheScreen();
- expect(getByText('0 TKN1')).toBeOnTheScreen();
- expect(getByText('0 TKN2')).toBeOnTheScreen();
- expect(getByText('Import (2)')).toBeOnTheScreen();
- });
-
- it('renders zero-token state with disabled import button', () => {
- (useSelector as jest.Mock).mockImplementation((selector) => {
- if (selector === selectDetectedTokens) return [];
- if (selector === selectAllDetectedTokensFlat) return [];
- if (selector === selectEvmChainId) return '1';
- if (selector === selectEvmNetworkConfigurationsByChainId) return {};
- return {};
- });
-
- const { getByText, getByTestId } = render(
-
-
- ,
- );
-
- expect(getByText('0 new token found')).toBeOnTheScreen();
- expect(getByText('Import (0)')).toBeOnTheScreen();
- expect(
- getByTestId(DetectedTokensSelectorIDs.IMPORT_BUTTON_ID),
- ).toBeDisabled();
- });
-
- it('navigates to confirmation on "Hide All" button press', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- const hideAllButton = getByText('Hide all');
- fireEvent.press(hideAllButton);
-
- expect(mockNavigate).toHaveBeenCalledWith(
- 'DetectedTokensConfirmation',
- expect.objectContaining({ isHidingAll: true }),
- );
- });
-});
diff --git a/app/components/Views/DetectedTokens/index.tsx b/app/components/Views/DetectedTokens/index.tsx
deleted file mode 100644
index c7cadeaebde..00000000000
--- a/app/components/Views/DetectedTokens/index.tsx
+++ /dev/null
@@ -1,413 +0,0 @@
-// Third party dependencies
-import React, { useRef, useState, useCallback, useMemo } from 'react';
-import { StyleSheet, View, Text, InteractionManager } from 'react-native';
-import { useSelector } from 'react-redux';
-import { Token as TokenType } from '@metamask/assets-controllers';
-import { useNavigation } from '@react-navigation/native';
-import { FlatList } from 'react-native-gesture-handler';
-import { Hex } from '@metamask/utils';
-
-// External Dependencies
-import { MetaMetricsEvents } from '../../../core/Analytics';
-import { fontStyles } from '../../../styles/common';
-import StyledButton from '../../UI/StyledButton';
-import Token from './components/Token';
-import Engine from '../../../core/Engine';
-import NotificationManager from '../../../core/NotificationManager';
-import { strings } from '../../../../locales/i18n';
-import Logger from '../../../util/Logger';
-import { useTheme } from '../../../util/theme';
-import { getDecimalChainId } from '../../../util/networks';
-import { createNavigationDetails } from '../../../util/navigation/navUtils';
-import Routes from '../../../constants/navigation/Routes';
-import {
- selectDetectedTokens,
- selectAllDetectedTokensFlat,
-} from '../../../selectors/tokensController';
-import {
- selectEvmChainId,
- selectEvmNetworkConfigurationsByChainId,
- selectIsAllNetworks,
- selectIsPopularNetwork,
-} from '../../../selectors/networkController';
-import BottomSheet, {
- BottomSheetRef,
-} from '../../../component-library/components/BottomSheets/BottomSheet';
-import { useAnalytics } from '../../../components/hooks/useAnalytics/useAnalytics';
-import { DetectedTokensSelectorIDs } from './DetectedTokensView.testIds';
-import { TokenI } from '../../UI/Tokens/types';
-
-// TODO: Replace "any" with type
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-const createStyles = (colors: any) =>
- StyleSheet.create({
- fill: {
- flex: 1,
- },
- sheet: {
- backgroundColor: colors.background.default,
- borderTopLeftRadius: 20,
- borderTopRightRadius: 20,
- height: '75%',
- },
- notch: {
- width: 48,
- height: 5,
- borderRadius: 4,
- backgroundColor: colors.border.default,
- marginTop: 12,
- alignSelf: 'center',
- },
- headerLabel: {
- textAlign: 'center',
- ...fontStyles.normal,
- fontSize: 18,
- paddingVertical: 16,
- color: colors.text.default,
- },
- tokenList: { paddingHorizontal: 16 },
- buttonsContainer: {
- padding: 16,
- flexDirection: 'row',
- },
- buttonDivider: {
- width: 8,
- },
- });
-
-interface IgnoredTokensByAddress {
- [address: string]: true;
-}
-
-const DetectedTokens = () => {
- const navigation = useNavigation();
- const { trackEvent, createEventBuilder } = useAnalytics();
- const sheetRef = useRef(null);
- const detectedTokens = useSelector(selectDetectedTokens);
- const allDetectedTokens = useSelector(
- selectAllDetectedTokensFlat,
- ) as TokenI[];
- const allNetworks = useSelector(selectEvmNetworkConfigurationsByChainId);
- const chainId = useSelector(selectEvmChainId);
- const isPopularNetworks = useSelector(selectIsPopularNetwork);
- const [ignoredTokens, setIgnoredTokens] = useState(
- {},
- );
- const isAllNetworks = useSelector(selectIsAllNetworks);
-
- const { colors } = useTheme();
- const styles = createStyles(colors);
-
- const currentDetectedTokens =
- isAllNetworks && isPopularNetworks ? allDetectedTokens : detectedTokens;
-
- const detectedTokensForAnalytics = useMemo(
- () =>
- currentDetectedTokens.map(
- (token) => `${token.symbol} - ${token.address}`,
- ),
- [currentDetectedTokens],
- );
-
- const getTokenAddedAnalyticsParams = useCallback(
- ({ address, symbol }: { address: string; symbol: string }) => {
- try {
- return {
- token_address: address,
- token_symbol: symbol,
- chain_id: getDecimalChainId(chainId),
- source: 'Add token dropdown',
- };
- } catch (error) {
- Logger.error(
- error as Error,
- 'DetectedTokens.getTokenAddedAnalyticsParams',
- );
- return undefined;
- }
- },
- [chainId],
- );
-
- const dismissModalAndTriggerAction = useCallback(
- (ignoreAllTokens?: boolean) => {
- // TODO: Replace "any" with type
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const { TokensController } = Engine.context as any;
- let title = '';
- let description = '';
- let errorMsg = '';
- const tokensToIgnore: TokenType[] = [];
- const tokensToImport = currentDetectedTokens.filter((token) => {
- const isIgnored = ignoreAllTokens || ignoredTokens[token.address];
- if (isIgnored) {
- tokensToIgnore.push(token);
- }
- return !isIgnored;
- });
-
- // Update toast description accordingly
- if (tokensToImport.length === 0 && tokensToIgnore.length > 0) {
- // Ignoring all tokens
- title = strings('wallet.token_toast.tokens_hidden_title');
- description = strings('wallet.token_toast.tokens_hidden_desc');
- errorMsg = 'DetectedTokens: Failed to hide all detected tokens!';
- } else if (
- (tokensToImport.length > 0 && tokensToIgnore.length > 0) ||
- (tokensToImport.length > 0 && tokensToIgnore.length === 0)
- ) {
- // At least some tokens are imported
- title = strings('wallet.token_toast.tokens_imported_title');
- description = strings('wallet.token_toast.tokens_imported_desc', {
- tokenSymbols: tokensToImport
- .map((token) => token.symbol.toUpperCase())
- .join(', '),
- });
- errorMsg = 'DetectedTokens: Failed to import detected tokens!';
- }
-
- sheetRef.current?.onCloseBottomSheet(async () => {
- try {
- if (tokensToIgnore.length > 0) {
- // Group tokens by their `chainId` using a plain object
- const tokensToIgnoreByChainId: Record = {};
-
- for (const token of tokensToIgnore) {
- const tokenChainId: Hex =
- (token as TokenI & { chainId: Hex }).chainId ?? chainId;
-
- if (!tokensToIgnoreByChainId[tokenChainId]) {
- tokensToIgnoreByChainId[tokenChainId] = [];
- }
-
- tokensToIgnoreByChainId[tokenChainId].push(token);
- }
-
- // Process all grouped tokens in parallel
- const ignorePromises = Object.entries(tokensToIgnoreByChainId).map(
- async ([networkId, tokens]) => {
- const chainConfig = allNetworks[networkId as Hex];
- const { defaultRpcEndpointIndex } = chainConfig;
- const { networkClientId: networkInstanceId } =
- chainConfig.rpcEndpoints[defaultRpcEndpointIndex];
-
- const tokenAddresses = tokens.map((token) => token.address);
-
- await TokensController.ignoreTokens(
- tokenAddresses,
- networkInstanceId,
- );
- },
- );
-
- await Promise.all(ignorePromises);
- }
- if (tokensToImport.length > 0) {
- // Group tokens by their `chainId` using a plain object
- const tokensByChainId: Record = {};
-
- for (const token of tokensToImport) {
- const tokenChainId: Hex =
- (token as TokenI & { chainId: Hex }).chainId ?? chainId;
-
- if (!tokensByChainId[tokenChainId]) {
- tokensByChainId[tokenChainId] = [];
- }
-
- tokensByChainId[tokenChainId].push(token);
- }
-
- // Process grouped tokens in parallel
- const importPromises = Object.entries(tokensByChainId).map(
- async ([networkId, tokens]) => {
- const chainConfig = allNetworks[networkId as Hex];
- const { defaultRpcEndpointIndex } = chainConfig;
- const { networkClientId: networkInstanceId } =
- chainConfig.rpcEndpoints[defaultRpcEndpointIndex];
-
- await TokensController.addTokens(tokens, networkInstanceId);
- },
- );
-
- await Promise.all(importPromises);
- InteractionManager.runAfterInteractions(() => {
- tokensToImport.forEach(
- ({ address, symbol }: { address: string; symbol: string }) => {
- const analyticsParams = getTokenAddedAnalyticsParams({
- address,
- symbol,
- });
-
- if (analyticsParams) {
- trackEvent(
- createEventBuilder(MetaMetricsEvents.TOKEN_ADDED)
- .addProperties({
- token_address: address,
- token_symbol: symbol,
- chain_id: getDecimalChainId(chainId),
- source: 'detected',
- })
- .build(),
- );
- }
- },
- );
- });
- }
- NotificationManager.showSimpleNotification({
- status: `simple_notification`,
- duration: 5000,
- title,
- description,
- });
- } catch (err) {
- Logger.log(err, errorMsg);
- }
- });
- },
- [
- chainId,
- trackEvent,
- createEventBuilder,
- currentDetectedTokens,
- ignoredTokens,
- allNetworks,
- getTokenAddedAnalyticsParams,
- ],
- );
-
- const triggerIgnoreAllTokens = () => {
- navigation.navigate('DetectedTokensConfirmation', {
- onConfirm: () => dismissModalAndTriggerAction(true),
- isHidingAll: true,
- });
-
- trackEvent(
- createEventBuilder(MetaMetricsEvents.TOKENS_HIDDEN)
- .addProperties({
- location: 'token_detection',
- token_standard: 'ERC20',
- asset_type: 'token',
- tokens: detectedTokensForAnalytics,
- chain_id: getDecimalChainId(chainId),
- })
- .build(),
- );
- };
-
- const triggerImportTokens = async () => {
- if (Object.keys(ignoredTokens).length === 0) {
- // Import all tokens
- dismissModalAndTriggerAction();
- } else {
- // Handle ignoring all or mix of imports and ignored tokens
- navigation.navigate('DetectedTokensConfirmation', {
- onConfirm: () => dismissModalAndTriggerAction(),
- });
- }
- };
-
- const renderHeader = () => (
-
- {strings(
- `detected_tokens.title${
- currentDetectedTokens.length > 1 ? '_plural' : ''
- }`,
- {
- tokenCount: currentDetectedTokens.length,
- },
- )}
-
- );
-
- const renderToken = ({ item }: { item: TokenType }) => {
- const { address } = item;
- const isChecked = !ignoredTokens[address];
-
- return (
- {
- const newIgnoredTokens = { ...ignoredTokens };
- if (selected) {
- delete newIgnoredTokens[address];
- } else {
- newIgnoredTokens[address] = true;
- }
- setIgnoredTokens(newIgnoredTokens);
- }}
- />
- );
- };
-
- const getTokenId = (item: TokenType) => item.address;
-
- const renderDetectedTokens = () => (
-
- );
-
- const renderButtons = () => {
- const importTokenCount =
- currentDetectedTokens.length - Object.keys(ignoredTokens).length;
- return (
-
-
- {strings('detected_tokens.hide_cta')}
-
-
-
- {strings('detected_tokens.import_cta', {
- tokenCount: importTokenCount,
- })}
-
-
- );
- };
-
- const trackCancelWithoutAction = (hasPendingAction?: boolean) => {
- if (hasPendingAction) {
- return;
- }
- trackEvent(
- createEventBuilder(MetaMetricsEvents.TOKEN_IMPORT_CANCELED)
- .addProperties({
- source: 'detected',
- tokens: detectedTokensForAnalytics,
- chain_id: getDecimalChainId(chainId),
- })
- .build(),
- );
- };
-
- return (
-
- {renderHeader()}
- {renderDetectedTokens()}
- {renderButtons()}
-
- );
-};
-
-export const createDetectedTokensNavDetails = createNavigationDetails(
- Routes.MODAL.ROOT_MODAL_FLOW,
- Routes.MODAL.DETECTED_TOKENS,
-);
-
-export default DetectedTokens;
diff --git a/app/components/Views/DetectedTokensConfirmation/index.tsx b/app/components/Views/DetectedTokensConfirmation/index.tsx
deleted file mode 100644
index 91ea11e5273..00000000000
--- a/app/components/Views/DetectedTokensConfirmation/index.tsx
+++ /dev/null
@@ -1,130 +0,0 @@
-import React, { useRef } from 'react';
-import { StyleSheet, View, Text } from 'react-native';
-import { RouteProp, useRoute } from '@react-navigation/native';
-import ReusableModal, { ReusableModalRef } from '../../UI/ReusableModal';
-import { fontStyles } from '../../../styles/common';
-import StyledButton from '../../UI/StyledButton';
-import { strings } from '../../../../locales/i18n';
-import { useTheme } from '../../../util/theme';
-
-// TODO: Replace "any" with type
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-const createStyles = (colors: any) =>
- StyleSheet.create({
- fill: {
- flex: 1,
- },
- screen: { justifyContent: 'center' },
- modal: {
- backgroundColor: colors.background.default,
- borderRadius: 10,
- marginHorizontal: 16,
- },
- bodyContainer: {
- paddingHorizontal: 24,
- paddingVertical: 32,
- },
- headerLabel: {
- textAlign: 'center',
- // TODO: Replace "any" with type
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- ...(fontStyles.bold as any),
- fontSize: 24,
- marginBottom: 16,
- color: colors.text.default,
- },
- description: {
- textAlign: 'center',
- fontSize: 16,
- // TODO: Replace "any" with type
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- ...(fontStyles.normal as any),
- color: colors.text.default,
- },
- divider: {
- height: 1,
- backgroundColor: colors.border.muted,
- },
- buttonsContainer: {
- flexDirection: 'row',
- padding: 16,
- },
- buttonDivider: {
- width: 8,
- },
- });
-
-interface DetectedTokensConfirmationRouteParams {
- isHidingAll?: boolean;
- onConfirm: () => void;
-}
-
-const DetectedTokensConfirmation = () => {
- const route =
- useRoute<
- RouteProp<{ params: DetectedTokensConfirmationRouteParams }, 'params'>
- >();
- const { onConfirm, isHidingAll } = route.params;
- const modalRef = useRef(null);
- const { colors } = useTheme();
- const styles = createStyles(colors);
-
- const triggerCancel = () => modalRef.current?.dismissModal();
-
- const triggerConfirm = () => {
- modalRef.current?.dismissModal(onConfirm);
- };
-
- const renderHeader = () => (
-
- {strings(
- `detected_tokens.confirm.${
- isHidingAll ? 'hide.title' : 'import.title'
- }`,
- )}
-
- );
-
- const renderDescription = () => (
-
- {strings(
- `detected_tokens.confirm.${isHidingAll ? 'hide.desc' : 'import.desc'}`,
- )}
-
- );
-
- const renderButtons = () => (
-
-
- {strings('detected_tokens.confirm.cancel_cta')}
-
-
-
- {strings('detected_tokens.confirm.confirm_cta')}
-
-
- );
-
- return (
-
-
-
- {renderHeader()}
- {renderDescription()}
-
-
- {renderButtons()}
-
-
- );
-};
-
-export default DetectedTokensConfirmation;
diff --git a/app/components/Views/Wallet/index.test.tsx b/app/components/Views/Wallet/index.test.tsx
index 28e7d5f0942..29276ea3218 100644
--- a/app/components/Views/Wallet/index.test.tsx
+++ b/app/components/Views/Wallet/index.test.tsx
@@ -393,9 +393,6 @@ jest.mock('../../../core/Engine', () => {
PreferencesController: {
setTokenNetworkFilter: jest.fn(),
},
- TokensController: {
- addTokens: jest.fn(),
- },
NetworkEnablementController: {
setEnabledNetwork: jest.fn(),
setDisabledNetwork: jest.fn(),
@@ -512,17 +509,6 @@ const mockInitialState = {
},
},
},
- TokensController: {
- ...backgroundState.TokensController,
- detectedTokens: [{ address: '0x123' }],
- allDetectedTokens: {
- '0x1': {
- '0xc4966c0d659d99699bfd7eb54d8fafee40e4a756': [
- { address: '0x123' },
- ],
- },
- },
- },
RewardsController: {
activeAccount: null,
},
@@ -740,29 +726,6 @@ const renderWalletWithRootState = (rootState: typeof mockInitialState) =>
},
);
-const renderWithoutDetectedTokens = (Component: React.ComponentType) =>
- renderScreen(
- Component,
- {
- name: Routes.WALLET_VIEW,
- },
- {
- state: {
- ...mockInitialState,
- engine: {
- backgroundState: {
- ...mockInitialState.engine.backgroundState,
- TokensController: {
- ...mockInitialState.engine.backgroundState.TokensController,
- // @ts-expect-error we are testing the invalid case
- detectedTokens: 'invalid-array',
- },
- },
- },
- },
- },
- );
-
describe('Wallet', () => {
afterEach(() => {
jest.clearAllMocks();
@@ -784,12 +747,6 @@ describe('Wallet', () => {
expect(mockTabsListComponent).toHaveBeenCalled();
});
- it('should render correctly when there are no detected tokens', () => {
- //@ts-expect-error we are ignoring the navigation params on purpose because we do not want to mock setOptions to test the navbar
- renderWithoutDetectedTokens(Wallet);
- expect(mockTabsListComponent).toHaveBeenCalled();
- });
-
it('should render TabsList', () => {
//@ts-expect-error we are ignoring the navigation params on purpose because we do not want to mock setOptions to test the navbar
render(Wallet);
@@ -798,15 +755,6 @@ describe('Wallet', () => {
expect(mockTabsListComponent).toHaveBeenCalled();
});
- it('Should add tokens to state automatically when there are detected tokens', () => {
- const mockedAddTokens = jest.mocked(Engine.context.TokensController);
-
- //@ts-expect-error we are ignoring the navigation params on purpose because we do not want to mock setOptions to test the navbar
- render(Wallet);
-
- expect(mockedAddTokens.addTokens).toHaveBeenCalledTimes(1);
- });
-
it('should render correctly when Solana support is enabled', () => {
jest
.mocked(useSelector)
diff --git a/app/components/Views/Wallet/index.tsx b/app/components/Views/Wallet/index.tsx
index afcdeb118bf..5a1aa9c1ef4 100644
--- a/app/components/Views/Wallet/index.tsx
+++ b/app/components/Views/Wallet/index.tsx
@@ -104,33 +104,20 @@ import {
ActionLocation,
ActionPosition,
} from '../../../util/analytics/actionButtonTracking';
-import Engine from '../../../core/Engine';
import { RootState } from '../../../reducers';
import { selectSelectedInternalAccount } from '../../../selectors/accountsController';
import { selectAccountBalanceByChainId } from '../../../selectors/accountTrackerController';
import {
selectChainId,
- selectEvmNetworkConfigurationsByChainId,
- selectIsAllNetworks,
- selectIsPopularNetwork,
- selectNetworkClientId,
selectProviderConfig,
} from '../../../selectors/networkController';
import {
getMetamaskNotificationsUnreadCount,
selectIsMetamaskNotificationsEnabled,
} from '../../../selectors/notifications';
-import {
- selectAllDetectedTokensFlat,
- selectDetectedTokens,
-} from '../../../selectors/tokensController';
import { selectSelectedAccountGroupId } from '../../../selectors/multichainAccounts/accountTreeController';
import { selectShouldShowWalletHomeOnboardingSteps } from '../../../selectors/onboarding';
-import {
- getDecimalChainId,
- getIsNetworkOnboarded,
- isTestNet,
-} from '../../../util/networks';
+import { getIsNetworkOnboarded, isTestNet } from '../../../util/networks';
import NotificationsService from '../../../util/notifications/services/NotificationService';
import { useTheme } from '../../../util/theme';
import { useAccountGroupName } from '../../hooks/multichainAccounts/useAccountGroupName';
@@ -139,8 +126,6 @@ import usePrevious from '../../hooks/usePrevious';
import { PERFORMANCE_CONFIG } from '@metamask/perps-controller';
import ErrorBoundary from '../ErrorBoundary';
-import { Token } from '@metamask/assets-controllers';
-import { Hex } from '@metamask/utils';
import { selectIsEvmNetworkSelected } from '../../../selectors/multichainNetworkController';
import {
selectHomepageSectionsV1Enabled,
@@ -162,13 +147,11 @@ import useCheckNftAutoDetectionModal from '../../hooks/useCheckNftAutoDetectionM
import useCheckMultiRpcModal from '../../hooks/useCheckMultiRpcModal';
import { useMultichainAccountsIntroModal } from '../../hooks/useMultichainAccountsIntroModal';
import { useAccountsWithNetworkActivitySync } from '../../hooks/useAccountsWithNetworkActivitySync';
-import { selectUseTokenDetection } from '../../../selectors/preferencesController';
import Logger from '../../../util/Logger';
import { useNftDetection } from '../../hooks/useNftDetection';
import BrazeBanner from '../../UI/BrazeBanner';
import ComponentErrorBoundary from '../../UI/ComponentErrorBoundary';
import { BRAZE_BANNER_WALLET_HOME_PLACEMENT_ID } from '../../../core/Braze/constants';
-import { TokenI } from '../../UI/Tokens/types';
import NetworkConnectionBanner from '../../UI/NetworkConnectionBanner';
import { selectAssetsDefiPositionsEnabled } from '../../../selectors/featureFlagController/assetsDefiPositions';
@@ -714,9 +697,6 @@ const Wallet = ({
const dispatch = useDispatch();
const { navigateToSendPage } = useSendNavigation();
- const evmNetworkConfigurations = useSelector(
- selectEvmNetworkConfigurationsByChainId,
- );
const { popularEvmNetworks: evmChainIds } = useNetworkEnablement();
/**
@@ -1067,19 +1047,8 @@ const Wallet = ({
getMetamaskNotificationsUnreadCount,
);
- const isAllNetworks = useSelector(selectIsAllNetworks);
- const isTokenDetectionEnabled = useSelector(selectUseTokenDetection);
- const isPopularNetworks = useSelector(selectIsPopularNetwork);
- const detectedTokens = useSelector(selectDetectedTokens) as TokenI[];
const homeGrowthBanner = useHomeGrowthBanner();
- const allDetectedTokens = useSelector(
- selectAllDetectedTokensFlat,
- ) as TokenI[];
- const currentDetectedTokens =
- isAllNetworks && isPopularNetworks ? allDetectedTokens : detectedTokens;
- const selectedNetworkClientId = useSelector(selectNetworkClientId);
-
const { detectNfts } = useNftDetection();
/**
@@ -1204,104 +1173,6 @@ const Wallet = ({
navigation.navigate(Routes.TRANSACTIONS_VIEW);
}, [navigation, trackEvent]);
- const getTokenAddedAnalyticsParams = useCallback(
- ({ address, symbol }: { address: string; symbol: string }) => {
- try {
- return {
- token_address: address,
- token_symbol: symbol,
- chain_id: getDecimalChainId(chainId),
- source: 'Add token dropdown',
- };
- } catch (error) {
- Logger.error(
- error as Error,
- 'SearchTokenAutocomplete.getTokenAddedAnalyticsParams',
- );
- return undefined;
- }
- },
- [chainId],
- );
-
- useEffect(() => {
- const importAllDetectedTokens = async () => {
- // If autodetect tokens toggle is OFF, return
- if (!isTokenDetectionEnabled) {
- return;
- }
- const { TokensController } = Engine.context;
- if (
- Array.isArray(currentDetectedTokens) &&
- currentDetectedTokens.length > 0
- ) {
- // Group tokens by their `chainId` using a plain object
- const tokensByChainId: Record = {};
-
- for (const token of currentDetectedTokens) {
- // TODO: [SOLANA] Check if this logic supports non evm networks before shipping Solana
- const tokenChainId: Hex =
- (token as TokenI & { chainId: Hex }).chainId ?? chainId;
-
- if (!tokensByChainId[tokenChainId]) {
- tokensByChainId[tokenChainId] = [];
- }
-
- tokensByChainId[tokenChainId].push(token);
- }
-
- // Process grouped tokens in parallel
- const importPromises = Object.entries(tokensByChainId).map(
- async ([networkId, allTokens]) => {
- const chainConfig = evmNetworkConfigurations[networkId as Hex];
- const { defaultRpcEndpointIndex } = chainConfig;
- const { networkClientId: networkInstanceId } =
- chainConfig.rpcEndpoints[defaultRpcEndpointIndex];
-
- await TokensController.addTokens(allTokens, networkInstanceId);
- },
- );
-
- await Promise.all(importPromises);
-
- currentDetectedTokens.forEach(
- ({ address, symbol }: { address: string; symbol: string }) => {
- const analyticsParams = getTokenAddedAnalyticsParams({
- address,
- symbol,
- });
-
- if (analyticsParams) {
- trackEvent(
- createEventBuilder(MetaMetricsEvents.TOKEN_ADDED)
- .addProperties({
- token_address: address,
- token_symbol: symbol,
- chain_id: getDecimalChainId(chainId),
- source: 'detected',
- })
- .build(),
- );
- }
- },
- );
- }
- };
- if (isEvmSelected) {
- importAllDetectedTokens();
- }
- }, [
- isEvmSelected,
- isTokenDetectionEnabled,
- evmNetworkConfigurations,
- chainId,
- currentDetectedTokens,
- selectedNetworkClientId,
- getTokenAddedAnalyticsParams,
- trackEvent,
- createEventBuilder,
- ]);
-
const onChangeTab = useCallback(
(obj: { i: number; ref: React.ReactNode }) => {
const tabLabel =
diff --git a/app/components/hooks/useMultichainBalances/useSelectedAccountMultichainBalances.test.ts b/app/components/hooks/useMultichainBalances/useSelectedAccountMultichainBalances.test.ts
index 1aa59ebd6b9..dfe9d0590f1 100644
--- a/app/components/hooks/useMultichainBalances/useSelectedAccountMultichainBalances.test.ts
+++ b/app/components/hooks/useMultichainBalances/useSelectedAccountMultichainBalances.test.ts
@@ -63,7 +63,6 @@ const MOCK_STORE_STATE = {
TokensController: {
allTokens: {},
allIgnoredTokens: {},
- allDetectedTokens: {},
},
NetworkEnablementController: {
enabledNetworks: ['0x1', '0x89'],
diff --git a/app/components/hooks/useNetworkSelection/useNetworkSelection.test.ts b/app/components/hooks/useNetworkSelection/useNetworkSelection.test.ts
index f3f12ae7447..49e0da076f6 100644
--- a/app/components/hooks/useNetworkSelection/useNetworkSelection.test.ts
+++ b/app/components/hooks/useNetworkSelection/useNetworkSelection.test.ts
@@ -140,7 +140,6 @@ jest.mock('../../../reducers/swaps', () => ({
jest.mock('../../../selectors/tokensController', () => ({
selectTokens: jest.fn(),
- selectTokensControllerState: jest.fn(),
selectAllTokens: jest.fn(),
}));
diff --git a/app/constants/navigation/Routes.ts b/app/constants/navigation/Routes.ts
index 522163ab78b..4db5ea31894 100644
--- a/app/constants/navigation/Routes.ts
+++ b/app/constants/navigation/Routes.ts
@@ -147,7 +147,6 @@ const Routes = {
WHATS_NEW: 'WhatsNewModal',
TURN_OFF_REMEMBER_ME: 'TurnOffRememberMeModal',
UPDATE_NEEDED: 'UpdateNeededModal',
- DETECTED_TOKENS: 'DetectedTokens',
SRP_REVEAL_QUIZ: 'SRPRevealQuiz',
WALLET_ACTIONS: 'WalletActions',
TRADE_WALLET_ACTIONS: 'TradeWalletActions',
diff --git a/app/selectors/smartTransactionsController.test.ts b/app/selectors/smartTransactionsController.test.ts
index ab5e6acb701..044b90be3af 100644
--- a/app/selectors/smartTransactionsController.test.ts
+++ b/app/selectors/smartTransactionsController.test.ts
@@ -28,7 +28,6 @@ jest.mock('./accountsController', () => {
});
jest.mock('./tokensController', () => ({
- selectTokensControllerState: jest.fn(),
selectTokens: jest.fn(() => []),
selectAllTokens: jest.fn(() => []),
}));
diff --git a/app/selectors/tokensController.test.ts b/app/selectors/tokensController.test.ts
index 1c453f6bb86..35197751ea9 100644
--- a/app/selectors/tokensController.test.ts
+++ b/app/selectors/tokensController.test.ts
@@ -5,10 +5,7 @@ import {
selectTokensByAddress,
selectTokensLength,
selectIgnoreTokens,
- selectDetectedTokens,
selectAllTokensFlat,
- selectAllDetectedTokensForSelectedAddress,
- selectAllDetectedTokensFlat,
selectTokensByChainIdAndAddress,
selectTokensByChainIdAndWalletAddress,
getChainIdsToPoll,
@@ -27,14 +24,6 @@ describe('TokensController Selectors', () => {
'0xAddress2': [mockToken2],
},
},
- allDetectedTokens: {
- '0x1': {
- '0xAddress1': [mockToken],
- },
- '0x2': {
- '0xAddress2': [mockToken2],
- },
- },
allIgnoredTokens: {
'0x1': {
'0xAddress1': ['0xToken2'],
@@ -209,38 +198,6 @@ describe('TokensController Selectors', () => {
});
});
- describe('selectDetectedTokens', () => {
- it('returns detected tokens', () => {
- expect(selectDetectedTokens(mockRootState)).toStrictEqual([mockToken]);
- });
-
- it('returns undefined if no detected tokens are present', () => {
- const stateWithoutDetectedTokens = {
- ...mockRootState,
- engine: {
- backgroundState: {
- TokensController: {
- ...mockTokensControllerState,
- allDetectedTokens: undefined,
- },
- AccountsController: {
- internalAccounts: {
- selectedAccount: '0xAddress1',
- accounts: {
- '0xAddress1': {
- address: '0xAddress1',
- },
- },
- },
- },
- },
- },
- } as unknown as RootState;
-
- expect(selectDetectedTokens(stateWithoutDetectedTokens)).toBeUndefined();
- });
- });
-
describe('selectAllTokensFlat', () => {
it('returns all tokens as a flat array', () => {
expect(selectAllTokensFlat(mockRootState)).toStrictEqual([
@@ -266,62 +223,6 @@ describe('TokensController Selectors', () => {
});
});
- describe('selectAllDetectedTokensForSelectedAddress', () => {
- it('returns detected tokens for the selected address', () => {
- const detectedTokens =
- selectAllDetectedTokensForSelectedAddress.resultFunc(
- mockTokensControllerState as unknown as TokensControllerState,
- '0xAddress1',
- );
- expect(detectedTokens).toStrictEqual({
- '0x1': [{ ...mockToken, chainId: '0x1' }],
- });
- });
-
- it('returns an empty object if no selected address is provided', () => {
- const detectedTokens =
- selectAllDetectedTokensForSelectedAddress.resultFunc(
- mockTokensControllerState as unknown as TokensControllerState,
- undefined,
- );
- expect(detectedTokens).toStrictEqual({});
- });
- });
-
- describe('selectAllDetectedTokensFlat', () => {
- it('returns all detected tokens as a flat array', () => {
- const detectedTokens = selectAllDetectedTokensFlat.resultFunc({
- '0x1': [mockToken as Token],
- '0x2': [mockToken2 as Token],
- });
- expect(detectedTokens).toStrictEqual([
- { ...mockToken, chainId: '0x1' },
- { ...mockToken2, chainId: '0x2' },
- ]);
- });
-
- it('returns an empty array if no detected tokens are present', () => {
- const detectedTokens = selectAllDetectedTokensFlat.resultFunc({});
- expect(detectedTokens).toStrictEqual([]);
- });
-
- it('preserves chain ID in detected tokens', () => {
- const detectedTokens = selectAllDetectedTokensFlat.resultFunc({
- '0x1': [mockToken as Token],
- '0x2': [mockToken2 as Token],
- });
- expect(detectedTokens).toStrictEqual([
- { ...mockToken, chainId: '0x1' },
- { ...mockToken2, chainId: '0x2' },
- ]);
- });
-
- it('handles empty detected tokens gracefully', () => {
- const detectedTokens = selectAllDetectedTokensFlat.resultFunc({});
- expect(detectedTokens).toStrictEqual([]);
- });
- });
-
describe('selectTokensByChainIdAndAddress', () => {
it('returns mapped tokens for given chain ID', () => {
expect(
diff --git a/app/selectors/tokensController.ts b/app/selectors/tokensController.ts
index 25d2b2d88fa..cd59f8b489c 100644
--- a/app/selectors/tokensController.ts
+++ b/app/selectors/tokensController.ts
@@ -17,13 +17,6 @@ import {
getTokensControllerAllTokens,
} from './assets/assets-migration';
-/**
- * @deprecated
- * This selector accesses deprecated AssetsController state directly.
- */
-const selectTokensControllerState = (state: RootState) =>
- state?.engine?.backgroundState?.TokensController;
-
export const selectTokens = createDeepEqualSelector(
getTokensControllerAllTokens,
selectEvmChainId,
@@ -106,24 +99,6 @@ export const selectIgnoreTokens = createSelector(
) => allIgnoredTokens?.[chainId]?.[selectedAddress as Hex],
);
-/**
- * @deprecated
- * This selector accesses deprecated AssetsController state directly.
- */
-export const selectDetectedTokens = createSelector(
- selectTokensControllerState,
- selectEvmChainId,
- selectSelectedInternalAccountAddress,
- (
- tokensControllerState: TokensControllerState,
- chainId: Hex,
- selectedAddress: string | undefined,
- ) =>
- tokensControllerState?.allDetectedTokens?.[chainId]?.[
- selectedAddress as Hex
- ],
-);
-
export { getTokensControllerAllTokens as selectAllTokens };
export const getChainIdsToPoll = createDeepEqualSelector(
@@ -160,60 +135,6 @@ export const selectAllTokensFlat = createSelector(
},
);
-/**
- * @deprecated
- * This selector accesses deprecated AssetsController state directly.
- */
-export const selectAllDetectedTokensForSelectedAddress = createSelector(
- selectTokensControllerState,
- selectSelectedInternalAccountAddress,
- (tokensControllerState, selectedAddress) => {
- // Updated return type to specify the structure more clearly
- if (!selectedAddress) {
- return {} as { [chainId: Hex]: Token[] }; // Specify return type
- }
-
- return Object.entries(
- tokensControllerState?.allDetectedTokens || {},
- ).reduce<{
- [chainId: string]: Token[];
- }>((acc, [chainId, chainTokens]) => {
- const tokensForAddress = chainTokens[selectedAddress] || [];
- if (tokensForAddress.length > 0) {
- acc[chainId] = tokensForAddress.map((token: Token) => ({
- ...token,
- chainId,
- }));
- }
- return acc;
- }, {});
- },
-);
-
-export const selectAllDetectedTokensFlat = createSelector(
- selectAllDetectedTokensForSelectedAddress,
- (detectedTokensByChain: { [chainId: string]: Token[] }) => {
- if (Object.keys(detectedTokensByChain).length === 0) {
- return [];
- }
-
- const flattenedTokens: (Token & { chainId: Hex })[] = [];
-
- for (const [chainId, addressTokens] of Object.entries(
- detectedTokensByChain,
- )) {
- for (const token of addressTokens) {
- flattenedTokens.push({
- ...token,
- chainId: chainId as Hex,
- });
- }
- }
-
- return flattenedTokens;
- },
-);
-
// Full selector implementation with selected address filtering
export const selectTransformedTokens = createSelector(
getTokensControllerAllTokens,
diff --git a/docs/bigint-migration-guide.md b/docs/bigint-migration-guide.md
index c7e87faa1c8..231b29136ca 100644
--- a/docs/bigint-migration-guide.md
+++ b/docs/bigint-migration-guide.md
@@ -136,7 +136,6 @@ Includes Stake UI and Money paths owned via `**/Earn/**`, `**/earn/**`, `**/Mone
- `app/components/UI/Tokens/util/deriveBalanceFromAssetMarketDetails.test.ts`
- `app/components/UI/Tokens/util/deriveBalanceFromAssetMarketDetails.ts`
- `app/components/Views/AssetDetails/index.tsx`
-- `app/components/Views/DetectedTokens/components/Token.tsx`
- `app/selectors/assets/assets-list.ts`
### @MetaMask/mobile-core-ux
diff --git a/tests/framework/fixtures/FixtureBuilder.ts b/tests/framework/fixtures/FixtureBuilder.ts
index 15c4cbc284d..a270ebfc191 100644
--- a/tests/framework/fixtures/FixtureBuilder.ts
+++ b/tests/framework/fixtures/FixtureBuilder.ts
@@ -1488,17 +1488,6 @@ class FixtureBuilder {
return this;
}
- withDetectedTokens(tokens: Record[]) {
- merge(this.fixture.state.engine.backgroundState.TokensController, {
- allDetectedTokens: {
- [CHAIN_IDS.MAINNET]: {
- [DEFAULT_FIXTURE_ACCOUNT]: tokens,
- },
- },
- });
- return this;
- }
-
withIncomingTransactionPreferences(incomingTransactionPreferences: boolean) {
merge(this.fixture.state.engine.backgroundState.PreferencesController, {
showIncomingTransactions: incomingTransactionPreferences,
diff --git a/tests/page-objects/wallet/DetectedTokensView.ts b/tests/page-objects/wallet/DetectedTokensView.ts
deleted file mode 100644
index a57cb91e549..00000000000
--- a/tests/page-objects/wallet/DetectedTokensView.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { DetectedTokensSelectorIDs } from '../../../app/components/Views/DetectedTokens/DetectedTokensView.testIds';
-import Gestures from '../../framework/Gestures';
-import Matchers from '../../framework/Matchers';
-
-class DetectedTokensView {
- get importButton(): DetoxElement {
- return device.getPlatform() === 'ios'
- ? Matchers.getElementByID(DetectedTokensSelectorIDs.IMPORT_BUTTON_ID)
- : Matchers.getElementByLabel(DetectedTokensSelectorIDs.IMPORT_BUTTON_ID);
- }
-
- async tapImport(): Promise {
- await Gestures.waitAndTap(this.importButton, {
- elemDescription: 'Import Button in Detected Tokens View',
- });
- }
-}
-
-export default new DetectedTokensView();
diff --git a/tests/regression/assets/token-detection-import-all.spec.ts b/tests/regression/assets/token-detection-import-all.spec.ts
deleted file mode 100644
index 72a6a06c61d..00000000000
--- a/tests/regression/assets/token-detection-import-all.spec.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-'use strict';
-import { loginToApp } from '../../flows/wallet.flow';
-import { RegressionAssets } from '../../tags';
-import WalletView from '../../page-objects/wallet/WalletView';
-import Assertions from '../../framework/Assertions';
-import TestHelpers from '../../helpers';
-import FixtureBuilder from '../../framework/fixtures/FixtureBuilder';
-import { withFixtures } from '../../framework/fixtures/FixtureHelper';
-
-const ETHEREUM_NAME = 'Ethereum';
-const USDC_NAME = 'USDCoin';
-
-describe(RegressionAssets('Import all tokens detected'), () => {
- beforeAll(async () => {
- jest.setTimeout(150000);
- await TestHelpers.reverseServerPort();
- });
-
- it('should import all tokens detected automatically', async () => {
- await withFixtures(
- {
- fixture: new FixtureBuilder()
- .withDetectedTokens([
- {
- address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
- decimals: 18,
- symbol: 'USDC',
- chainId: '0x1',
- name: 'USDCoin',
- },
- ])
- .build(),
- restartDevice: true,
- },
- async () => {
- await loginToApp();
-
- await Assertions.expectElementToBeVisible(WalletView.container);
- const eth = WalletView.tokenInWallet(ETHEREUM_NAME);
- const usdc = WalletView.tokenInWallet(USDC_NAME);
-
- await Assertions.expectElementToBeVisible(eth);
- await Assertions.expectElementToBeVisible(usdc);
- },
- );
- });
-});