Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions packages/assets-controllers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Export new type `TrendingTokensQueryParams` for extensible trending token query parameters ([#8729](https://github.com/MetaMask/core/pull/8729))

### Changed

- **BREAKING:** `getTrendingTokens` now accepts `sort` instead of `sortBy` to match the API parameter name ([#8729](https://github.com/MetaMask/core/pull/8729))
Comment thread
sahar-fehri marked this conversation as resolved.
- `getTrendingTokens` and `getTrendingTokensURL` now accept arbitrary query parameters via an index signature on `TrendingTokensQueryParams`, allowing new API parameters to pass through without a core release ([#8729](https://github.com/MetaMask/core/pull/8729))

- Bump `@metamask/account-tree-controller` from `^7.2.0` to `^7.3.0` ([#8722](https://github.com/MetaMask/core/pull/8722))
- Bump `@metamask/keyring-controller` from `^25.4.0` to `^25.5.0` ([#8722](https://github.com/MetaMask/core/pull/8722))
- Bump `@metamask/multichain-account-service` from `^8.0.1` to `^9.0.0` ([#8722](https://github.com/MetaMask/core/pull/8722))
Expand Down
1 change: 1 addition & 0 deletions packages/assets-controllers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ export { createFormatters } from './utils/formatters';
export type {
SortTrendingBy,
TrendingAsset,
TrendingTokensQueryParams,
TokenSearchItem,
TokenAsset,
TokenRwaData,
Expand Down
25 changes: 21 additions & 4 deletions packages/assets-controllers/src/token-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1162,22 +1162,22 @@ describe('Token service', () => {

it('returns the list of trending tokens if the fetch succeeds', async () => {
const testChainId = 'eip155:1';
const sortBy: SortTrendingBy = 'm5_trending';
const sort: SortTrendingBy = 'm5_trending';
const testMinLiquidity = 1000000;
const testMinVolume24hUsd = 1000000;
const testMaxVolume24hUsd = 1000000;
const testMinMarketCap = 1000000;
const testMaxMarketCap = 1000000;
nock(TOKEN_END_POINT_API)
.get(
`/v3/tokens/trending?chainIds=${encodeURIComponent(testChainId)}&sort=${sortBy}&minLiquidity=${testMinLiquidity}&minVolume24hUsd=${testMinVolume24hUsd}&maxVolume24hUsd=${testMaxVolume24hUsd}&minMarketCap=${testMinMarketCap}&maxMarketCap=${testMaxMarketCap}&includeRwaData=true&usePriceApiData=true`,
`/v3/tokens/trending?chainIds=${encodeURIComponent(testChainId)}&sort=${sort}&minLiquidity=${testMinLiquidity}&minVolume24hUsd=${testMinVolume24hUsd}&maxVolume24hUsd=${testMaxVolume24hUsd}&minMarketCap=${testMinMarketCap}&maxMarketCap=${testMaxMarketCap}&includeRwaData=true&usePriceApiData=true`,
)
.reply(200, sampleTrendingTokens)
.persist();

const result = await getTrendingTokens({
chainIds: [testChainId],
sortBy,
sort,
minLiquidity: testMinLiquidity,
minVolume24hUsd: testMinVolume24hUsd,
maxVolume24hUsd: testMaxVolume24hUsd,
Expand Down Expand Up @@ -1292,14 +1292,31 @@ describe('Token service', () => {

const result = await getTrendingTokens({
chainIds: [testChainId],
sortBy: 'h6_trending',
sort: 'h6_trending',
minLiquidity: testMinLiquidity,
minVolume24hUsd: testMinVolume,
includeRwaData: false,
includeTokenSecurityData: true,
});
expect(result).toStrictEqual(sampleTrendingTokensWithSecurityData);
});

it('passes unknown query params through to the URL', async () => {
const testChainId = 'eip155:1';

nock(TOKEN_END_POINT_API)
.get(
`/v3/tokens/trending?chainIds=${encodeURIComponent(testChainId)}&includeRwaData=true&usePriceApiData=true&vsCurrency=eur`,
)
.reply(200, sampleTrendingTokens)
.persist();

const result = await getTrendingTokens({
chainIds: [testChainId],
vsCurrency: 'eur',
});
expect(result).toStrictEqual(sampleTrendingTokens);
});
});

describe('searchTokens with includeTokenSecurityData', () => {
Expand Down
97 changes: 32 additions & 65 deletions packages/assets-controllers/src/token-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,14 @@ function getTokenAssetsURL(options: {
}

/**
* Get the trending tokens URL for the given networks and search query.
* Shared query-parameter type for the v3 trending tokens endpoint.
*
* @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).
* @returns The trending tokens URL.
* 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.
*/
function getTrendingTokensURL(options: {
chainIds: CaipChainId[];
export type TrendingTokensQueryParams = {
sort?: SortTrendingBy;
minLiquidity?: number;
minVolume24hUsd?: number;
Expand All @@ -166,11 +156,21 @@ function getTrendingTokensURL(options: {
includeRwaData?: boolean;
usePriceApiData?: boolean;
includeTokenSecurityData?: boolean;
}): string {
[key: string]: string | number | boolean | string[] | undefined;
};

/**
* Get the trending tokens URL for the given networks and search query.
*
* @param options - Options bag: `chainIds` (required) plus any query params.
* @returns The trending tokens URL.
*/
function getTrendingTokensURL(
options: { chainIds: CaipChainId[] } & TrendingTokensQueryParams,
): string {
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]) => {
Expand Down Expand Up @@ -391,63 +391,30 @@ 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 async function getTrendingTokens({
chainIds,
sortBy,
minLiquidity,
minVolume24hUsd,
maxVolume24hUsd,
minMarketCap,
maxMarketCap,
excludeLabels,
includeRwaData = true,
Comment thread
cursor[bot] marked this conversation as resolved.
usePriceApiData = true,
includeTokenSecurityData,
}: {
chainIds: CaipChainId[];
sortBy?: SortTrendingBy;
minLiquidity?: number;
minVolume24hUsd?: number;
maxVolume24hUsd?: number;
minMarketCap?: number;
maxMarketCap?: number;
excludeLabels?: string[];
includeRwaData?: boolean;
usePriceApiData?: boolean;
includeTokenSecurityData?: boolean;
}): Promise<TrendingAsset[]> {
export async function getTrendingTokens(
options: { chainIds: CaipChainId[] } & TrendingTokensQueryParams,
): Promise<TrendingAsset[]> {
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 {
Expand Down
Loading