diff --git a/miniapps/biobridge/src/api/recharge.ts b/miniapps/biobridge/src/api/recharge.ts index 1e31bf17c..c1ffd623a 100644 --- a/miniapps/biobridge/src/api/recharge.ts +++ b/miniapps/biobridge/src/api/recharge.ts @@ -27,8 +27,12 @@ import type { ContractTokenInfo, } from './types' +const tokenInfoCache = new Map() +const tokenInfoInflight = new Map>() + /** - * Convert TRON hex addresses in ExternalAssetInfoItem to Base58 format + * Convert TRON hex deposit addresses in ExternalAssetInfoItem to Base58 format. + * Contract addresses must keep their original hex format for token info API. */ async function convertTronAddresses(item: ExternalAssetInfoItem): Promise { const result = { ...item } @@ -38,16 +42,11 @@ async function convertTronAddresses(item: ExternalAssetInfoItem): Promise { const recharge = { ...response.recharge } @@ -77,7 +76,7 @@ async function transformSupportResponse(response: RechargeSupportResDto): Promis } export const rechargeApi = { - /** 获取支持的充值配置 (TRON addresses converted to Base58) */ + /** 获取支持的充值配置 (TRON depositAddress converted to Base58) */ async getSupport(): Promise { const raw = await apiClient.get(API_ENDPOINTS.RECHARGE_SUPPORT) const parsed = rechargeSupportSchema.safeParse(raw) @@ -97,17 +96,37 @@ export const rechargeApi = { return parsed.data }, - /** 获取合约代币信息(精度/图标等) */ + /** 获取合约代币信息(精度/图标等),按 chainName+contractAddress 缓存 */ async getTokenInfo(params: { contractAddress: string; chainName: string }): Promise { - const raw = await apiClient.get(API_ENDPOINTS.CONTRACT_TOKEN_INFO, { - contractAddress: params.contractAddress, - chainName: params.chainName, - }) - const parsed = contractTokenInfoSchema.safeParse(raw) - if (!parsed.success) { - throw new ApiError('Invalid contract token info response', 0, parsed.error.flatten()) + const contractAddress = params.contractAddress.trim() + const chainName = params.chainName.trim() + const key = `${chainName}:${contractAddress}`.toLowerCase() + if (tokenInfoCache.has(key)) { + return tokenInfoCache.get(key) as ContractTokenInfo + } + if (tokenInfoInflight.has(key)) { + return tokenInfoInflight.get(key) as Promise + } + + const task = (async () => { + const raw = await apiClient.get(API_ENDPOINTS.CONTRACT_TOKEN_INFO, { + contractAddress, + chainName, + }) + const parsed = contractTokenInfoSchema.safeParse(raw) + if (!parsed.success) { + throw new ApiError('Invalid contract token info response', 0, parsed.error.flatten()) + } + tokenInfoCache.set(key, parsed.data) + return parsed.data + })() + + tokenInfoInflight.set(key, task) + try { + return await task + } finally { + tokenInfoInflight.delete(key) } - return parsed.data }, /** 获取合约池信息 */