From 967a5b656144b02c13340717bae61507cfec6edd Mon Sep 17 00:00:00 2001 From: "dawnseeker8@gmail.com" Date: Tue, 23 Dec 2025 16:27:22 +0800 Subject: [PATCH 1/4] feat: fake the rwaData returned from backend to make sure it work for stock label. --- .../assets-controllers/src/token-service.ts | 86 ++++++++++++++++--- packages/bridge-controller/src/utils/fetch.ts | 17 +++- .../bridge-controller/src/utils/validators.ts | 16 ++++ 3 files changed, 108 insertions(+), 11 deletions(-) diff --git a/packages/assets-controllers/src/token-service.ts b/packages/assets-controllers/src/token-service.ts index 4672a817572..3a81c22c483 100644 --- a/packages/assets-controllers/src/token-service.ts +++ b/packages/assets-controllers/src/token-service.ts @@ -8,7 +8,9 @@ import type { CaipChainId, Hex } from '@metamask/utils'; import { isTokenListSupportedForNetwork } from './assetsUtil'; -export const TOKEN_END_POINT_API = 'https://token.api.cx.metamask.io'; +// export const TOKEN_END_POINT_API = 'https://token.api.cx.metamask.io'; +// TODO change it back after development is done +export const TOKEN_END_POINT_API = 'https://token.dev-api.cx.metamask.io'; export const TOKEN_METADATA_NO_SUPPORT_ERROR = 'TokenService Error: Network does not support fetchTokenMetadata'; @@ -18,7 +20,7 @@ export const TOKEN_METADATA_NO_SUPPORT_ERROR = * @param chainId - The chain ID of the network the tokens requested are on. * @returns The tokens URL. */ -function getTokensURL(chainId: Hex) { +function getTokensURL(chainId: Hex): string { const occurrenceFloor = chainId === ChainId['linea-mainnet'] ? 1 : 3; return `${TOKEN_END_POINT_API}/tokens/${convertHexToDecimal( @@ -33,7 +35,7 @@ function getTokensURL(chainId: Hex) { * @param tokenAddress - The token address. * @returns The token metadata URL. */ -function getTokenMetadataURL(chainId: Hex, tokenAddress: string) { +function getTokenMetadataURL(chainId: Hex, tokenAddress: string): string { return `${TOKEN_END_POINT_API}/token/${convertHexToDecimal( chainId, )}?address=${tokenAddress}`; @@ -62,12 +64,12 @@ function getTokenSearchURL( query: string, limit = 10, includeMarketData = false, -) { +): string { const encodedQuery = encodeURIComponent(query); const encodedChainIds = chainIds .map((id) => encodeURIComponent(id)) .join(','); - return `${TOKEN_END_POINT_API}/tokens/search?networks=${encodedChainIds}&query=${encodedQuery}&limit=${limit}&includeMarketData=${includeMarketData}`; + return `${TOKEN_END_POINT_API}/tokens/search?networks=${encodedChainIds}&query=${encodedQuery}&limit=${limit}&includeMarketData=${includeMarketData}&includeRwaData=true`; } /** @@ -142,16 +144,42 @@ export async function fetchTokenListByChainId( if (response) { const result = await parseJsonResponse(response); if (Array.isArray(result) && chainId === ChainId['linea-mainnet']) { - return result.filter( + const filteredResult = result.filter( (elm) => - elm.aggregators.includes('lineaTeam') || elm.aggregators.length >= 3, + elm.aggregators.includes('lineaTeam') ?? elm.aggregators.length >= 3, ); + // TODO: remove this after development is done + // if the filteredResult has an aggregator that includes 'Ondo' then append rwaData as metadata. + const filteredResultWithRwaData = filteredResult.map((elm) => { + const metadata = { + rwaData: { + instrumentType: 'stock', + ticker: elm.name?.split(' ')[0] ?? '', + market: { + nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), + nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + }, + nextPause: { + start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + end: new Date(new Date().setHours(17, 0, 0, 0)).toISOString(), + }, + }, + }; + if (elm.aggregators.includes('Ondo')) { + return { ...elm, ...metadata }; + } + return elm; + }); + + console.log('filteredResult', filteredResult); + return filteredResultWithRwaData; } return result; } return undefined; } +// TODO This end point already contain RwaData, so we don't need to append it here. /** * Search for tokens across one or more networks by query string using CAIP format chain IDs. * @@ -180,7 +208,7 @@ export async function searchTokens( // The API returns an object with structure: { count: number, data: array, pageInfo: object } if (result && typeof result === 'object' && Array.isArray(result.data)) { return { - count: result.count || result.data.length, + count: result.count ?? result.data.length, data: result.data, }; } @@ -271,7 +299,21 @@ export async function getTrendingTokens({ // Validate that the API returned an array if (Array.isArray(result)) { - return result; + // TODO hack the results to include RwaData + const filteredResultWithRwaData = result.map((elm) => { + const metadata = { + rwaData: { + instrumentType: 'stock', + ticker: elm.name?.split(' ')[0] ?? '', + market: { + nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), + nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + }, + }, + }; + return { ...elm, ...metadata }; + }); + return filteredResultWithRwaData; } // Handle non-expected responses @@ -306,7 +348,31 @@ export async function fetchTokenMetadata( const tokenMetadataURL = getTokenMetadataURL(chainId, tokenAddress); const response = await queryApi(tokenMetadataURL, abortSignal, timeout); if (response) { - return parseJsonResponse(response) as Promise; + const result = await parseJsonResponse(response); + if (Array.isArray(result)) { + const filteredResultWithRwaData = result.map((elm) => { + const metadata = { + rwaData: { + instrumentType: 'stock', + ticker: elm.name?.split(' ')[0] ?? '', + market: { + nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), + nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + }, + nextPause: { + start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + end: new Date(new Date().setHours(17, 0, 0, 0)).toISOString(), + }, + }, + }; + if (elm.aggregators.includes('Ondo')) { + return { ...elm, ...metadata }; + } + return elm; + }); + return filteredResultWithRwaData as unknown as T; + } + return result as T; } return undefined; } diff --git a/packages/bridge-controller/src/utils/fetch.ts b/packages/bridge-controller/src/utils/fetch.ts index 5a391c777f3..bc8bb0753e1 100644 --- a/packages/bridge-controller/src/utils/fetch.ts +++ b/packages/bridge-controller/src/utils/fetch.ts @@ -53,7 +53,22 @@ export async function fetchBridgeTokens( const transformedTokens: Record = {}; tokens.forEach((token: unknown) => { if (validateSwapsTokenObject(token)) { - transformedTokens[token.address] = token; + // TODO hack the results to include RwaData + const metadata = { + rwaData: { + instrumentType: 'stock', + ticker: token.name?.split(' ')[0] ?? '', + market: { + nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), + nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + }, + nextPause: { + start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + end: new Date(new Date().setHours(17, 0, 0, 0)).toISOString(), + }, + }, + }; + transformedTokens[token.address] = { ...token, ...metadata }; } }); return transformedTokens; diff --git a/packages/bridge-controller/src/utils/validators.ts b/packages/bridge-controller/src/utils/validators.ts index 327a3f5eee1..f256b9cf68a 100644 --- a/packages/bridge-controller/src/utils/validators.ts +++ b/packages/bridge-controller/src/utils/validators.ts @@ -16,6 +16,7 @@ import { assert, pattern, intersection, + date, } from '@metamask/superstruct'; import { CaipAssetTypeStruct, isStrictHexString } from '@metamask/utils'; @@ -86,6 +87,21 @@ export const BridgeAssetSchema = type({ * URL for token icon */ iconUrl: optional(nullable(string())), + + rwaData: optional( + type({ + instrumentType: string(), + ticker: string(), + market: type({ + nextOpen: string(), + nextClose: string(), + }), + nextPause: type({ + start: string(), + end: string(), + }), + }), + ), }); const DefaultPairSchema = type({ From 7e9d704a93e5d2b4d51e070d8accac6eb1a5e0c8 Mon Sep 17 00:00:00 2001 From: "dawnseeker8@gmail.com" Date: Wed, 24 Dec 2025 16:50:23 +0800 Subject: [PATCH 2/4] Add some type definition to fix home asset rwaData lost. --- .../src/TokenListController.ts | 12 ++++ .../assets-controllers/src/token-service.ts | 58 ++++++++++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/packages/assets-controllers/src/TokenListController.ts b/packages/assets-controllers/src/TokenListController.ts index 6ee57c476bb..10e01b3a295 100644 --- a/packages/assets-controllers/src/TokenListController.ts +++ b/packages/assets-controllers/src/TokenListController.ts @@ -34,6 +34,18 @@ export type TokenListToken = { occurrences: number; aggregators: string[]; iconUrl: string; + rwaData: { + instrumentType: string; + ticker: string; + market: { + nextOpen: string; + nextClose: string; + }; + nextPause: { + start: string; + end: string; + }; + }; }; export type TokenListMap = Record; diff --git a/packages/assets-controllers/src/token-service.ts b/packages/assets-controllers/src/token-service.ts index 3a81c22c483..fc714520d5f 100644 --- a/packages/assets-controllers/src/token-service.ts +++ b/packages/assets-controllers/src/token-service.ts @@ -157,7 +157,9 @@ export async function fetchTokenListByChainId( ticker: elm.name?.split(' ')[0] ?? '', market: { nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), - nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + nextClose: new Date( + new Date().setHours(16, 0, 0, 0), + ).toISOString(), }, nextPause: { start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), @@ -174,6 +176,36 @@ export async function fetchTokenListByChainId( console.log('filteredResult', filteredResult); return filteredResultWithRwaData; } + + if (Array.isArray(result)) { + // TODO: remove this after development is done + // if the filteredResult has an aggregator that includes 'Ondo' then append rwaData as metadata. + const filteredResultWithRwaData = result.map((elm) => { + const metadata = { + rwaData: { + instrumentType: 'stock', + ticker: elm.name?.split(' ')[0] ?? '', + market: { + nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), + nextClose: new Date( + new Date().setHours(16, 0, 0, 0), + ).toISOString(), + }, + nextPause: { + start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + end: new Date(new Date().setHours(17, 0, 0, 0)).toISOString(), + }, + }, + }; + if (elm.aggregators.includes('Ondo')) { + return { ...elm, ...metadata }; + } + return elm; + }); + + console.log('filteredResultWithRwaData', filteredResultWithRwaData); + return filteredResultWithRwaData; + } return result; } return undefined; @@ -242,6 +274,18 @@ export type TrendingAsset = { h24?: string; }; labels?: string[]; + rwaData?: { + instrumentType: string; + ticker: string; + market: { + nextOpen: string; + nextClose: string; + }; + nextPause: { + start: string; + end: string; + }; + }; }; /** @@ -307,7 +351,13 @@ export async function getTrendingTokens({ ticker: elm.name?.split(' ')[0] ?? '', market: { nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), - nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + nextClose: new Date( + new Date().setHours(16, 0, 0, 0), + ).toISOString(), + }, + nextPause: { + start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + end: new Date(new Date().setHours(17, 0, 0, 0)).toISOString(), }, }, }; @@ -357,7 +407,9 @@ export async function fetchTokenMetadata( ticker: elm.name?.split(' ')[0] ?? '', market: { nextOpen: new Date(new Date().setHours(9, 0, 0, 0)).toISOString(), - nextClose: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), + nextClose: new Date( + new Date().setHours(16, 0, 0, 0), + ).toISOString(), }, nextPause: { start: new Date(new Date().setHours(16, 0, 0, 0)).toISOString(), From 16a22306451c8ad37f4a1c87260a1e852f01b956 Mon Sep 17 00:00:00 2001 From: "dawnseeker8@gmail.com" Date: Wed, 24 Dec 2025 17:17:54 +0800 Subject: [PATCH 3/4] Fix the lint issue. --- packages/bridge-controller/src/utils/validators.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/bridge-controller/src/utils/validators.ts b/packages/bridge-controller/src/utils/validators.ts index f256b9cf68a..bbad4569f77 100644 --- a/packages/bridge-controller/src/utils/validators.ts +++ b/packages/bridge-controller/src/utils/validators.ts @@ -16,7 +16,6 @@ import { assert, pattern, intersection, - date, } from '@metamask/superstruct'; import { CaipAssetTypeStruct, isStrictHexString } from '@metamask/utils'; From 42084fe4fbd1c2c58135dec9d10afafec352aedd Mon Sep 17 00:00:00 2001 From: "dawnseeker8@gmail.com" Date: Wed, 24 Dec 2025 17:24:14 +0800 Subject: [PATCH 4/4] make rwaData as optional --- packages/assets-controllers/src/TokenListController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/assets-controllers/src/TokenListController.ts b/packages/assets-controllers/src/TokenListController.ts index 10e01b3a295..6b2ecca89c9 100644 --- a/packages/assets-controllers/src/TokenListController.ts +++ b/packages/assets-controllers/src/TokenListController.ts @@ -34,7 +34,7 @@ export type TokenListToken = { occurrences: number; aggregators: string[]; iconUrl: string; - rwaData: { + rwaData?: { instrumentType: string; ticker: string; market: {