diff --git a/shared/constants/network.ts b/shared/constants/network.ts index 5315195b7a69..349ec1e172e4 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -211,6 +211,7 @@ export const CHAIN_IDS = { MONAD: '0x8f', HYPE: '0x3e7', X_LAYER: '0xc4', + TEMPO_TESTNET: '0xa5bd', } as const; export const CHAINLIST_CHAIN_IDS_MAP = { diff --git a/shared/lib/tempo-utils.test.ts b/shared/lib/tempo-utils.test.ts new file mode 100644 index 000000000000..fb997784df04 --- /dev/null +++ b/shared/lib/tempo-utils.test.ts @@ -0,0 +1,45 @@ +import { isTempoNetwork, shouldHideTempoToken } from './tempo-utils'; + +describe('isTempoNetwork', () => { + it('returns true for Tempo Testnet chain ID', () => { + expect(isTempoNetwork('0xa5bd')).toBe(true); + }); + + it('handles uppercase chain ID', () => { + expect(isTempoNetwork('0xA5BD')).toBe(true); + }); + + it('returns false for non-Tempo chain IDs', () => { + expect(isTempoNetwork('0x1')).toBe(false); + expect(isTempoNetwork('0x89')).toBe(false); + }); +}); + +describe('shouldHideTempoToken', () => { + const TEMPO_CHAIN_ID = '0xa5bd'; + const NON_TEMPO_CHAIN_ID = '0x1'; + + it('returns true for native tokens on Tempo', () => { + expect(shouldHideTempoToken(TEMPO_CHAIN_ID, true, 'ETH')).toBe(true); + }); + + it('returns true for USD symbol on Tempo', () => { + expect(shouldHideTempoToken(TEMPO_CHAIN_ID, false, 'USD')).toBe(true); + expect(shouldHideTempoToken(TEMPO_CHAIN_ID, false, 'usd')).toBe(true); + }); + + it('returns false for other tokens on Tempo', () => { + expect(shouldHideTempoToken(TEMPO_CHAIN_ID, false, 'USDC')).toBe(false); + expect(shouldHideTempoToken(TEMPO_CHAIN_ID, false, 'ETH')).toBe(false); + }); + + it('returns false for tokens on non-Tempo networks', () => { + expect(shouldHideTempoToken(NON_TEMPO_CHAIN_ID, true, 'ETH')).toBe(false); + expect(shouldHideTempoToken(NON_TEMPO_CHAIN_ID, false, 'USD')).toBe(false); + }); + + it('returns false when symbol is undefined', () => { + expect(shouldHideTempoToken(TEMPO_CHAIN_ID, false, undefined)).toBe(false); + }); +}); + diff --git a/shared/lib/tempo-utils.ts b/shared/lib/tempo-utils.ts new file mode 100644 index 000000000000..f111defadee9 --- /dev/null +++ b/shared/lib/tempo-utils.ts @@ -0,0 +1,42 @@ +const TEMPO_CHAIN_IDS = ['0xa5bd'] as const; + +/** + * Determines whether the given chain ID belongs to a Tempo network. + * + * @param chainId - The chain ID to check. + * @returns True if the chain ID is a Tempo network, false otherwise. + */ +export function isTempoNetwork(chainId: string): boolean { + return TEMPO_CHAIN_IDS.includes( + chainId.toLowerCase() as (typeof TEMPO_CHAIN_IDS)[number], + ); +} + +/** + * Determines whether a token should be hidden on Tempo networks. + * + * @param chainId - The chain ID of the token. + * @param isNative - Whether the token is marked as native. + * @param symbol - The token symbol. + * @returns True if the token should be hidden, false otherwise. + */ +export function shouldHideTempoToken( + chainId: string, + isNative: boolean | undefined, + symbol: string | undefined, +): boolean { + if (!isTempoNetwork(chainId)) { + return false; + } + + if (isNative) { + return true; + } + + if (symbol?.toUpperCase() === 'USD') { + return true; + } + + return false; +} + diff --git a/ui/components/app/assets/token-list/token-list.tsx b/ui/components/app/assets/token-list/token-list.tsx index cbb21f8ad33a..ee1677035231 100644 --- a/ui/components/app/assets/token-list/token-list.tsx +++ b/ui/components/app/assets/token-list/token-list.tsx @@ -41,6 +41,7 @@ import { isEvmChainId, isTronResource, } from '../../../../../shared/lib/asset-utils'; +import { shouldHideTempoToken } from '../../../../../shared/lib/tempo-utils'; import { sortAssetsWithPriority } from '../util/sortAssetsWithPriority'; import { useScrollContainer } from '../../../../contexts/scroll-container'; @@ -102,7 +103,12 @@ function TokenList({ onTokenClick, safeChains }: TokenListProps) { }, ]); - return sortAssets([...filteredAssets], tokenSortConfig); + const sortedAssets = sortAssets([...filteredAssets], tokenSortConfig); + + return sortedAssets.filter( + (asset) => + !shouldHideTempoToken(asset.chainId, asset.isNative, asset.symbol), + ); } const accountAssetsPreSort = Object.entries(accountGroupIdAssets).flatMap( @@ -129,7 +135,7 @@ function TokenList({ onTokenClick, safeChains }: TokenListProps) { tokenSortConfig, ); - return accountAssets.map((asset) => { + const mappedAssets = accountAssets.map((asset) => { const token: TokenWithFiatAmount = { ...asset, tokenFiatAmount: asset.fiat?.balance, @@ -141,6 +147,11 @@ function TokenList({ onTokenClick, safeChains }: TokenListProps) { return token; }); + + return mappedAssets.filter( + (asset) => + !shouldHideTempoToken(asset.chainId, asset.isNative, asset.symbol), + ); }, [ isEvm, evmBalances, diff --git a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx index 24c4b5c5f1a1..dc990942765e 100644 --- a/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx +++ b/ui/components/multichain/asset-picker-amount/asset-picker-modal/asset-picker-modal.tsx @@ -76,6 +76,7 @@ import { import { MultichainNetworks } from '../../../../../shared/constants/multichain/networks'; import { Numeric } from '../../../../../shared/modules/Numeric'; import { isEvmChainId } from '../../../../../shared/lib/asset-utils'; +import { shouldHideTempoToken } from '../../../../../shared/lib/tempo-utils'; import { useAssetMetadata } from './hooks/useAssetMetadata'; import type { @@ -553,7 +554,18 @@ export function AssetPickerModal({ ); const displayedTokens = useMemo(() => { - return unlistedAssetMetadata ? [unlistedAssetMetadata] : filteredTokenList; + const tokens = unlistedAssetMetadata + ? [unlistedAssetMetadata] + : filteredTokenList; + + return tokens.filter( + (token) => + !shouldHideTempoToken( + token.chainId, + token.type === AssetType.native, + token.symbol, + ), + ); }, [unlistedAssetMetadata, filteredTokenList]); const getNetworkPickerLabel = () => { diff --git a/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx b/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx index ce628fa106d6..07c4f1c68d4a 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/edit-gas-fees-row/edit-gas-fees-row.tsx @@ -3,6 +3,7 @@ import { Hex } from '@metamask/utils'; import React, { Dispatch, SetStateAction } from 'react'; import { useSelector } from 'react-redux'; import { TEST_CHAINS } from '../../../../../../../../shared/constants/network'; +import { isTempoNetwork } from '../../../../../../../../shared/lib/tempo-utils'; import { ConfirmInfoAlertRow } from '../../../../../../../components/app/confirm/info/row/alert-row/alert-row'; import { RowAlertKey } from '../../../../../../../components/app/confirm/info/row/constants'; import { Box, Text } from '../../../../../../../components/component-library'; @@ -57,6 +58,7 @@ export const EditGasFeesRow = ({ } = transactionMeta; const gasFeeToken = useSelectedGasFeeToken(); const showFiat = useShowFiat(chainId); + const isTempoChain = isTempoNetwork(chainId); const fiatValue = gasFeeToken ? gasFeeToken.amountFiat : fiatFee; const tokenValue = gasFeeToken ? gasFeeToken.amountFormatted : nativeFee; const metamaskFeeFiat = gasFeeToken?.metamaskFeeFiat; @@ -117,8 +119,14 @@ export const EditGasFeesRow = ({ roundedValue={fiatValue} /> )} - {!(showFiat && !showAdvancedDetails) && !isGasFeeSponsored && ( - + {!(showFiat && !showAdvancedDetails) && + !isGasFeeSponsored && + !isTempoChain && } + {showAdvancedDetails && !isGasFeeSponsored && isTempoChain && ( + )} {!isGasFeeSponsored && } @@ -142,7 +150,7 @@ export const EditGasFeesRow = ({ : ' '} - {showAdvancedDetails && ( + {showAdvancedDetails && !isTempoChain && ( diff --git a/ui/pages/confirmations/hooks/send/useSendAssetFilter.test.ts b/ui/pages/confirmations/hooks/send/useSendAssetFilter.test.ts index c6221b257c90..ae64b42c87b8 100644 --- a/ui/pages/confirmations/hooks/send/useSendAssetFilter.test.ts +++ b/ui/pages/confirmations/hooks/send/useSendAssetFilter.test.ts @@ -307,4 +307,28 @@ describe('useSendAssetFilter', () => { expect(result.current.filteredTokens).toEqual(mockTokens); expect(result.current.filteredNfts).toEqual(mockNfts); }); + + it('filters out USD tokens on Tempo network', () => { + const tempoTokens: Asset[] = [ + { name: 'USD', symbol: 'USD', chainId: '0xa5bd', isNative: true }, + { name: 'AlphaUSD', symbol: 'AlphaUSD', chainId: '0xa5bd' }, + { name: 'Ethereum', symbol: 'ETH', chainId: '0x1' }, + ]; + + const { result } = renderHookWithProvider( + () => + useSendAssetFilter({ + tokens: tempoTokens, + nfts: [], + selectedChainId: null, + searchQuery: '', + }), + mockState, + ); + + expect(result.current.filteredTokens).toEqual([ + tempoTokens[1], + tempoTokens[2], + ]); + }); }); diff --git a/ui/pages/confirmations/hooks/send/useSendAssetFilter.ts b/ui/pages/confirmations/hooks/send/useSendAssetFilter.ts index ef04a927e862..43fbda41435c 100644 --- a/ui/pages/confirmations/hooks/send/useSendAssetFilter.ts +++ b/ui/pages/confirmations/hooks/send/useSendAssetFilter.ts @@ -1,5 +1,6 @@ import { useMemo } from 'react'; +import { shouldHideTempoToken } from '../../../../../shared/lib/tempo-utils'; import { type Asset } from '../../types/send'; type UseSendAssetFilterProps = { @@ -41,8 +42,17 @@ export const useSendAssetFilter = ({ matchesSearchQuery(nft, searchQuery), ); + const tempoFilteredTokens = filteredTokens.filter((token) => { + const chainId = + typeof token.chainId === 'string' ? token.chainId : undefined; + if (!chainId) { + return true; + } + return !shouldHideTempoToken(chainId, token.isNative, token.symbol); + }); + return { - filteredTokens, + filteredTokens: tempoFilteredTokens, filteredNfts, }; }, [tokens, nfts, selectedChainId, searchQuery]);