diff --git a/.eslintrc.js b/.eslintrc.js index 58a606864521..fe907c50c259 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/.github/CODEOWNERS b/.github/CODEOWNERS index eab0a91e5898..6c7581fcf50d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -262,7 +262,6 @@ app/components/Views/AssetHideConfirmation @MetaMask/metamask-assets app/components/Views/AssetOptions @MetaMask/metamask-assets app/components/Views/Collectible @MetaMask/metamask-assets app/components/Views/CollectibleView @MetaMask/metamask-assets -app/components/Views/DetectedTokens @MetaMask/metamask-assets app/components/Views/NFTAutoDetectionModal @MetaMask/metamask-assets app/components/Views/NftDetails @MetaMask/metamask-assets app/reducers/collectibles @MetaMask/metamask-assets diff --git a/app/component-library/components-temp/MultichainAccounts/AccountCell/AccountCell.stories.tsx b/app/component-library/components-temp/MultichainAccounts/AccountCell/AccountCell.stories.tsx index 338b4daeb538..6e1e36d9c086 100644 --- a/app/component-library/components-temp/MultichainAccounts/AccountCell/AccountCell.stories.tsx +++ b/app/component-library/components-temp/MultichainAccounts/AccountCell/AccountCell.stories.tsx @@ -79,7 +79,6 @@ const mockStore = configureStore({ TokensController: { allTokens: {}, allIgnoredTokens: {}, - allDetectedTokens: {}, }, CurrencyRateController: { currentCurrency: 'usd', diff --git a/app/components/Nav/App/App.test.tsx b/app/components/Nav/App/App.test.tsx index d72cd66cf286..fda94b6d6c43 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 c3ceacfc9aa2..8b6626b58718 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/UI/Card/hooks/useAssetBalances.test.ts b/app/components/UI/Card/hooks/useAssetBalances.test.ts index 746196afb20b..4a24a45ce06f 100644 --- a/app/components/UI/Card/hooks/useAssetBalances.test.ts +++ b/app/components/UI/Card/hooks/useAssetBalances.test.ts @@ -131,7 +131,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -218,7 +217,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -449,7 +447,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -546,7 +543,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -694,7 +690,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -754,7 +749,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -804,7 +798,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -870,7 +863,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: {}, @@ -1017,7 +1009,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1089,7 +1080,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1161,7 +1151,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1233,7 +1222,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1291,7 +1279,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1356,7 +1343,6 @@ describe('useAssetBalances', () => { backgroundState: { TokensController: { allTokens: {}, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1426,7 +1412,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1496,7 +1481,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1877,7 +1861,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -1944,7 +1927,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -2012,7 +1994,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { @@ -2079,7 +2060,6 @@ describe('useAssetBalances', () => { 'mock-account': [walletAsset], }, }, - allDetectedTokens: {}, }, NetworkController: { networkConfigurationsByChainId: { diff --git a/app/components/UI/Card/hooks/useAssetBalances.tsx b/app/components/UI/Card/hooks/useAssetBalances.tsx index 208f5e886ceb..6b8663b7a5b0 100644 --- a/app/components/UI/Card/hooks/useAssetBalances.tsx +++ b/app/components/UI/Card/hooks/useAssetBalances.tsx @@ -95,10 +95,6 @@ export const useAssetBalances = ( // Get raw state needed for asset lookups - these are stable references from Redux const allAssets = useSelector(getTokensControllerAllTokens); - const allDetectedTokens = useSelector( - (state: RootState) => - state.engine.backgroundState.TokensController.allDetectedTokens, - ); const networkConfigs = useSelector( (state: RootState) => state.engine.backgroundState.NetworkController @@ -124,7 +120,6 @@ export const useAssetBalances = ( // Manually lookup asset from raw state (similar to selectAsset) const allTokensForChain = allAssets?.[chainId as Hex]; - const detectedTokensForChain = allDetectedTokens?.[chainId as Hex]; let asset: TokenI | undefined; if (allTokensForChain) { @@ -139,18 +134,6 @@ export const useAssetBalances = ( } } } - if (!asset && detectedTokensForChain) { - for (const accountTokens of Object.values(detectedTokensForChain)) { - const found = (accountTokens as TokenI[])?.find( - (t) => - t.address?.toLowerCase() === token.address?.toLowerCase(), - ); - if (found) { - asset = found; - break; - } - } - } if (asset) { const key = `${token.address.toLowerCase()}-${token.caipChainId}`; @@ -159,7 +142,7 @@ export const useAssetBalances = ( } }); return map; - }, [tokens, allAssets, allDetectedTokens]); + }, [tokens, allAssets]); // Build the exchangeRatesMap in useMemo using raw state const exchangeRatesMap = useMemo(() => { diff --git a/app/components/UI/Earn/hooks/useEarnNetworkPolling.test.ts b/app/components/UI/Earn/hooks/useEarnNetworkPolling.test.ts index 3b1e6a6e71da..d3e206b4beda 100644 --- a/app/components/UI/Earn/hooks/useEarnNetworkPolling.test.ts +++ b/app/components/UI/Earn/hooks/useEarnNetworkPolling.test.ts @@ -23,9 +23,6 @@ jest.mock('../../../../core/Engine', () => ({ TokenDetectionController: { detectTokens: jest.fn(), }, - TokensController: { - addTokens: jest.fn(), - }, }, })); @@ -58,10 +55,6 @@ describe('useEarnNetworkPolling', () => { const mockFindNetworkClientIdByChainId = jest.mocked( Engine.context.NetworkController.findNetworkClientIdByChainId, ); - const mockDetectTokens = jest.mocked( - Engine.context.TokenDetectionController.detectTokens, - ); - const mockAddTokens = jest.mocked(Engine.context.TokensController.addTokens); const mockSelectedAccount = MOCK_ACCOUNTS_CONTROLLER_STATE.internalAccounts.accounts[ @@ -91,32 +84,6 @@ describe('useEarnNetworkPolling', () => { PreferencesController: { useTokenDetection: true, }, - TokensController: { - allDetectedTokens: { - '0x1': { - [mockSelectedAccount.address]: { - '0x123': { - address: '0x123', - symbol: 'TEST', - decimals: 18, - image: 'test-image.png', - name: 'Test Token', - }, - }, - }, - '0x89': { - [mockSelectedAccount.address]: { - '0x456': { - address: '0x456', - symbol: 'TEST2', - decimals: 6, - image: 'test2-image.png', - name: 'Test Token 2', - }, - }, - }, - }, - }, }, }, } as unknown as RootState; @@ -128,8 +95,6 @@ describe('useEarnNetworkPolling', () => { if (chainId === '0x89') return 'polygon'; throw new Error(`Network client not found for chain ${chainId}`); }); - mockDetectTokens.mockResolvedValue(undefined); - mockAddTokens.mockResolvedValue(undefined); }); it('should call all polling hooks when mounted', () => { @@ -173,123 +138,6 @@ describe('useEarnNetworkPolling', () => { }); }); - it('should call TokenDetectionController.detectTokens when component mounts', () => { - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: mockState, - }); - - expect(mockDetectTokens).toHaveBeenCalledWith({ - chainIds: expect.any(Array), - selectedAddress: mockSelectedAccount.address, - }); - }); - - it('should not call detectTokens when useTokenDetection is false', () => { - const stateWithoutTokenDetection = { - ...mockState, - engine: { - ...mockState.engine, - backgroundState: { - ...mockState.engine.backgroundState, - PreferencesController: { - useTokenDetection: false, - }, - }, - }, - } as unknown as RootState; - - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: stateWithoutTokenDetection, - }); - - expect(mockDetectTokens).toHaveBeenCalledWith({ - chainIds: expect.any(Array), - selectedAddress: mockSelectedAccount.address, - }); - }); - - it('should not call detectTokens when no selected account', () => { - const stateWithoutAccount = { - ...mockState, - engine: { - ...mockState.engine, - backgroundState: { - ...mockState.engine.backgroundState, - AccountsController: { - ...MOCK_ACCOUNTS_CONTROLLER_STATE, - internalAccounts: { - ...MOCK_ACCOUNTS_CONTROLLER_STATE.internalAccounts, - selectedAccount: '', - }, - }, - AccountTreeController: { - accountTree: { - wallets: {}, - }, - selectedAccountGroup: '', - }, - }, - }, - } as unknown as RootState; - - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: stateWithoutAccount, - }); - - expect(mockDetectTokens).toHaveBeenCalledWith({ - chainIds: expect.any(Array), - selectedAddress: undefined, - }); - }); - - it('should call TokensController.addTokens for detected tokens', async () => { - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: mockState, - }); - - // Wait for async operations to complete - await new Promise((resolve) => setTimeout(resolve, 0)); - - // Verify tokens are added (order may vary based on LENDING_CHAIN_IDS) - expect(mockAddTokens).toHaveBeenCalledWith( - [ - { - address: '0x123', - symbol: 'TEST', - decimals: 18, - image: 'test-image.png', - name: 'Test Token', - isERC721: false, - }, - ], - 'mainnet', - ); - }); - - it('should not call addTokens when no detected tokens', async () => { - const stateWithoutDetectedTokens = { - ...mockState, - engine: { - ...mockState.engine, - backgroundState: { - ...mockState.engine.backgroundState, - TokensController: { - allDetectedTokens: {}, - }, - }, - }, - } as unknown as RootState; - - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: stateWithoutDetectedTokens, - }); - - // Wait for async operations to complete - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(mockAddTokens).not.toHaveBeenCalled(); - }); - it('should pass empty chainIds to useTokenDetectionPolling when useTokenDetection is false', () => { const stateWithoutTokenDetection = { ...mockState, @@ -314,32 +162,6 @@ describe('useEarnNetworkPolling', () => { }); }); - it('should handle addTokens errors gracefully', async () => { - mockAddTokens.mockRejectedValue(new Error('Failed to add tokens')); - - expect(() => { - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: mockState, - }); - }).not.toThrow(); - - // Wait for async operations to complete - await new Promise((resolve) => setTimeout(resolve, 0)); - }); - - it('should handle detectTokens errors gracefully', async () => { - mockDetectTokens.mockRejectedValue(new Error('Failed to detect tokens')); - - expect(() => { - renderHookWithProvider(() => useEarnNetworkPolling(), { - state: mockState, - }); - }).not.toThrow(); - - // Wait for async operations to complete - await new Promise((resolve) => setTimeout(resolve, 0)); - }); - it('should return null', () => { const { result } = renderHookWithProvider(() => useEarnNetworkPolling(), { state: mockState, diff --git a/app/components/UI/Earn/hooks/useEarnNetworkPolling.ts b/app/components/UI/Earn/hooks/useEarnNetworkPolling.ts index 711b1cae4662..a893b06d472d 100644 --- a/app/components/UI/Earn/hooks/useEarnNetworkPolling.ts +++ b/app/components/UI/Earn/hooks/useEarnNetworkPolling.ts @@ -1,17 +1,14 @@ -import { Token } from '@metamask/assets-controllers'; import { toHex } from '@metamask/controller-utils'; import { CHAIN_ID_TO_AAVE_POOL_CONTRACT } from '@metamask/stake-sdk'; import { Hex } from '@metamask/utils'; import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; -import Engine from '../../../../core/Engine'; import { selectSelectedInternalAccountByScope } from '../../../../selectors/multichainAccounts/accounts'; import { selectUseTokenDetection } from '../../../../selectors/preferencesController'; import useCurrencyRatePolling from '../../../hooks/AssetPolling/useCurrencyRatePolling'; import useTokenBalancesPolling from '../../../hooks/AssetPolling/useTokenBalancesPolling'; import useTokenDetectionPolling from '../../../hooks/AssetPolling/useTokenDetectionPolling'; import useTokenRatesPolling from '../../../hooks/AssetPolling/useTokenRatesPolling'; -import { RootState } from '../../BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal.test'; import { EVM_SCOPE } from '../constants/networks'; /** @@ -55,9 +52,6 @@ export const useEarnNetworkPolling = () => { EVM_SCOPE, ); const useTokenDetection = useSelector(selectUseTokenDetection); - const tokensState = useSelector( - (state: RootState) => state.engine?.backgroundState?.TokensController, - ); const [lendingChainIds, setLendingChainIds] = useState([]); useTokenBalancesPolling({ chainIds: lendingChainIds }); @@ -78,56 +72,6 @@ export const useEarnNetworkPolling = () => { setLendingChainIds(validChainIds); }, [setLendingChainIds]); - // Import tokens from all lending chains - useEffect(() => { - const importLendingTokens = async () => { - if (!selectedAccount?.address || !useTokenDetection) return; - - const { TokensController } = Engine.context; - const allDetectedTokens = tokensState?.allDetectedTokens || {}; - - for (const chainId of LENDING_CHAIN_IDS) { - const chainDetectedTokens = - allDetectedTokens[chainId]?.[selectedAccount.address]; - if ( - chainDetectedTokens && - Object.keys(chainDetectedTokens).length > 0 - ) { - const tokensToImport = Object.values(chainDetectedTokens).map( - (token: Token) => ({ - address: token.address, - symbol: token.symbol, - decimals: token.decimals, - image: token.image, - name: token.name, - isERC721: false, - }), - ); - - const networkClientId = - Engine.context.NetworkController.findNetworkClientIdByChainId( - chainId, - ); - - if (networkClientId && tokensToImport.length > 0) { - await TokensController.addTokens(tokensToImport, networkClientId); - } - } - } - }; - - Engine.context.TokenDetectionController.detectTokens({ - chainIds: LENDING_CHAIN_IDS, - selectedAddress: selectedAccount?.address as Hex, - }) - .then(importLendingTokens) - .catch(console.error); - }, [ - tokensState?.allDetectedTokens, - selectedAccount?.address, - useTokenDetection, - ]); - return null; }; diff --git a/app/components/UI/Earn/hooks/useEarnToken.test.ts b/app/components/UI/Earn/hooks/useEarnToken.test.ts index dc02431452e6..a659312ebdb1 100644 --- a/app/components/UI/Earn/hooks/useEarnToken.test.ts +++ b/app/components/UI/Earn/hooks/useEarnToken.test.ts @@ -163,7 +163,6 @@ const mockState = { }, }, allIgnoredTokens: {}, - allDetectedTokens: {}, } as TokensControllerState, TokenBalancesController: { tokenBalances: { diff --git a/app/components/UI/Earn/hooks/useEarnTokens.test.ts b/app/components/UI/Earn/hooks/useEarnTokens.test.ts index 5e45f9929021..f4fe9e88cbad 100644 --- a/app/components/UI/Earn/hooks/useEarnTokens.test.ts +++ b/app/components/UI/Earn/hooks/useEarnTokens.test.ts @@ -174,7 +174,6 @@ const mockState = { }, }, allIgnoredTokens: {}, - allDetectedTokens: {}, } as TokensControllerState, TokenBalancesController: { tokenBalances: { diff --git a/app/components/Views/DetectedTokens/DetectedTokensView.testIds.ts b/app/components/Views/DetectedTokens/DetectedTokensView.testIds.ts deleted file mode 100644 index 61be806bed8f..000000000000 --- 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 4c1ade3ac659..000000000000 --- 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 ee8560b4b3a2..000000000000 --- 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 965524d4e5e2..000000000000 --- 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 c7cadeaebde0..000000000000 --- 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 91ea11e5273b..000000000000 --- 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 28e7d5f0942c..29276ea3218b 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 afcdeb118bf4..5a1aa9c1ef42 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 1aa59ebd6b9d..dfe9d0590f13 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/constants/navigation/Routes.ts b/app/constants/navigation/Routes.ts index 522163ab78b7..4db5ea318948 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/core/Engine/Engine.test.ts b/app/core/Engine/Engine.test.ts index 251471542af8..e532b9ea3abf 100644 --- a/app/core/Engine/Engine.test.ts +++ b/app/core/Engine/Engine.test.ts @@ -632,7 +632,6 @@ describe('Engine', () => { }, }, allIgnoredTokens: {}, - allDetectedTokens: {}, }, TokenBalancesController: { tokenBalances: { @@ -747,7 +746,6 @@ describe('Engine', () => { }, }, allIgnoredTokens: {}, - allDetectedTokens: {}, }, TokenBalancesController: { tokenBalances: { diff --git a/app/core/NavigationService/types.ts b/app/core/NavigationService/types.ts index c0d772b49bb8..d4a7f862dbfa 100644 --- a/app/core/NavigationService/types.ts +++ b/app/core/NavigationService/types.ts @@ -374,7 +374,6 @@ export interface RootStackParamList extends ParamListBase { WhatsNewModal: undefined; TurnOffRememberMeModal: undefined; UpdateNeededModal: undefined; - DetectedTokens: undefined; SRPRevealQuiz: SRPRevealQuizParams | undefined; WalletActions: undefined; TradeWalletActions: undefined; diff --git a/app/selectors/assets/balances.test.ts b/app/selectors/assets/balances.test.ts index 3adfa80c9590..b407413fdee8 100644 --- a/app/selectors/assets/balances.test.ts +++ b/app/selectors/assets/balances.test.ts @@ -187,7 +187,6 @@ const makeState = (overrides: Record = {}) => ({ }, }, allIgnoredTokens: {}, - allDetectedTokens: {}, }, CurrencyRateController: { currentCurrency: 'usd', @@ -327,7 +326,6 @@ describe('assets balance and balance change selectors (mobile)', () => { TokensController: { allTokens: {}, allIgnoredTokens: {}, - allDetectedTokens: {}, }, CurrencyRateController: { currentCurrency: 'usd', diff --git a/app/selectors/assets/balances.ts b/app/selectors/assets/balances.ts index cc235ba4c750..8517bd26d12c 100644 --- a/app/selectors/assets/balances.ts +++ b/app/selectors/assets/balances.ts @@ -137,7 +137,6 @@ const selectTokensStateForBalances = createSelector( ({ allTokens: allTokens ?? {}, allIgnoredTokens: {}, - allDetectedTokens: {}, }) as TokensControllerState, ); diff --git a/app/selectors/tokensController.test.ts b/app/selectors/tokensController.test.ts index 1c453f6bb86d..35197751ea96 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 25d2b2d88fad..3ae77de7dcd7 100644 --- a/app/selectors/tokensController.ts +++ b/app/selectors/tokensController.ts @@ -106,24 +106,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 +142,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 c7e87faa1c86..231b29136caf 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/component-view/presets/assetDetails.ts b/tests/component-view/presets/assetDetails.ts index a47c27715951..493b1ff9c83b 100644 --- a/tests/component-view/presets/assetDetails.ts +++ b/tests/component-view/presets/assetDetails.ts @@ -61,7 +61,6 @@ export const initialStateAssetDetails = ( TokenBalancesController: { tokenBalances: {} }, TokensController: { allTokens: {}, - allDetectedTokens: {}, allIgnoredTokens: {}, }, }, diff --git a/tests/component-view/presets/wallet.ts b/tests/component-view/presets/wallet.ts index 2acb72c5379c..c3e38b53e574 100644 --- a/tests/component-view/presets/wallet.ts +++ b/tests/component-view/presets/wallet.ts @@ -57,7 +57,6 @@ export const initialStateWallet = (options?: InitialStateWalletOptions) => { '0x0000000000000000000000000000000000000001': [], }, }, - allDetectedTokens: {}, allIgnoredTokens: {}, }, MultichainBalancesController: { diff --git a/tests/component-view/presets/walletActions.ts b/tests/component-view/presets/walletActions.ts index 5db0f5a5d851..1a873e94e043 100644 --- a/tests/component-view/presets/walletActions.ts +++ b/tests/component-view/presets/walletActions.ts @@ -53,7 +53,6 @@ export const initialStateWalletActions = ( TokenBalancesController: { tokenBalances: {} }, TokensController: { allTokens: {}, - allDetectedTokens: {}, allIgnoredTokens: {}, }, CurrencyRateController: { diff --git a/tests/framework/fixtures/FixtureBuilder.ts b/tests/framework/fixtures/FixtureBuilder.ts index 15c4cbc284d2..a270ebfc1913 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 a57cb91e549a..000000000000 --- 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 72a6a06c61d2..000000000000 --- 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); - }, - ); - }); -});