diff --git a/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch b/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch new file mode 100644 index 000000000000..07f882a9eca0 --- /dev/null +++ b/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch @@ -0,0 +1,168 @@ +diff --git a/dist/index.d.cts b/dist/index.d.cts +index e6741164a2d67dabbd6b74ee34a07c37cb41d8c9..6dd7a98e3143c45ba3b636be3f0acd615adb87ab 100644 +--- a/dist/index.d.cts ++++ b/dist/index.d.cts +@@ -49,5 +49,5 @@ export { calculateBalanceChangeForAllWallets, calculateBalanceChangeForAccountGr + export type { AssetsByAccountGroup, AccountGroupAssets, Asset, AssetListState, } from "./selectors/token-selectors.cjs"; + export { selectAssetsBySelectedAccountGroup, selectAllAssets, } from "./selectors/token-selectors.cjs"; + export { createFormatters } from "./utils/formatters.cjs"; +-export type { SortTrendingBy, TrendingAsset, TokenSearchItem, TokenAsset, TokenRwaData, TokenSecurityData, TokenSecurityFeature, TokenSecurityHolder, TokenSecurityMarket, TokenSecurityFees, TokenSecurityFinancialStats, TokenSecurityMetadata, } from "./token-service.cjs"; ++export type { SortTrendingBy, TrendingAsset, TokenSearchItem, TokenAsset, TrendingTokensQueryParams, TokenRwaData, TokenSecurityData, TokenSecurityFeature, TokenSecurityHolder, TokenSecurityMarket, TokenSecurityFees, TokenSecurityFinancialStats, TokenSecurityMetadata, } from "./token-service.cjs"; + //# sourceMappingURL=index.d.cts.map +\ No newline at end of file +diff --git a/dist/token-service.cjs b/dist/token-service.cjs +index e420ea7b8ba28eae8efcec239e2fbe54caaa3916..54991205703a6ed3e00b73f1547fa982c6553020 100644 +--- a/dist/token-service.cjs ++++ b/dist/token-service.cjs +@@ -98,25 +98,13 @@ function getTokenAssetsURL(options) { + /** + * Get the trending tokens URL for the given networks and search query. + * +- * @param options - Options for getting trending tokens. +- * @param options.chainIds - Array of CAIP format chain IDs (e.g., ['eip155:1', 'eip155:137', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp']). +- * @param options.sort - The sort field. +- * @param options.minLiquidity - The minimum liquidity. +- * @param options.minVolume24hUsd - The minimum volume 24h in USD. +- * @param options.maxVolume24hUsd - The maximum volume 24h in USD. +- * @param options.minMarketCap - The minimum market cap. +- * @param options.maxMarketCap - The maximum market cap. +- * @param options.excludeLabels - Array of labels to exclude (e.g., ['stable_coin', 'blue_chip']). +- * @param options.includeRwaData - Optional flag to include RWA data in the results (defaults to false). +- * @param options.usePriceApiData - Optional flag to use price API data in the results (defaults to false). +- * @param options.includeTokenSecurityData - Optional flag to include token security data in the results (defaults to false). ++ * @param options - Options bag: `chainIds` (required) plus any query params. + * @returns The trending tokens URL. + */ + function getTrendingTokensURL(options) { + const encodedChainIds = options.chainIds + .map((id) => encodeURIComponent(id)) + .join(','); +- // Add the rest of query params if they are defined + const queryParams = new URLSearchParams(); + const { chainIds, excludeLabels, ...rest } = options; + Object.entries(rest).forEach(([key, value]) => { +@@ -201,38 +189,26 @@ exports.searchTokens = searchTokens; + /** + * Get the trending tokens for the given chains. + * +- * @param options - Options for getting trending tokens. +- * @param options.chainIds - The chains to get the trending tokens for. +- * @param options.sortBy - The sort by field. +- * @param options.minLiquidity - The minimum liquidity. +- * @param options.minVolume24hUsd - The minimum volume 24h in USD. +- * @param options.maxVolume24hUsd - The maximum volume 24h in USD. +- * @param options.minMarketCap - The minimum market cap. +- * @param options.maxMarketCap - The maximum market cap. +- * @param options.excludeLabels - Array of labels to exclude (e.g., ['stable_coin', 'blue_chip']). +- * @param options.includeRwaData - Optional flag to include RWA data in the results (defaults to true). +- * @param options.usePriceApiData - Optional flag to use price API data in the results (defaults to true). +- * @param options.includeTokenSecurityData - Optional flag to include token security data in the results (defaults to false). ++ * Accepts all known query parameters plus any additional ones via the ++ * index signature on {@link TrendingTokensQueryParams}. New API parameters ++ * can be passed without updating this function. ++ * ++ * @param options - Options bag: `chainIds` (required) plus any query params ++ * supported by the v3 trending endpoint. + * @returns The trending tokens. + * @throws Will throw if the request fails. + */ +-async function getTrendingTokens({ chainIds, sortBy, minLiquidity, minVolume24hUsd, maxVolume24hUsd, minMarketCap, maxMarketCap, excludeLabels, includeRwaData = true, usePriceApiData = true, includeTokenSecurityData, }) { ++async function getTrendingTokens(options) { ++ const { chainIds, ...rest } = options; + if (chainIds.length === 0) { + console.error('No chains provided'); + return []; + } + const trendingTokensURL = getTrendingTokensURL({ + chainIds, +- sort: sortBy, +- minLiquidity, +- minVolume24hUsd, +- maxVolume24hUsd, +- minMarketCap, +- maxMarketCap, +- excludeLabels, +- includeRwaData, +- usePriceApiData, +- includeTokenSecurityData, ++ includeRwaData: true, ++ usePriceApiData: true, ++ ...rest, + }); + try { + const result = await (0, controller_utils_1.handleFetch)(trendingTokensURL); +diff --git a/dist/token-service.d.cts b/dist/token-service.d.cts +index 38521c00fd2e37c5976936ec55ace02ef803b663..c0e9eb61e4622747e8dabbcfededc30c360b33bd 100644 +--- a/dist/token-service.d.cts ++++ b/dist/token-service.d.cts +@@ -5,6 +5,27 @@ export declare const TOKEN_METADATA_NO_SUPPORT_ERROR = "TokenService Error: Netw + * The sort by field for trending tokens. + */ + export type SortTrendingBy = 'm5_trending' | 'h1_trending' | 'h6_trending' | 'h24_trending'; ++/** ++ * Shared query-parameter type for the v3 trending tokens endpoint. ++ * ++ * Known parameters are explicitly typed for autocomplete and documentation. ++ * The index signature allows new API parameters to pass through without ++ * requiring a core release — callers can add any additional key/value and ++ * it will be forwarded as a query parameter. ++ */ ++export type TrendingTokensQueryParams = { ++ sort?: SortTrendingBy; ++ minLiquidity?: number; ++ minVolume24hUsd?: number; ++ maxVolume24hUsd?: number; ++ minMarketCap?: number; ++ maxMarketCap?: number; ++ excludeLabels?: string[]; ++ includeRwaData?: boolean; ++ usePriceApiData?: boolean; ++ includeTokenSecurityData?: boolean; ++ [key: string]: string | number | boolean | string[] | undefined; ++}; + /** + * Fetch the list of token metadata for a given network. This request is cancellable using the + * abort signal passed in. +@@ -138,34 +159,18 @@ export type TrendingAsset = { + /** + * Get the trending tokens for the given chains. + * +- * @param options - Options for getting trending tokens. +- * @param options.chainIds - The chains to get the trending tokens for. +- * @param options.sortBy - The sort by field. +- * @param options.minLiquidity - The minimum liquidity. +- * @param options.minVolume24hUsd - The minimum volume 24h in USD. +- * @param options.maxVolume24hUsd - The maximum volume 24h in USD. +- * @param options.minMarketCap - The minimum market cap. +- * @param options.maxMarketCap - The maximum market cap. +- * @param options.excludeLabels - Array of labels to exclude (e.g., ['stable_coin', 'blue_chip']). +- * @param options.includeRwaData - Optional flag to include RWA data in the results (defaults to true). +- * @param options.usePriceApiData - Optional flag to use price API data in the results (defaults to true). +- * @param options.includeTokenSecurityData - Optional flag to include token security data in the results (defaults to false). ++ * Accepts all known query parameters plus any additional ones via the ++ * index signature on {@link TrendingTokensQueryParams}. New API parameters ++ * can be passed without updating this function. ++ * ++ * @param options - Options bag: `chainIds` (required) plus any query params ++ * supported by the v3 trending endpoint. + * @returns The trending tokens. + * @throws Will throw if the request fails. + */ +-export declare function getTrendingTokens({ chainIds, sortBy, minLiquidity, minVolume24hUsd, maxVolume24hUsd, minMarketCap, maxMarketCap, excludeLabels, includeRwaData, usePriceApiData, includeTokenSecurityData, }: { ++export declare function getTrendingTokens(options: { + chainIds: CaipChainId[]; +- sortBy?: SortTrendingBy; +- minLiquidity?: number; +- minVolume24hUsd?: number; +- maxVolume24hUsd?: number; +- minMarketCap?: number; +- maxMarketCap?: number; +- excludeLabels?: string[]; +- includeRwaData?: boolean; +- usePriceApiData?: boolean; +- includeTokenSecurityData?: boolean; +-}): Promise; ++} & TrendingTokensQueryParams): Promise; + /** + * The token asset type returned by the /assets endpoint. + */ diff --git a/app/components/UI/Trending/components/TrendingTokenRowItem/TrendingTokenRowItem.tsx b/app/components/UI/Trending/components/TrendingTokenRowItem/TrendingTokenRowItem.tsx index 1d6ba2184653..ead07e06cfbf 100644 --- a/app/components/UI/Trending/components/TrendingTokenRowItem/TrendingTokenRowItem.tsx +++ b/app/components/UI/Trending/components/TrendingTokenRowItem/TrendingTokenRowItem.tsx @@ -1,5 +1,6 @@ import React, { useCallback, useMemo } from 'react'; import { TouchableOpacity, View } from 'react-native'; +import { useSelector } from 'react-redux'; import Text, { TextColor, TextVariant, @@ -33,6 +34,7 @@ import type { TrendingFilterContext } from '../TrendingTokensList/TrendingTokens import { TokenDetailsSource } from '../../../TokenDetails/constants/constants'; import { useTrendingTokenPress } from '../../hooks/useTrendingTokenPress/useTrendingTokenPress'; import SecurityTrustInlineBadge from '../../../SecurityTrust/components/SecurityTrustInlineBadge/SecurityTrustInlineBadge'; +import { selectCurrentCurrency } from '../../../../../selectors/currencyRateController'; /** * Gets the text color for price percentage change @@ -129,6 +131,7 @@ const TrendingTokenRowItem = ({ testIdInstanceKey, }: TrendingTokenRowItemProps) => { const { styles } = useStyles(styleSheet, {}); + const currentCurrency = useSelector(selectCurrentCurrency) || 'USD'; const caipChainId = useMemo( () => getCaipChainIdFromAssetId(token.assetId), @@ -232,7 +235,7 @@ const TrendingTokenRowItem = ({ - {formatPriceWithSubscriptNotation(token.price)} + {formatPriceWithSubscriptNotation(token.price, currentCurrency)} {parseFloat(token.price) === 0 ? ( diff --git a/app/components/UI/Trending/hooks/useTrendingRequest/useTrendingRequest.ts b/app/components/UI/Trending/hooks/useTrendingRequest/useTrendingRequest.ts index 99c9da1d4fe5..9e848342271b 100644 --- a/app/components/UI/Trending/hooks/useTrendingRequest/useTrendingRequest.ts +++ b/app/components/UI/Trending/hooks/useTrendingRequest/useTrendingRequest.ts @@ -1,12 +1,14 @@ import { useCallback, useMemo, useEffect, useState, useRef } from 'react'; +import { useSelector } from 'react-redux'; import type { CaipChainId } from '@metamask/utils'; import { getTrendingTokens, - SortTrendingBy, + TrendingTokensQueryParams, } from '@metamask/assets-controllers'; import { useStableArray } from '../../../Perps/hooks/useStableArray'; import { TRENDING_NETWORKS_LIST } from '../../utils/trendingNetworksList'; import { NetworkToCaipChainId } from '../../../NetworkMultiSelector/NetworkMultiSelector.constants'; +import { selectCurrentCurrency } from '../../../../../selectors/currencyRateController'; /** * Baseline thresholds for multi-chain requests @@ -140,18 +142,14 @@ interface FetchOptions { * Hook for handling trending tokens request * @returns {Object} An object containing the trending tokens results, loading state, error, and a function to trigger fetch */ -export const useTrendingRequest = (options: { - chainIds?: CaipChainId[]; - sortBy?: SortTrendingBy; - minLiquidity?: number; - minVolume24hUsd?: number; - maxVolume24hUsd?: number; - minMarketCap?: number; - maxMarketCap?: number; -}) => { +export const useTrendingRequest = ( + options: { + chainIds?: CaipChainId[]; + } & TrendingTokensQueryParams, +) => { const { chainIds: providedChainIds = [], - sortBy = 'h24_trending', + sort = 'h24_trending', minLiquidity: providedMinLiquidity, minVolume24hUsd: providedMinVolume24hUsd, maxVolume24hUsd, @@ -159,6 +157,9 @@ export const useTrendingRequest = (options: { maxMarketCap, } = options; + // Get user's selected currency from Redux store (default to 'usd' if not set) + const currentCurrency = useSelector(selectCurrentCurrency) || 'usd'; + // Use provided chainIds or default to trending networks const chainIds = useMemo((): CaipChainId[] => { if (providedChainIds.length > 0) { @@ -168,13 +169,17 @@ export const useTrendingRequest = (options: { }, [providedChainIds]); // Calculate thresholds based on selected chains - const minLiquidity = useMemo( - () => providedMinLiquidity ?? getMinLiquidityForChains(chainIds), + const minLiquidity: number = useMemo( + () => + (providedMinLiquidity as number | undefined) ?? + getMinLiquidityForChains(chainIds), [providedMinLiquidity, chainIds], ); - const minVolume24hUsd = useMemo( - () => providedMinVolume24hUsd ?? getMinVolume24hForChains(chainIds), + const minVolume24hUsd: number = useMemo( + () => + (providedMinVolume24hUsd as number | undefined) ?? + getMinVolume24hForChains(chainIds), [providedMinVolume24hUsd, chainIds], ); @@ -217,14 +222,15 @@ export const useTrendingRequest = (options: { try { const resultsToStore = await getTrendingTokens({ chainIds: stableChainIds, - sortBy, + sort, minLiquidity, minVolume24hUsd, - maxVolume24hUsd, - minMarketCap, - maxMarketCap, + maxVolume24hUsd: maxVolume24hUsd as number | undefined, + minMarketCap: minMarketCap as number | undefined, + maxMarketCap: maxMarketCap as number | undefined, excludeLabels: ['stable_coin', 'blue_chip'], includeTokenSecurityData: true, + vsCurrency: currentCurrency.toLowerCase(), }); // Only update state if this is still the current request if (currentRequestId === requestIdRef.current) { @@ -246,12 +252,13 @@ export const useTrendingRequest = (options: { }, [ stableChainIds, - sortBy, + sort, minLiquidity, minVolume24hUsd, maxVolume24hUsd, minMarketCap, maxMarketCap, + currentCurrency, ], ); diff --git a/app/components/UI/Trending/hooks/useTrendingTokenPress/useTrendingTokenPress.test.ts b/app/components/UI/Trending/hooks/useTrendingTokenPress/useTrendingTokenPress.test.ts index de39077c2ca6..b04cef8122ff 100644 --- a/app/components/UI/Trending/hooks/useTrendingTokenPress/useTrendingTokenPress.test.ts +++ b/app/components/UI/Trending/hooks/useTrendingTokenPress/useTrendingTokenPress.test.ts @@ -22,6 +22,9 @@ jest.mock('../../../../hooks/useAddPopularNetwork'); jest.mock('../../../../../selectors/networkController', () => ({ selectNetworkConfigurationsByCaipChainId: jest.fn(), })); +jest.mock('../../../../../selectors/currencyRateController', () => ({ + selectCurrentCurrency: jest.fn(() => 'USD'), +})); jest.mock('../../services/TrendingFeedSessionManager', () => ({ __esModule: true, default: { getInstance: jest.fn() }, diff --git a/package.json b/package.json index ae9cdbd7febe..1e570521e9db 100644 --- a/package.json +++ b/package.json @@ -214,7 +214,9 @@ "@metamask/keyring-api@npm:^21.4.0": "23.1.0", "@metamask/keyring-api@npm:^21.6.0": "23.1.0", "@metamask/keyring-api@npm:^22.0.0": "23.1.0", - "@metamask/bridge-status-controller@npm:^71.0.0": "patch:@metamask/bridge-status-controller@npm%3A71.1.0#~/.yarn/patches/@metamask-bridge-status-controller-npm-71.1.0-6140a0bdf3.patch" + "@metamask/bridge-status-controller@npm:^71.0.0": "patch:@metamask/bridge-status-controller@npm%3A71.1.0#~/.yarn/patches/@metamask-bridge-status-controller-npm-71.1.0-6140a0bdf3.patch", + "@metamask/assets-controllers@npm:^105.1.0": "patch:@metamask/assets-controllers@npm%3A105.1.0#~/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch", + "@metamask/assets-controllers@npm:^105.0.0": "patch:@metamask/assets-controllers@npm%3A105.1.0#~/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch" }, "dependencies": { "@braze/react-native-sdk": "patch:@braze/react-native-sdk@npm%3A19.1.0#~/.yarn/patches/@braze-react-native-sdk-npm-19.1.0-076-reactmoduleinfo.patch", @@ -241,7 +243,7 @@ "@metamask/app-metadata-controller": "^2.0.0", "@metamask/approval-controller": "^9.0.0", "@metamask/assets-controller": "^6.2.1", - "@metamask/assets-controllers": "^105.0.0", + "@metamask/assets-controllers": "patch:@metamask/assets-controllers@npm%3A105.1.0#~/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch", "@metamask/authenticated-user-storage": "^1.0.0", "@metamask/base-controller": "^9.0.1", "@metamask/bitcoin-wallet-snap": "^1.10.1", diff --git a/yarn.lock b/yarn.lock index 787872a8cd36..50def696dd06 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7919,7 +7919,7 @@ __metadata: languageName: node linkType: hard -"@metamask/assets-controllers@npm:^105.0.0, @metamask/assets-controllers@npm:^105.1.0": +"@metamask/assets-controllers@npm:105.1.0": version: 105.1.0 resolution: "@metamask/assets-controllers@npm:105.1.0" dependencies: @@ -7975,6 +7975,62 @@ __metadata: languageName: node linkType: hard +"@metamask/assets-controllers@patch:@metamask/assets-controllers@npm%3A105.1.0#~/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch": + version: 105.1.0 + resolution: "@metamask/assets-controllers@patch:@metamask/assets-controllers@npm%3A105.1.0#~/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch::version=105.1.0&hash=b10091" + dependencies: + "@ethereumjs/util": "npm:^9.1.0" + "@ethersproject/abi": "npm:^5.7.0" + "@ethersproject/address": "npm:^5.7.0" + "@ethersproject/bignumber": "npm:^5.7.0" + "@ethersproject/contracts": "npm:^5.7.0" + "@ethersproject/providers": "npm:^5.7.0" + "@metamask/abi-utils": "npm:^2.0.3" + "@metamask/account-tree-controller": "npm:^7.1.0" + "@metamask/accounts-controller": "npm:^37.2.0" + "@metamask/approval-controller": "npm:^9.0.1" + "@metamask/base-controller": "npm:^9.1.0" + "@metamask/contract-metadata": "npm:^2.4.0" + "@metamask/controller-utils": "npm:^11.20.0" + "@metamask/core-backend": "npm:^6.2.1" + "@metamask/eth-query": "npm:^4.0.0" + "@metamask/keyring-api": "npm:^23.1.0" + "@metamask/keyring-controller": "npm:^25.3.0" + "@metamask/messenger": "npm:^1.2.0" + "@metamask/metamask-eth-abis": "npm:^3.1.1" + "@metamask/multichain-account-service": "npm:^8.0.1" + "@metamask/network-controller": "npm:^30.1.0" + "@metamask/network-enablement-controller": "npm:^5.0.2" + "@metamask/permission-controller": "npm:^13.0.0" + "@metamask/phishing-controller": "npm:^17.1.1" + "@metamask/polling-controller": "npm:^16.0.4" + "@metamask/preferences-controller": "npm:^23.1.0" + "@metamask/profile-sync-controller": "npm:^28.0.2" + "@metamask/rpc-errors": "npm:^7.0.2" + "@metamask/snaps-controllers": "npm:^19.0.0" + "@metamask/snaps-sdk": "npm:^11.0.0" + "@metamask/snaps-utils": "npm:^12.1.2" + "@metamask/storage-service": "npm:^1.0.1" + "@metamask/transaction-controller": "npm:^65.0.0" + "@metamask/utils": "npm:^11.9.0" + "@types/bn.js": "npm:^5.1.5" + "@types/uuid": "npm:^8.3.0" + async-mutex: "npm:^0.5.0" + bitcoin-address-validation: "npm:^2.2.3" + bn.js: "npm:^5.2.1" + immer: "npm:^9.0.6" + lodash: "npm:^4.17.21" + multiformats: "npm:^9.9.0" + reselect: "npm:^5.1.1" + single-call-balance-checker-abi: "npm:^1.0.0" + uuid: "npm:^8.3.2" + peerDependencies: + "@metamask/providers": ^22.0.0 + webextension-polyfill: ^0.10.0 || ^0.11.0 || ^0.12.0 + checksum: 10/41aa24461a693073464927af23dfdd012729c976f0de5d4d223ee339cd606c7901324351254bf2db1aeaad56649abe2d62eeff9c78f608a91d539b1e6ae714b6 + languageName: node + linkType: hard + "@metamask/auth-network-utils@npm:^0.3.0": version: 0.3.1 resolution: "@metamask/auth-network-utils@npm:0.3.1" @@ -35628,7 +35684,7 @@ __metadata: "@metamask/app-metadata-controller": "npm:^2.0.0" "@metamask/approval-controller": "npm:^9.0.0" "@metamask/assets-controller": "npm:^6.2.1" - "@metamask/assets-controllers": "npm:^105.0.0" + "@metamask/assets-controllers": "patch:@metamask/assets-controllers@npm%3A105.1.0#~/.yarn/patches/@metamask-assets-controllers-npm-105.1.0-76332163aa.patch" "@metamask/authenticated-user-storage": "npm:^1.0.0" "@metamask/auto-changelog": "npm:^5.3.0" "@metamask/base-controller": "npm:^9.0.1"