Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions shared/constants/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
45 changes: 45 additions & 0 deletions shared/lib/tempo-utils.test.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});

42 changes: 42 additions & 0 deletions shared/lib/tempo-utils.ts
Original file line number Diff line number Diff line change
@@ -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;
}

15 changes: 13 additions & 2 deletions ui/components/app/assets/token-list/token-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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(
Expand All @@ -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,
Expand All @@ -141,6 +147,11 @@ function TokenList({ onTokenClick, safeChains }: TokenListProps) {

return token;
});

return mappedAssets.filter(
(asset) =>
!shouldHideTempoToken(asset.chainId, asset.isNative, asset.symbol),
);
}, [
isEvm,
evmBalances,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -117,8 +119,14 @@ export const EditGasFeesRow = ({
roundedValue={fiatValue}
/>
)}
{!(showFiat && !showAdvancedDetails) && !isGasFeeSponsored && (
<TokenValue roundedValue={tokenValue} />
{!(showFiat && !showAdvancedDetails) &&
!isGasFeeSponsored &&
!isTempoChain && <TokenValue roundedValue={tokenValue} />}
{showAdvancedDetails && !isGasFeeSponsored && isTempoChain && (
<FiatValue
fullValue={fiatFeeWith18SignificantDigits}
roundedValue={fiatValue}
/>
)}
{!isGasFeeSponsored && <SelectedGasFeeToken />}
</Box>
Expand All @@ -142,7 +150,7 @@ export const EditGasFeesRow = ({
: ' '}
</Text>
</Box>
{showAdvancedDetails && (
{showAdvancedDetails && !isTempoChain && (
<FiatValue
fullValue={fiatFeeWith18SignificantDigits}
roundedValue={fiatValue}
Expand Down Expand Up @@ -199,5 +207,9 @@ function useShowFiat(chainId: Hex): boolean {
const isTestnet = TEST_CHAINS.includes(chainId as TestNetChainId);
const { showFiatInTestnets } = useSelector(getPreferences);

if (isTempoNetwork(chainId)) {
return true;
}

return !isTestnet || showFiatInTestnets;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TransactionMeta } from '@metamask/transaction-controller';
import { useSelector } from 'react-redux';

import { NATIVE_TOKEN_ADDRESS } from '../../../../../../../../shared/constants/transaction';
import { isTempoNetwork } from '../../../../../../../../shared/lib/tempo-utils';
import {
Box,
Icon,
Expand Down Expand Up @@ -64,7 +65,8 @@ export function SelectedGasFeeToken() {

const nativeTicker = networkConfiguration?.nativeCurrency;
const gasFeeToken = useSelectedGasFeeToken();
const symbol = gasFeeToken?.symbol ?? nativeTicker;
const isTempoChain = isTempoNetwork(chainId);
const symbol = gasFeeToken?.symbol ?? (isTempoChain ? 'USD' : nativeTicker);

return (
<>
Expand Down
24 changes: 24 additions & 0 deletions ui/pages/confirmations/hooks/send/useSendAssetFilter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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],
]);
});
});
12 changes: 11 additions & 1 deletion ui/pages/confirmations/hooks/send/useSendAssetFilter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useMemo } from 'react';

import { shouldHideTempoToken } from '../../../../../shared/lib/tempo-utils';
import { type Asset } from '../../types/send';

type UseSendAssetFilterProps = {
Expand Down Expand Up @@ -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]);
Expand Down
Loading