@metamask-previews/assets-controller 0.0.0-preview-e09bf49f → 0.0.0-preview-9c68b732

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/AssetsController.cjs +26 -32
  3. package/dist/AssetsController.cjs.map +1 -1
  4. package/dist/AssetsController.d.cts +5 -1
  5. package/dist/AssetsController.d.cts.map +1 -1
  6. package/dist/AssetsController.d.mts +5 -1
  7. package/dist/AssetsController.d.mts.map +1 -1
  8. package/dist/AssetsController.mjs +26 -32
  9. package/dist/AssetsController.mjs.map +1 -1
  10. package/dist/data-sources/PriceDataSource.cjs +12 -19
  11. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  12. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  13. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  14. package/dist/data-sources/PriceDataSource.mjs +12 -19
  15. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  16. package/dist/data-sources/RpcDataSource.cjs +232 -42
  17. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  18. package/dist/data-sources/RpcDataSource.d.cts +5 -1
  19. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  20. package/dist/data-sources/RpcDataSource.d.mts +5 -1
  21. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  22. package/dist/data-sources/RpcDataSource.mjs +229 -42
  23. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  24. package/dist/data-sources/evm-rpc-services/index.cjs.map +1 -1
  25. package/dist/data-sources/evm-rpc-services/index.d.cts +1 -1
  26. package/dist/data-sources/evm-rpc-services/index.d.cts.map +1 -1
  27. package/dist/data-sources/evm-rpc-services/index.d.mts +1 -1
  28. package/dist/data-sources/evm-rpc-services/index.d.mts.map +1 -1
  29. package/dist/data-sources/evm-rpc-services/index.mjs.map +1 -1
  30. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +32 -27
  31. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
  32. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +12 -5
  33. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
  34. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +12 -5
  35. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
  36. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +32 -27
  37. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
  38. package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs +23 -12
  39. package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs.map +1 -1
  40. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts +8 -3
  41. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts.map +1 -1
  42. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts +8 -3
  43. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts.map +1 -1
  44. package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs +23 -12
  45. package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs.map +1 -1
  46. package/dist/data-sources/evm-rpc-services/services/index.cjs.map +1 -1
  47. package/dist/data-sources/evm-rpc-services/services/index.d.cts +2 -2
  48. package/dist/data-sources/evm-rpc-services/services/index.d.cts.map +1 -1
  49. package/dist/data-sources/evm-rpc-services/services/index.d.mts +2 -2
  50. package/dist/data-sources/evm-rpc-services/services/index.d.mts.map +1 -1
  51. package/dist/data-sources/evm-rpc-services/services/index.mjs.map +1 -1
  52. package/dist/data-sources/evm-rpc-services/types/index.cjs.map +1 -1
  53. package/dist/data-sources/evm-rpc-services/types/index.d.cts +1 -1
  54. package/dist/data-sources/evm-rpc-services/types/index.d.cts.map +1 -1
  55. package/dist/data-sources/evm-rpc-services/types/index.d.mts +1 -1
  56. package/dist/data-sources/evm-rpc-services/types/index.d.mts.map +1 -1
  57. package/dist/data-sources/evm-rpc-services/types/index.mjs.map +1 -1
  58. package/dist/data-sources/evm-rpc-services/types/state.cjs.map +1 -1
  59. package/dist/data-sources/evm-rpc-services/types/state.d.cts +9 -24
  60. package/dist/data-sources/evm-rpc-services/types/state.d.cts.map +1 -1
  61. package/dist/data-sources/evm-rpc-services/types/state.d.mts +9 -24
  62. package/dist/data-sources/evm-rpc-services/types/state.d.mts.map +1 -1
  63. package/dist/data-sources/evm-rpc-services/types/state.mjs.map +1 -1
  64. package/dist/types.cjs.map +1 -1
  65. package/dist/types.d.cts +40 -6
  66. package/dist/types.d.cts.map +1 -1
  67. package/dist/types.d.mts +40 -6
  68. package/dist/types.d.mts.map +1 -1
  69. package/dist/types.mjs.map +1 -1
  70. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PriceDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SupportedCurrency,\n V3SpotPricesResponse,\n} from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { SubscriptionRequest } from './AbstractDataSource';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetPrice,\n AssetBalance,\n AccountId,\n ChainId,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'PriceDataSource';\nconst DEFAULT_POLL_INTERVAL = 60_000; // 1 minute for price updates\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Action to get balance state (used to determine which assets need prices).\n */\ntype GetAssetsBalanceStateAction = {\n type: 'AssetsController:getState';\n handler: () => {\n assetsBalance: Record<AccountId, Record<Caip19AssetId, AssetBalance>>;\n };\n};\n\n/**\n * Action to get the PriceDataSource middleware.\n */\nexport type PriceDataSourceGetAssetsMiddlewareAction = {\n type: `${typeof CONTROLLER_NAME}:getAssetsMiddleware`;\n handler: () => Middleware;\n};\n\n/**\n * Action to fetch prices for assets.\n */\nexport type PriceDataSourceFetchAction = {\n type: `${typeof CONTROLLER_NAME}:fetch`;\n handler: (request: DataRequest) => Promise<DataResponse>;\n};\n\n/**\n * Action to subscribe to price updates.\n */\nexport type PriceDataSourceSubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:subscribe`;\n handler: (request: SubscriptionRequest) => Promise<void>;\n};\n\n/**\n * Action to unsubscribe from price updates.\n */\nexport type PriceDataSourceUnsubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:unsubscribe`;\n handler: (subscriptionId: string) => Promise<void>;\n};\n\n/**\n * All actions exposed by PriceDataSource.\n */\nexport type PriceDataSourceActions =\n | PriceDataSourceGetAssetsMiddlewareAction\n | PriceDataSourceFetchAction\n | PriceDataSourceSubscribeAction\n | PriceDataSourceUnsubscribeAction;\n\n/**\n * Event emitted when prices are updated.\n */\nexport type PriceDataSourceAssetsUpdatedEvent = {\n type: `${typeof CONTROLLER_NAME}:assetsUpdated`;\n payload: [DataResponse, string];\n};\n\n/**\n * All events exposed by PriceDataSource.\n */\nexport type PriceDataSourceEvents = PriceDataSourceAssetsUpdatedEvent;\n\n// Action to report assets updated to AssetsController\ntype AssetsControllerAssetsUpdateAction = {\n type: 'AssetsController:assetsUpdate';\n handler: (response: DataResponse, sourceId: string) => Promise<void>;\n};\n\n/**\n * External actions that PriceDataSource needs to call.\n * Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed.\n */\nexport type PriceDataSourceAllowedActions =\n | GetAssetsBalanceStateAction\n | AssetsControllerAssetsUpdateAction;\n\nexport type PriceDataSourceMessenger = Messenger<\n typeof CONTROLLER_NAME,\n PriceDataSourceAllowedActions | PriceDataSourceActions,\n PriceDataSourceEvents\n>;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type PriceDataSourceOptions = {\n messenger: PriceDataSourceMessenger;\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Currency to fetch prices in (default: 'usd') */\n currency?: SupportedCurrency;\n /** Polling interval in ms (default: 60000) */\n pollInterval?: number;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Asset reference patterns that should NOT be sent to the Price API.\n * These are internal resource tracking values without market prices.\n */\nconst NON_PRICEABLE_ASSET_PATTERNS = [\n // Tron resource assets (bandwidth, energy, staking states)\n /\\/slip44:\\d+-staked-for-/u,\n /\\/slip44:bandwidth$/u,\n /\\/slip44:energy$/u,\n /\\/slip44:maximum-bandwidth$/u,\n /\\/slip44:maximum-energy$/u,\n];\n\n/**\n * Check if an asset ID represents a priceable asset.\n * Filters out internal resource tracking values that don't have market prices.\n *\n * @param assetId - The CAIP-19 asset ID to check.\n * @returns True if the asset has market price data.\n */\nfunction isPriceableAsset(assetId: Caip19AssetId): boolean {\n return !NON_PRICEABLE_ASSET_PATTERNS.some((pattern) => pattern.test(assetId));\n}\n\n/** Market data item from spot prices response */\ntype SpotPriceMarketData = {\n price: number;\n pricePercentChange1d?: number;\n marketCap?: number;\n totalVolume?: number;\n};\n\n/**\n * Type guard to check if market data has a valid price\n *\n * @param data - The data to check.\n * @returns True if data is valid SpotPriceMarketData.\n */\nfunction isValidMarketData(data: unknown): data is SpotPriceMarketData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'price' in data &&\n typeof (data as SpotPriceMarketData).price === 'number'\n );\n}\n\nfunction transformMarketDataToAssetPrice(\n marketData: SpotPriceMarketData,\n): AssetPrice {\n return {\n price: marketData.price,\n priceChange24h: marketData.pricePercentChange1d,\n lastUpdated: Date.now(),\n // Extended market data\n marketCap: marketData.marketCap,\n volume24h: marketData.totalVolume,\n };\n}\n\n// ============================================================================\n// PRICE DATA SOURCE\n// ============================================================================\n\n/**\n * PriceDataSource fetches asset prices from the Price API.\n *\n * This data source:\n * - Fetches prices from Price API v3 spot-prices endpoint\n * - Supports one-time fetch and subscription-based polling\n * - In subscribe mode, automatically fetches prices for all assets in assetsBalance state\n * - Publishes price updates via messenger events\n *\n * Usage:\n * ```typescript\n * // Create and initialize (registers messenger actions)\n * const priceDataSource = new PriceDataSource({ messenger });\n *\n * // One-time fetch for specific assets\n * const response = await messenger.call('PriceDataSource:fetch', {\n * customAssets: ['eip155:1/erc20:0x...'],\n * });\n *\n * // Subscribe to price updates (polls all assets in balance state)\n * await messenger.call('PriceDataSource:subscribe', { request, subscriptionId });\n *\n * // Listen for updates\n * messenger.subscribe('PriceDataSource:assetsUpdated', (response) => {\n * // Handle price updates\n * });\n * ```\n */\nexport class PriceDataSource {\n readonly name = CONTROLLER_NAME;\n\n readonly #messenger: PriceDataSourceMessenger;\n\n readonly #currency: SupportedCurrency;\n\n readonly #pollInterval: number;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<\n string,\n { cleanup: () => void; request: DataRequest }\n > = new Map();\n\n constructor(options: PriceDataSourceOptions) {\n this.#messenger = options.messenger;\n this.#currency = options.currency ?? 'usd';\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#apiClient = options.queryApiClient;\n\n this.#registerActionHandlers();\n }\n\n #registerActionHandlers(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n messenger.registerActionHandler(\n 'PriceDataSource:getAssetsMiddleware',\n () => this.assetsMiddleware,\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:fetch',\n (request: DataRequest) => this.fetch(request),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:subscribe',\n (subscriptionRequest: SubscriptionRequest) =>\n this.subscribe(subscriptionRequest),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:unsubscribe',\n (subscriptionId: string) => this.unsubscribe(subscriptionId),\n );\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for enriching responses with price data.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches prices for detected assets (assets without metadata)\n * 3. Enriches the response with fetched prices\n * 4. Calls next() at the end to continue the middleware chain\n *\n * Note: This middleware ONLY fetches prices for detected assets.\n * For fetching prices for all assets, use the subscription mechanism\n * which polls prices for all assets in the balance state.\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['price'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n // Only fetch prices for detected assets (assets without metadata)\n // The subscription handles fetching prices for all existing assets\n if (!response.detectedAssets) {\n return next(ctx);\n }\n\n const detectedAssetIds = new Set<Caip19AssetId>();\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n detectedAssetIds.add(assetId);\n }\n }\n\n if (detectedAssetIds.size === 0) {\n return next(ctx);\n }\n\n // Filter to only priceable assets\n const priceableAssetIds = [...detectedAssetIds].filter(isPriceableAsset);\n\n if (priceableAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices(\n priceableAssetIds,\n true, // includeMarketData\n );\n\n response.assetsPrice ??= {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] =\n transformMarketDataToAssetPrice(marketData);\n }\n } catch (error) {\n log('Failed to fetch prices via middleware', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n\n // ============================================================================\n // HELPERS\n // ============================================================================\n\n /**\n * Fetch spot prices with caching and deduplication via query service.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @param includeMarketData - Whether to include market data\n * @returns Spot prices response\n */\n async #fetchSpotPrices(\n assetIds: string[],\n includeMarketData: boolean,\n ): Promise<V3SpotPricesResponse> {\n return this.#apiClient.prices.fetchV3SpotPrices(assetIds, {\n currency: this.#currency,\n includeMarketData,\n });\n }\n\n /**\n * Get unique asset IDs from the assetsBalance state.\n * Filters by accounts and chains from the request.\n *\n * @param request - Data request with accounts and chainIds filters.\n * @returns Array of CAIP-19 asset IDs from balance state.\n */\n #getAssetIdsFromBalanceState(request: DataRequest): Caip19AssetId[] {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n const assetIds = new Set<Caip19AssetId>();\n\n const accountIds = request.accounts.map((a) => a.id);\n const accountFilter =\n accountIds.length > 0 ? new Set(accountIds) : undefined;\n const chainFilter =\n request.chainIds.length > 0 ? new Set(request.chainIds) : undefined;\n\n if (state?.assetsBalance) {\n for (const [accountId, accountBalances] of Object.entries(\n state.assetsBalance,\n )) {\n // Filter by account if specified\n if (accountFilter && !accountFilter.has(accountId)) {\n continue;\n }\n\n for (const assetId of Object.keys(\n accountBalances as Record<string, unknown>,\n )) {\n // Filter by chain if specified\n if (chainFilter) {\n const chainId = assetId.split('/')[0] as ChainId;\n if (!chainFilter.has(chainId)) {\n continue;\n }\n }\n assetIds.add(assetId as Caip19AssetId);\n }\n }\n }\n\n return [...assetIds];\n } catch (error) {\n log('Failed to get asset IDs from balance state', { error });\n return [];\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n /**\n * Fetch prices for assets held by the accounts and chains in the request.\n * Gets asset IDs from balance state, filtered by request.accounts and request.chainIds.\n *\n * @param request - The data request specifying accounts and chains.\n * @returns DataResponse containing asset prices.\n */\n async fetch(request: DataRequest): Promise<DataResponse> {\n const response: DataResponse = {};\n\n // Get asset IDs from balance state, filtered by accounts and chains\n const rawAssetIds = this.#getAssetIdsFromBalanceState(request);\n\n // Filter out non-priceable assets (e.g., Tron bandwidth/energy resources)\n const assetIds = rawAssetIds.filter(isPriceableAsset);\n\n if (assetIds.length === 0) {\n return response;\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices(\n [...assetIds],\n true, // includeMarketData\n );\n\n response.assetsPrice = {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n // Skip assets with invalid market data (API doesn't have price for this asset)\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] =\n transformMarketDataToAssetPrice(marketData);\n }\n } catch (error) {\n log('Failed to fetch prices', { error });\n }\n\n return response;\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n /**\n * Subscribe to price updates.\n * Sets up polling that fetches prices for all assets in assetsBalance state.\n *\n * @param subscriptionRequest - The subscription request configuration.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Handle subscription update - just update the request\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function - fetches prices for all assets in balance state\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (!subscription) {\n return;\n }\n\n // Fetch prices for all assets currently in balance state\n const fetchResponse = await this.fetch(subscription.request);\n\n // Only report if we got prices\n if (\n fetchResponse.assetsPrice &&\n Object.keys(fetchResponse.assetsPrice).length > 0\n ) {\n await this.#messenger.call(\n 'AssetsController:assetsUpdate',\n fetchResponse,\n CONTROLLER_NAME,\n );\n }\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription\n this.#activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n request,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n /**\n * Unsubscribe from price updates.\n *\n * @param subscriptionId - The ID of the subscription to cancel.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n subscription.cleanup();\n this.#activeSubscriptions.delete(subscriptionId);\n }\n }\n\n /**\n * Destroy the data source and clean up all subscriptions.\n */\n destroy(): void {\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.cleanup();\n }\n this.#activeSubscriptions.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"PriceDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SupportedCurrency,\n V3SpotPricesResponse,\n} from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { SubscriptionRequest } from './AbstractDataSource';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetBalance,\n AccountId,\n ChainId,\n DataRequest,\n DataResponse,\n FungibleAssetPrice,\n Middleware,\n} from '../types';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'PriceDataSource';\nconst DEFAULT_POLL_INTERVAL = 60_000; // 1 minute for price updates\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Action to get balance state (used to determine which assets need prices).\n */\ntype GetAssetsBalanceStateAction = {\n type: 'AssetsController:getState';\n handler: () => {\n assetsBalance: Record<AccountId, Record<Caip19AssetId, AssetBalance>>;\n };\n};\n\n/**\n * Action to get the PriceDataSource middleware.\n */\nexport type PriceDataSourceGetAssetsMiddlewareAction = {\n type: `${typeof CONTROLLER_NAME}:getAssetsMiddleware`;\n handler: () => Middleware;\n};\n\n/**\n * Action to fetch prices for assets.\n */\nexport type PriceDataSourceFetchAction = {\n type: `${typeof CONTROLLER_NAME}:fetch`;\n handler: (request: DataRequest) => Promise<DataResponse>;\n};\n\n/**\n * Action to subscribe to price updates.\n */\nexport type PriceDataSourceSubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:subscribe`;\n handler: (request: SubscriptionRequest) => Promise<void>;\n};\n\n/**\n * Action to unsubscribe from price updates.\n */\nexport type PriceDataSourceUnsubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:unsubscribe`;\n handler: (subscriptionId: string) => Promise<void>;\n};\n\n/**\n * All actions exposed by PriceDataSource.\n */\nexport type PriceDataSourceActions =\n | PriceDataSourceGetAssetsMiddlewareAction\n | PriceDataSourceFetchAction\n | PriceDataSourceSubscribeAction\n | PriceDataSourceUnsubscribeAction;\n\n/**\n * Event emitted when prices are updated.\n */\nexport type PriceDataSourceAssetsUpdatedEvent = {\n type: `${typeof CONTROLLER_NAME}:assetsUpdated`;\n payload: [DataResponse, string];\n};\n\n/**\n * All events exposed by PriceDataSource.\n */\nexport type PriceDataSourceEvents = PriceDataSourceAssetsUpdatedEvent;\n\n// Action to report assets updated to AssetsController\ntype AssetsControllerAssetsUpdateAction = {\n type: 'AssetsController:assetsUpdate';\n handler: (response: DataResponse, sourceId: string) => Promise<void>;\n};\n\n/**\n * External actions that PriceDataSource needs to call.\n * Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed.\n */\nexport type PriceDataSourceAllowedActions =\n | GetAssetsBalanceStateAction\n | AssetsControllerAssetsUpdateAction;\n\nexport type PriceDataSourceMessenger = Messenger<\n typeof CONTROLLER_NAME,\n PriceDataSourceAllowedActions | PriceDataSourceActions,\n PriceDataSourceEvents\n>;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type PriceDataSourceOptions = {\n messenger: PriceDataSourceMessenger;\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Currency to fetch prices in (default: 'usd') */\n currency?: SupportedCurrency;\n /** Polling interval in ms (default: 60000) */\n pollInterval?: number;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Asset reference patterns that should NOT be sent to the Price API.\n * These are internal resource tracking values without market prices.\n */\nconst NON_PRICEABLE_ASSET_PATTERNS = [\n // Tron resource assets (bandwidth, energy, staking states)\n /\\/slip44:\\d+-staked-for-/u,\n /\\/slip44:bandwidth$/u,\n /\\/slip44:energy$/u,\n /\\/slip44:maximum-bandwidth$/u,\n /\\/slip44:maximum-energy$/u,\n];\n\n/**\n * Check if an asset ID represents a priceable asset.\n * Filters out internal resource tracking values that don't have market prices.\n *\n * @param assetId - The CAIP-19 asset ID to check.\n * @returns True if the asset has market price data.\n */\nfunction isPriceableAsset(assetId: Caip19AssetId): boolean {\n return !NON_PRICEABLE_ASSET_PATTERNS.some((pattern) => pattern.test(assetId));\n}\n\n/** Market data item from spot prices response (same as FungibleAssetPrice without lastUpdated) */\ntype SpotPriceMarketData = Omit<FungibleAssetPrice, 'lastUpdated'>;\n\n/**\n * Type guard to check if market data has a valid price\n *\n * @param data - The data to check.\n * @returns True if data is valid SpotPriceMarketData.\n */\nfunction isValidMarketData(data: unknown): data is SpotPriceMarketData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'price' in data &&\n typeof (data as SpotPriceMarketData).price === 'number'\n );\n}\n\n// ============================================================================\n// PRICE DATA SOURCE\n// ============================================================================\n\n/**\n * PriceDataSource fetches asset prices from the Price API.\n *\n * This data source:\n * - Fetches prices from Price API v3 spot-prices endpoint\n * - Supports one-time fetch and subscription-based polling\n * - In subscribe mode, automatically fetches prices for all assets in assetsBalance state\n * - Publishes price updates via messenger events\n *\n * Usage:\n * ```typescript\n * // Create and initialize (registers messenger actions)\n * const priceDataSource = new PriceDataSource({ messenger });\n *\n * // One-time fetch for specific assets\n * const response = await messenger.call('PriceDataSource:fetch', {\n * customAssets: ['eip155:1/erc20:0x...'],\n * });\n *\n * // Subscribe to price updates (polls all assets in balance state)\n * await messenger.call('PriceDataSource:subscribe', { request, subscriptionId });\n *\n * // Listen for updates\n * messenger.subscribe('PriceDataSource:assetsUpdated', (response) => {\n * // Handle price updates\n * });\n * ```\n */\nexport class PriceDataSource {\n readonly name = CONTROLLER_NAME;\n\n readonly #messenger: PriceDataSourceMessenger;\n\n readonly #currency: SupportedCurrency;\n\n readonly #pollInterval: number;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<\n string,\n { cleanup: () => void; request: DataRequest }\n > = new Map();\n\n constructor(options: PriceDataSourceOptions) {\n this.#messenger = options.messenger;\n this.#currency = options.currency ?? 'usd';\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#apiClient = options.queryApiClient;\n\n this.#registerActionHandlers();\n }\n\n #registerActionHandlers(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n messenger.registerActionHandler(\n 'PriceDataSource:getAssetsMiddleware',\n () => this.assetsMiddleware,\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:fetch',\n (request: DataRequest) => this.fetch(request),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:subscribe',\n (subscriptionRequest: SubscriptionRequest) =>\n this.subscribe(subscriptionRequest),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:unsubscribe',\n (subscriptionId: string) => this.unsubscribe(subscriptionId),\n );\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for enriching responses with price data.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches prices for detected assets (assets without metadata)\n * 3. Enriches the response with fetched prices\n * 4. Calls next() at the end to continue the middleware chain\n *\n * Note: This middleware ONLY fetches prices for detected assets.\n * For fetching prices for all assets, use the subscription mechanism\n * which polls prices for all assets in the balance state.\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['price'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n // Only fetch prices for detected assets (assets without metadata)\n // The subscription handles fetching prices for all existing assets\n if (!response.detectedAssets) {\n return next(ctx);\n }\n\n const detectedAssetIds = new Set<Caip19AssetId>();\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n detectedAssetIds.add(assetId);\n }\n }\n\n if (detectedAssetIds.size === 0) {\n return next(ctx);\n }\n\n // Filter to only priceable assets\n const priceableAssetIds = [...detectedAssetIds].filter(isPriceableAsset);\n\n if (priceableAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices(priceableAssetIds);\n\n response.assetsPrice ??= {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] = {\n ...marketData,\n lastUpdated: Date.now(),\n };\n }\n } catch (error) {\n log('Failed to fetch prices via middleware', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n\n // ============================================================================\n // HELPERS\n // ============================================================================\n\n /**\n * Fetch spot prices with caching and deduplication via query service.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @returns Spot prices response\n */\n async #fetchSpotPrices(assetIds: string[]): Promise<V3SpotPricesResponse> {\n return this.#apiClient.prices.fetchV3SpotPrices(assetIds, {\n currency: this.#currency,\n includeMarketData: true,\n });\n }\n\n /**\n * Get unique asset IDs from the assetsBalance state.\n * Filters by accounts and chains from the request.\n *\n * @param request - Data request with accounts and chainIds filters.\n * @returns Array of CAIP-19 asset IDs from balance state.\n */\n #getAssetIdsFromBalanceState(request: DataRequest): Caip19AssetId[] {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n const assetIds = new Set<Caip19AssetId>();\n\n const accountIds = request.accounts.map((a) => a.id);\n const accountFilter =\n accountIds.length > 0 ? new Set(accountIds) : undefined;\n const chainFilter =\n request.chainIds.length > 0 ? new Set(request.chainIds) : undefined;\n\n if (state?.assetsBalance) {\n for (const [accountId, accountBalances] of Object.entries(\n state.assetsBalance,\n )) {\n // Filter by account if specified\n if (accountFilter && !accountFilter.has(accountId)) {\n continue;\n }\n\n for (const assetId of Object.keys(\n accountBalances as Record<string, unknown>,\n )) {\n // Filter by chain if specified\n if (chainFilter) {\n const chainId = assetId.split('/')[0] as ChainId;\n if (!chainFilter.has(chainId)) {\n continue;\n }\n }\n assetIds.add(assetId as Caip19AssetId);\n }\n }\n }\n\n return [...assetIds];\n } catch (error) {\n log('Failed to get asset IDs from balance state', { error });\n return [];\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n /**\n * Fetch prices for assets held by the accounts and chains in the request.\n * Gets asset IDs from balance state, filtered by request.accounts and request.chainIds.\n *\n * @param request - The data request specifying accounts and chains.\n * @returns DataResponse containing asset prices.\n */\n async fetch(request: DataRequest): Promise<DataResponse> {\n const response: DataResponse = {};\n\n // Get asset IDs from balance state, filtered by accounts and chains\n const rawAssetIds = this.#getAssetIdsFromBalanceState(request);\n\n // Filter out non-priceable assets (e.g., Tron bandwidth/energy resources)\n const assetIds = rawAssetIds.filter(isPriceableAsset);\n\n if (assetIds.length === 0) {\n return response;\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices([...assetIds]);\n\n response.assetsPrice = {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n // Skip assets with invalid market data (API doesn't have price for this asset)\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] = {\n ...marketData,\n lastUpdated: Date.now(),\n };\n }\n } catch (error) {\n log('Failed to fetch prices', { error });\n }\n\n return response;\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n /**\n * Subscribe to price updates.\n * Sets up polling that fetches prices for all assets in assetsBalance state.\n *\n * @param subscriptionRequest - The subscription request configuration.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Handle subscription update - just update the request\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function - fetches prices for all assets in balance state\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (!subscription) {\n return;\n }\n\n // Fetch prices for all assets currently in balance state\n const fetchResponse = await this.fetch(subscription.request);\n\n // Only report if we got prices\n if (\n fetchResponse.assetsPrice &&\n Object.keys(fetchResponse.assetsPrice).length > 0\n ) {\n await this.#messenger.call(\n 'AssetsController:assetsUpdate',\n fetchResponse,\n CONTROLLER_NAME,\n );\n }\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription\n this.#activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n request,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n /**\n * Unsubscribe from price updates.\n *\n * @param subscriptionId - The ID of the subscription to cancel.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n subscription.cleanup();\n this.#activeSubscriptions.delete(subscriptionId);\n }\n }\n\n /**\n * Destroy the data source and clean up all subscriptions.\n */\n destroy(): void {\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.cleanup();\n }\n this.#activeSubscriptions.clear();\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"PriceDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PriceDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAElB,+BAA+B;AAChC,OAAO,EAAE,iBAAiB,EAAE,+BAA+B;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,mBAAmB,EAAE,iCAA6B;AAGhE,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,SAAS,EAET,WAAW,EACX,YAAY,EAEZ,UAAU,EACX,qBAAiB;AAMlB,QAAA,MAAM,eAAe,oBAAoB,CAAC;AAS1C;;GAEG;AACH,KAAK,2BAA2B,GAAG;IACjC,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,MAAM;QACb,aAAa,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC;KACvE,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wCAAwC,GAAG;IACrD,IAAI,EAAE,GAAG,OAAO,eAAe,sBAAsB,CAAC;IACtD,OAAO,EAAE,MAAM,UAAU,CAAC;CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,IAAI,EAAE,GAAG,OAAO,eAAe,QAAQ,CAAC;IACxC,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,GAAG,OAAO,eAAe,YAAY,CAAC;IAC5C,OAAO,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,GAAG,OAAO,eAAe,cAAc,CAAC;IAC9C,OAAO,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B,wCAAwC,GACxC,0BAA0B,GAC1B,8BAA8B,GAC9B,gCAAgC,CAAC;AAErC;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,GAAG,OAAO,eAAe,gBAAgB,CAAC;IAChD,OAAO,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,iCAAiC,CAAC;AAGtE,KAAK,kCAAkC,GAAG;IACxC,IAAI,EAAE,+BAA+B,CAAC;IACtC,OAAO,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GACrC,2BAA2B,GAC3B,kCAAkC,CAAC;AAEvC,MAAM,MAAM,wBAAwB,GAAG,SAAS,CAC9C,OAAO,eAAe,EACtB,6BAA6B,GAAG,sBAAsB,EACtD,qBAAqB,CACtB,CAAC;AAMF,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,wBAAwB,CAAC;IACpC,mDAAmD;IACnD,cAAc,EAAE,iBAAiB,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,8CAA8C;IAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAoDF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,eAAe;;IAC1B,QAAQ,CAAC,IAAI,qBAAmB;gBAiBpB,OAAO,EAAE,sBAAsB;IAuC3C;;;;;;;;;;;;;;OAcG;IACH,IAAI,gBAAgB,IAAI,UAAU,CAoDjC;IAwED;;;;;;OAMG;IACG,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAyCxD;;;;;OAKG;IACG,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IA6DxE;;;;OAIG;IACG,WAAW,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxD;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"PriceDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PriceDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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"}
@@ -56,16 +56,6 @@ function isValidMarketData(data) {
56
56
  'price' in data &&
57
57
  typeof data.price === 'number');
58
58
  }
59
- function transformMarketDataToAssetPrice(marketData) {
60
- return {
61
- price: marketData.price,
62
- priceChange24h: marketData.pricePercentChange1d,
63
- lastUpdated: Date.now(),
64
- // Extended market data
65
- marketCap: marketData.marketCap,
66
- volume24h: marketData.totalVolume,
67
- };
68
- }
69
59
  // ============================================================================
70
60
  // PRICE DATA SOURCE
71
61
  // ============================================================================
@@ -156,15 +146,17 @@ export class PriceDataSource {
156
146
  return next(ctx);
157
147
  }
158
148
  try {
159
- const priceResponse = await __classPrivateFieldGet(this, _PriceDataSource_instances, "m", _PriceDataSource_fetchSpotPrices).call(this, priceableAssetIds, true);
149
+ const priceResponse = await __classPrivateFieldGet(this, _PriceDataSource_instances, "m", _PriceDataSource_fetchSpotPrices).call(this, priceableAssetIds);
160
150
  response.assetsPrice ?? (response.assetsPrice = {});
161
151
  for (const [assetId, marketData] of Object.entries(priceResponse)) {
162
152
  if (!isValidMarketData(marketData)) {
163
153
  continue;
164
154
  }
165
155
  const caipAssetId = assetId;
166
- response.assetsPrice[caipAssetId] =
167
- transformMarketDataToAssetPrice(marketData);
156
+ response.assetsPrice[caipAssetId] = {
157
+ ...marketData,
158
+ lastUpdated: Date.now(),
159
+ };
168
160
  }
169
161
  }
170
162
  catch (error) {
@@ -194,7 +186,7 @@ export class PriceDataSource {
194
186
  return response;
195
187
  }
196
188
  try {
197
- const priceResponse = await __classPrivateFieldGet(this, _PriceDataSource_instances, "m", _PriceDataSource_fetchSpotPrices).call(this, [...assetIds], true);
189
+ const priceResponse = await __classPrivateFieldGet(this, _PriceDataSource_instances, "m", _PriceDataSource_fetchSpotPrices).call(this, [...assetIds]);
198
190
  response.assetsPrice = {};
199
191
  for (const [assetId, marketData] of Object.entries(priceResponse)) {
200
192
  // Skip assets with invalid market data (API doesn't have price for this asset)
@@ -202,8 +194,10 @@ export class PriceDataSource {
202
194
  continue;
203
195
  }
204
196
  const caipAssetId = assetId;
205
- response.assetsPrice[caipAssetId] =
206
- transformMarketDataToAssetPrice(marketData);
197
+ response.assetsPrice[caipAssetId] = {
198
+ ...marketData,
199
+ lastUpdated: Date.now(),
200
+ };
207
201
  }
208
202
  }
209
203
  catch (error) {
@@ -303,13 +297,12 @@ _PriceDataSource_messenger = new WeakMap(), _PriceDataSource_currency = new Weak
303
297
  * Fetch spot prices with caching and deduplication via query service.
304
298
  *
305
299
  * @param assetIds - Array of CAIP-19 asset IDs
306
- * @param includeMarketData - Whether to include market data
307
300
  * @returns Spot prices response
308
301
  */
309
- async function _PriceDataSource_fetchSpotPrices(assetIds, includeMarketData) {
302
+ async function _PriceDataSource_fetchSpotPrices(assetIds) {
310
303
  return __classPrivateFieldGet(this, _PriceDataSource_apiClient, "f").prices.fetchV3SpotPrices(assetIds, {
311
304
  currency: __classPrivateFieldGet(this, _PriceDataSource_currency, "f"),
312
- includeMarketData,
305
+ includeMarketData: true,
313
306
  });
314
307
  }, _PriceDataSource_getAssetIdsFromBalanceState = function _PriceDataSource_getAssetIdsFromBalanceState(request) {
315
308
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"PriceDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SupportedCurrency,\n V3SpotPricesResponse,\n} from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { SubscriptionRequest } from './AbstractDataSource';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetPrice,\n AssetBalance,\n AccountId,\n ChainId,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'PriceDataSource';\nconst DEFAULT_POLL_INTERVAL = 60_000; // 1 minute for price updates\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Action to get balance state (used to determine which assets need prices).\n */\ntype GetAssetsBalanceStateAction = {\n type: 'AssetsController:getState';\n handler: () => {\n assetsBalance: Record<AccountId, Record<Caip19AssetId, AssetBalance>>;\n };\n};\n\n/**\n * Action to get the PriceDataSource middleware.\n */\nexport type PriceDataSourceGetAssetsMiddlewareAction = {\n type: `${typeof CONTROLLER_NAME}:getAssetsMiddleware`;\n handler: () => Middleware;\n};\n\n/**\n * Action to fetch prices for assets.\n */\nexport type PriceDataSourceFetchAction = {\n type: `${typeof CONTROLLER_NAME}:fetch`;\n handler: (request: DataRequest) => Promise<DataResponse>;\n};\n\n/**\n * Action to subscribe to price updates.\n */\nexport type PriceDataSourceSubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:subscribe`;\n handler: (request: SubscriptionRequest) => Promise<void>;\n};\n\n/**\n * Action to unsubscribe from price updates.\n */\nexport type PriceDataSourceUnsubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:unsubscribe`;\n handler: (subscriptionId: string) => Promise<void>;\n};\n\n/**\n * All actions exposed by PriceDataSource.\n */\nexport type PriceDataSourceActions =\n | PriceDataSourceGetAssetsMiddlewareAction\n | PriceDataSourceFetchAction\n | PriceDataSourceSubscribeAction\n | PriceDataSourceUnsubscribeAction;\n\n/**\n * Event emitted when prices are updated.\n */\nexport type PriceDataSourceAssetsUpdatedEvent = {\n type: `${typeof CONTROLLER_NAME}:assetsUpdated`;\n payload: [DataResponse, string];\n};\n\n/**\n * All events exposed by PriceDataSource.\n */\nexport type PriceDataSourceEvents = PriceDataSourceAssetsUpdatedEvent;\n\n// Action to report assets updated to AssetsController\ntype AssetsControllerAssetsUpdateAction = {\n type: 'AssetsController:assetsUpdate';\n handler: (response: DataResponse, sourceId: string) => Promise<void>;\n};\n\n/**\n * External actions that PriceDataSource needs to call.\n * Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed.\n */\nexport type PriceDataSourceAllowedActions =\n | GetAssetsBalanceStateAction\n | AssetsControllerAssetsUpdateAction;\n\nexport type PriceDataSourceMessenger = Messenger<\n typeof CONTROLLER_NAME,\n PriceDataSourceAllowedActions | PriceDataSourceActions,\n PriceDataSourceEvents\n>;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type PriceDataSourceOptions = {\n messenger: PriceDataSourceMessenger;\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Currency to fetch prices in (default: 'usd') */\n currency?: SupportedCurrency;\n /** Polling interval in ms (default: 60000) */\n pollInterval?: number;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Asset reference patterns that should NOT be sent to the Price API.\n * These are internal resource tracking values without market prices.\n */\nconst NON_PRICEABLE_ASSET_PATTERNS = [\n // Tron resource assets (bandwidth, energy, staking states)\n /\\/slip44:\\d+-staked-for-/u,\n /\\/slip44:bandwidth$/u,\n /\\/slip44:energy$/u,\n /\\/slip44:maximum-bandwidth$/u,\n /\\/slip44:maximum-energy$/u,\n];\n\n/**\n * Check if an asset ID represents a priceable asset.\n * Filters out internal resource tracking values that don't have market prices.\n *\n * @param assetId - The CAIP-19 asset ID to check.\n * @returns True if the asset has market price data.\n */\nfunction isPriceableAsset(assetId: Caip19AssetId): boolean {\n return !NON_PRICEABLE_ASSET_PATTERNS.some((pattern) => pattern.test(assetId));\n}\n\n/** Market data item from spot prices response */\ntype SpotPriceMarketData = {\n price: number;\n pricePercentChange1d?: number;\n marketCap?: number;\n totalVolume?: number;\n};\n\n/**\n * Type guard to check if market data has a valid price\n *\n * @param data - The data to check.\n * @returns True if data is valid SpotPriceMarketData.\n */\nfunction isValidMarketData(data: unknown): data is SpotPriceMarketData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'price' in data &&\n typeof (data as SpotPriceMarketData).price === 'number'\n );\n}\n\nfunction transformMarketDataToAssetPrice(\n marketData: SpotPriceMarketData,\n): AssetPrice {\n return {\n price: marketData.price,\n priceChange24h: marketData.pricePercentChange1d,\n lastUpdated: Date.now(),\n // Extended market data\n marketCap: marketData.marketCap,\n volume24h: marketData.totalVolume,\n };\n}\n\n// ============================================================================\n// PRICE DATA SOURCE\n// ============================================================================\n\n/**\n * PriceDataSource fetches asset prices from the Price API.\n *\n * This data source:\n * - Fetches prices from Price API v3 spot-prices endpoint\n * - Supports one-time fetch and subscription-based polling\n * - In subscribe mode, automatically fetches prices for all assets in assetsBalance state\n * - Publishes price updates via messenger events\n *\n * Usage:\n * ```typescript\n * // Create and initialize (registers messenger actions)\n * const priceDataSource = new PriceDataSource({ messenger });\n *\n * // One-time fetch for specific assets\n * const response = await messenger.call('PriceDataSource:fetch', {\n * customAssets: ['eip155:1/erc20:0x...'],\n * });\n *\n * // Subscribe to price updates (polls all assets in balance state)\n * await messenger.call('PriceDataSource:subscribe', { request, subscriptionId });\n *\n * // Listen for updates\n * messenger.subscribe('PriceDataSource:assetsUpdated', (response) => {\n * // Handle price updates\n * });\n * ```\n */\nexport class PriceDataSource {\n readonly name = CONTROLLER_NAME;\n\n readonly #messenger: PriceDataSourceMessenger;\n\n readonly #currency: SupportedCurrency;\n\n readonly #pollInterval: number;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<\n string,\n { cleanup: () => void; request: DataRequest }\n > = new Map();\n\n constructor(options: PriceDataSourceOptions) {\n this.#messenger = options.messenger;\n this.#currency = options.currency ?? 'usd';\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#apiClient = options.queryApiClient;\n\n this.#registerActionHandlers();\n }\n\n #registerActionHandlers(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n messenger.registerActionHandler(\n 'PriceDataSource:getAssetsMiddleware',\n () => this.assetsMiddleware,\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:fetch',\n (request: DataRequest) => this.fetch(request),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:subscribe',\n (subscriptionRequest: SubscriptionRequest) =>\n this.subscribe(subscriptionRequest),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:unsubscribe',\n (subscriptionId: string) => this.unsubscribe(subscriptionId),\n );\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for enriching responses with price data.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches prices for detected assets (assets without metadata)\n * 3. Enriches the response with fetched prices\n * 4. Calls next() at the end to continue the middleware chain\n *\n * Note: This middleware ONLY fetches prices for detected assets.\n * For fetching prices for all assets, use the subscription mechanism\n * which polls prices for all assets in the balance state.\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['price'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n // Only fetch prices for detected assets (assets without metadata)\n // The subscription handles fetching prices for all existing assets\n if (!response.detectedAssets) {\n return next(ctx);\n }\n\n const detectedAssetIds = new Set<Caip19AssetId>();\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n detectedAssetIds.add(assetId);\n }\n }\n\n if (detectedAssetIds.size === 0) {\n return next(ctx);\n }\n\n // Filter to only priceable assets\n const priceableAssetIds = [...detectedAssetIds].filter(isPriceableAsset);\n\n if (priceableAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices(\n priceableAssetIds,\n true, // includeMarketData\n );\n\n response.assetsPrice ??= {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] =\n transformMarketDataToAssetPrice(marketData);\n }\n } catch (error) {\n log('Failed to fetch prices via middleware', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n\n // ============================================================================\n // HELPERS\n // ============================================================================\n\n /**\n * Fetch spot prices with caching and deduplication via query service.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @param includeMarketData - Whether to include market data\n * @returns Spot prices response\n */\n async #fetchSpotPrices(\n assetIds: string[],\n includeMarketData: boolean,\n ): Promise<V3SpotPricesResponse> {\n return this.#apiClient.prices.fetchV3SpotPrices(assetIds, {\n currency: this.#currency,\n includeMarketData,\n });\n }\n\n /**\n * Get unique asset IDs from the assetsBalance state.\n * Filters by accounts and chains from the request.\n *\n * @param request - Data request with accounts and chainIds filters.\n * @returns Array of CAIP-19 asset IDs from balance state.\n */\n #getAssetIdsFromBalanceState(request: DataRequest): Caip19AssetId[] {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n const assetIds = new Set<Caip19AssetId>();\n\n const accountIds = request.accounts.map((a) => a.id);\n const accountFilter =\n accountIds.length > 0 ? new Set(accountIds) : undefined;\n const chainFilter =\n request.chainIds.length > 0 ? new Set(request.chainIds) : undefined;\n\n if (state?.assetsBalance) {\n for (const [accountId, accountBalances] of Object.entries(\n state.assetsBalance,\n )) {\n // Filter by account if specified\n if (accountFilter && !accountFilter.has(accountId)) {\n continue;\n }\n\n for (const assetId of Object.keys(\n accountBalances as Record<string, unknown>,\n )) {\n // Filter by chain if specified\n if (chainFilter) {\n const chainId = assetId.split('/')[0] as ChainId;\n if (!chainFilter.has(chainId)) {\n continue;\n }\n }\n assetIds.add(assetId as Caip19AssetId);\n }\n }\n }\n\n return [...assetIds];\n } catch (error) {\n log('Failed to get asset IDs from balance state', { error });\n return [];\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n /**\n * Fetch prices for assets held by the accounts and chains in the request.\n * Gets asset IDs from balance state, filtered by request.accounts and request.chainIds.\n *\n * @param request - The data request specifying accounts and chains.\n * @returns DataResponse containing asset prices.\n */\n async fetch(request: DataRequest): Promise<DataResponse> {\n const response: DataResponse = {};\n\n // Get asset IDs from balance state, filtered by accounts and chains\n const rawAssetIds = this.#getAssetIdsFromBalanceState(request);\n\n // Filter out non-priceable assets (e.g., Tron bandwidth/energy resources)\n const assetIds = rawAssetIds.filter(isPriceableAsset);\n\n if (assetIds.length === 0) {\n return response;\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices(\n [...assetIds],\n true, // includeMarketData\n );\n\n response.assetsPrice = {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n // Skip assets with invalid market data (API doesn't have price for this asset)\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] =\n transformMarketDataToAssetPrice(marketData);\n }\n } catch (error) {\n log('Failed to fetch prices', { error });\n }\n\n return response;\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n /**\n * Subscribe to price updates.\n * Sets up polling that fetches prices for all assets in assetsBalance state.\n *\n * @param subscriptionRequest - The subscription request configuration.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Handle subscription update - just update the request\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function - fetches prices for all assets in balance state\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (!subscription) {\n return;\n }\n\n // Fetch prices for all assets currently in balance state\n const fetchResponse = await this.fetch(subscription.request);\n\n // Only report if we got prices\n if (\n fetchResponse.assetsPrice &&\n Object.keys(fetchResponse.assetsPrice).length > 0\n ) {\n await this.#messenger.call(\n 'AssetsController:assetsUpdate',\n fetchResponse,\n CONTROLLER_NAME,\n );\n }\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription\n this.#activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n request,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n /**\n * Unsubscribe from price updates.\n *\n * @param subscriptionId - The ID of the subscription to cancel.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n subscription.cleanup();\n this.#activeSubscriptions.delete(subscriptionId);\n }\n }\n\n /**\n * Destroy the data source and clean up all subscriptions.\n */\n destroy(): void {\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.cleanup();\n }\n this.#activeSubscriptions.clear();\n }\n}\n"]}
1
+ {"version":3,"file":"PriceDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/PriceDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n SupportedCurrency,\n V3SpotPricesResponse,\n} from '@metamask/core-backend';\nimport { ApiPlatformClient } from '@metamask/core-backend';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { SubscriptionRequest } from './AbstractDataSource';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport { forDataTypes } from '../types';\nimport type {\n Caip19AssetId,\n AssetBalance,\n AccountId,\n ChainId,\n DataRequest,\n DataResponse,\n FungibleAssetPrice,\n Middleware,\n} from '../types';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'PriceDataSource';\nconst DEFAULT_POLL_INTERVAL = 60_000; // 1 minute for price updates\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Action to get balance state (used to determine which assets need prices).\n */\ntype GetAssetsBalanceStateAction = {\n type: 'AssetsController:getState';\n handler: () => {\n assetsBalance: Record<AccountId, Record<Caip19AssetId, AssetBalance>>;\n };\n};\n\n/**\n * Action to get the PriceDataSource middleware.\n */\nexport type PriceDataSourceGetAssetsMiddlewareAction = {\n type: `${typeof CONTROLLER_NAME}:getAssetsMiddleware`;\n handler: () => Middleware;\n};\n\n/**\n * Action to fetch prices for assets.\n */\nexport type PriceDataSourceFetchAction = {\n type: `${typeof CONTROLLER_NAME}:fetch`;\n handler: (request: DataRequest) => Promise<DataResponse>;\n};\n\n/**\n * Action to subscribe to price updates.\n */\nexport type PriceDataSourceSubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:subscribe`;\n handler: (request: SubscriptionRequest) => Promise<void>;\n};\n\n/**\n * Action to unsubscribe from price updates.\n */\nexport type PriceDataSourceUnsubscribeAction = {\n type: `${typeof CONTROLLER_NAME}:unsubscribe`;\n handler: (subscriptionId: string) => Promise<void>;\n};\n\n/**\n * All actions exposed by PriceDataSource.\n */\nexport type PriceDataSourceActions =\n | PriceDataSourceGetAssetsMiddlewareAction\n | PriceDataSourceFetchAction\n | PriceDataSourceSubscribeAction\n | PriceDataSourceUnsubscribeAction;\n\n/**\n * Event emitted when prices are updated.\n */\nexport type PriceDataSourceAssetsUpdatedEvent = {\n type: `${typeof CONTROLLER_NAME}:assetsUpdated`;\n payload: [DataResponse, string];\n};\n\n/**\n * All events exposed by PriceDataSource.\n */\nexport type PriceDataSourceEvents = PriceDataSourceAssetsUpdatedEvent;\n\n// Action to report assets updated to AssetsController\ntype AssetsControllerAssetsUpdateAction = {\n type: 'AssetsController:assetsUpdate';\n handler: (response: DataResponse, sourceId: string) => Promise<void>;\n};\n\n/**\n * External actions that PriceDataSource needs to call.\n * Note: Uses ApiPlatformClient directly, so no BackendApiClient actions needed.\n */\nexport type PriceDataSourceAllowedActions =\n | GetAssetsBalanceStateAction\n | AssetsControllerAssetsUpdateAction;\n\nexport type PriceDataSourceMessenger = Messenger<\n typeof CONTROLLER_NAME,\n PriceDataSourceAllowedActions | PriceDataSourceActions,\n PriceDataSourceEvents\n>;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type PriceDataSourceOptions = {\n messenger: PriceDataSourceMessenger;\n /** ApiPlatformClient for API calls with caching */\n queryApiClient: ApiPlatformClient;\n /** Currency to fetch prices in (default: 'usd') */\n currency?: SupportedCurrency;\n /** Polling interval in ms (default: 60000) */\n pollInterval?: number;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Asset reference patterns that should NOT be sent to the Price API.\n * These are internal resource tracking values without market prices.\n */\nconst NON_PRICEABLE_ASSET_PATTERNS = [\n // Tron resource assets (bandwidth, energy, staking states)\n /\\/slip44:\\d+-staked-for-/u,\n /\\/slip44:bandwidth$/u,\n /\\/slip44:energy$/u,\n /\\/slip44:maximum-bandwidth$/u,\n /\\/slip44:maximum-energy$/u,\n];\n\n/**\n * Check if an asset ID represents a priceable asset.\n * Filters out internal resource tracking values that don't have market prices.\n *\n * @param assetId - The CAIP-19 asset ID to check.\n * @returns True if the asset has market price data.\n */\nfunction isPriceableAsset(assetId: Caip19AssetId): boolean {\n return !NON_PRICEABLE_ASSET_PATTERNS.some((pattern) => pattern.test(assetId));\n}\n\n/** Market data item from spot prices response (same as FungibleAssetPrice without lastUpdated) */\ntype SpotPriceMarketData = Omit<FungibleAssetPrice, 'lastUpdated'>;\n\n/**\n * Type guard to check if market data has a valid price\n *\n * @param data - The data to check.\n * @returns True if data is valid SpotPriceMarketData.\n */\nfunction isValidMarketData(data: unknown): data is SpotPriceMarketData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'price' in data &&\n typeof (data as SpotPriceMarketData).price === 'number'\n );\n}\n\n// ============================================================================\n// PRICE DATA SOURCE\n// ============================================================================\n\n/**\n * PriceDataSource fetches asset prices from the Price API.\n *\n * This data source:\n * - Fetches prices from Price API v3 spot-prices endpoint\n * - Supports one-time fetch and subscription-based polling\n * - In subscribe mode, automatically fetches prices for all assets in assetsBalance state\n * - Publishes price updates via messenger events\n *\n * Usage:\n * ```typescript\n * // Create and initialize (registers messenger actions)\n * const priceDataSource = new PriceDataSource({ messenger });\n *\n * // One-time fetch for specific assets\n * const response = await messenger.call('PriceDataSource:fetch', {\n * customAssets: ['eip155:1/erc20:0x...'],\n * });\n *\n * // Subscribe to price updates (polls all assets in balance state)\n * await messenger.call('PriceDataSource:subscribe', { request, subscriptionId });\n *\n * // Listen for updates\n * messenger.subscribe('PriceDataSource:assetsUpdated', (response) => {\n * // Handle price updates\n * });\n * ```\n */\nexport class PriceDataSource {\n readonly name = CONTROLLER_NAME;\n\n readonly #messenger: PriceDataSourceMessenger;\n\n readonly #currency: SupportedCurrency;\n\n readonly #pollInterval: number;\n\n /** ApiPlatformClient for cached API calls */\n readonly #apiClient: ApiPlatformClient;\n\n /** Active subscriptions by ID */\n readonly #activeSubscriptions: Map<\n string,\n { cleanup: () => void; request: DataRequest }\n > = new Map();\n\n constructor(options: PriceDataSourceOptions) {\n this.#messenger = options.messenger;\n this.#currency = options.currency ?? 'usd';\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#apiClient = options.queryApiClient;\n\n this.#registerActionHandlers();\n }\n\n #registerActionHandlers(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n messenger.registerActionHandler(\n 'PriceDataSource:getAssetsMiddleware',\n () => this.assetsMiddleware,\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:fetch',\n (request: DataRequest) => this.fetch(request),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:subscribe',\n (subscriptionRequest: SubscriptionRequest) =>\n this.subscribe(subscriptionRequest),\n );\n\n messenger.registerActionHandler(\n 'PriceDataSource:unsubscribe',\n (subscriptionId: string) => this.unsubscribe(subscriptionId),\n );\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for enriching responses with price data.\n *\n * This middleware:\n * 1. Extracts the response from context\n * 2. Fetches prices for detected assets (assets without metadata)\n * 3. Enriches the response with fetched prices\n * 4. Calls next() at the end to continue the middleware chain\n *\n * Note: This middleware ONLY fetches prices for detected assets.\n * For fetching prices for all assets, use the subscription mechanism\n * which polls prices for all assets in the balance state.\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return forDataTypes(['price'], async (ctx, next) => {\n // Extract response from context\n const { response } = ctx;\n\n // Only fetch prices for detected assets (assets without metadata)\n // The subscription handles fetching prices for all existing assets\n if (!response.detectedAssets) {\n return next(ctx);\n }\n\n const detectedAssetIds = new Set<Caip19AssetId>();\n for (const detectedIds of Object.values(response.detectedAssets)) {\n for (const assetId of detectedIds) {\n detectedAssetIds.add(assetId);\n }\n }\n\n if (detectedAssetIds.size === 0) {\n return next(ctx);\n }\n\n // Filter to only priceable assets\n const priceableAssetIds = [...detectedAssetIds].filter(isPriceableAsset);\n\n if (priceableAssetIds.length === 0) {\n return next(ctx);\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices(priceableAssetIds);\n\n response.assetsPrice ??= {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] = {\n ...marketData,\n lastUpdated: Date.now(),\n };\n }\n } catch (error) {\n log('Failed to fetch prices via middleware', { error });\n }\n\n // Call next() at the end to continue the middleware chain\n return next(ctx);\n });\n }\n\n // ============================================================================\n // HELPERS\n // ============================================================================\n\n /**\n * Fetch spot prices with caching and deduplication via query service.\n *\n * @param assetIds - Array of CAIP-19 asset IDs\n * @returns Spot prices response\n */\n async #fetchSpotPrices(assetIds: string[]): Promise<V3SpotPricesResponse> {\n return this.#apiClient.prices.fetchV3SpotPrices(assetIds, {\n currency: this.#currency,\n includeMarketData: true,\n });\n }\n\n /**\n * Get unique asset IDs from the assetsBalance state.\n * Filters by accounts and chains from the request.\n *\n * @param request - Data request with accounts and chainIds filters.\n * @returns Array of CAIP-19 asset IDs from balance state.\n */\n #getAssetIdsFromBalanceState(request: DataRequest): Caip19AssetId[] {\n try {\n const state = this.#messenger.call('AssetsController:getState');\n const assetIds = new Set<Caip19AssetId>();\n\n const accountIds = request.accounts.map((a) => a.id);\n const accountFilter =\n accountIds.length > 0 ? new Set(accountIds) : undefined;\n const chainFilter =\n request.chainIds.length > 0 ? new Set(request.chainIds) : undefined;\n\n if (state?.assetsBalance) {\n for (const [accountId, accountBalances] of Object.entries(\n state.assetsBalance,\n )) {\n // Filter by account if specified\n if (accountFilter && !accountFilter.has(accountId)) {\n continue;\n }\n\n for (const assetId of Object.keys(\n accountBalances as Record<string, unknown>,\n )) {\n // Filter by chain if specified\n if (chainFilter) {\n const chainId = assetId.split('/')[0] as ChainId;\n if (!chainFilter.has(chainId)) {\n continue;\n }\n }\n assetIds.add(assetId as Caip19AssetId);\n }\n }\n }\n\n return [...assetIds];\n } catch (error) {\n log('Failed to get asset IDs from balance state', { error });\n return [];\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n /**\n * Fetch prices for assets held by the accounts and chains in the request.\n * Gets asset IDs from balance state, filtered by request.accounts and request.chainIds.\n *\n * @param request - The data request specifying accounts and chains.\n * @returns DataResponse containing asset prices.\n */\n async fetch(request: DataRequest): Promise<DataResponse> {\n const response: DataResponse = {};\n\n // Get asset IDs from balance state, filtered by accounts and chains\n const rawAssetIds = this.#getAssetIdsFromBalanceState(request);\n\n // Filter out non-priceable assets (e.g., Tron bandwidth/energy resources)\n const assetIds = rawAssetIds.filter(isPriceableAsset);\n\n if (assetIds.length === 0) {\n return response;\n }\n\n try {\n const priceResponse = await this.#fetchSpotPrices([...assetIds]);\n\n response.assetsPrice = {};\n\n for (const [assetId, marketData] of Object.entries(priceResponse)) {\n // Skip assets with invalid market data (API doesn't have price for this asset)\n if (!isValidMarketData(marketData)) {\n continue;\n }\n\n const caipAssetId = assetId as Caip19AssetId;\n response.assetsPrice[caipAssetId] = {\n ...marketData,\n lastUpdated: Date.now(),\n };\n }\n } catch (error) {\n log('Failed to fetch prices', { error });\n }\n\n return response;\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n /**\n * Subscribe to price updates.\n * Sets up polling that fetches prices for all assets in assetsBalance state.\n *\n * @param subscriptionRequest - The subscription request configuration.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Handle subscription update - just update the request\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n existing.request = request;\n return;\n }\n }\n\n // Clean up existing subscription\n await this.unsubscribe(subscriptionId);\n\n const pollInterval = request.updateInterval ?? this.#pollInterval;\n\n // Create poll function - fetches prices for all assets in balance state\n const pollFn = async (): Promise<void> => {\n try {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (!subscription) {\n return;\n }\n\n // Fetch prices for all assets currently in balance state\n const fetchResponse = await this.fetch(subscription.request);\n\n // Only report if we got prices\n if (\n fetchResponse.assetsPrice &&\n Object.keys(fetchResponse.assetsPrice).length > 0\n ) {\n await this.#messenger.call(\n 'AssetsController:assetsUpdate',\n fetchResponse,\n CONTROLLER_NAME,\n );\n }\n } catch (error) {\n log('Subscription poll failed', { subscriptionId, error });\n }\n };\n\n // Set up polling\n const timer = setInterval(() => {\n pollFn().catch(console.error);\n }, pollInterval);\n\n // Store subscription\n this.#activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n clearInterval(timer);\n },\n request,\n });\n\n // Initial fetch\n await pollFn();\n }\n\n /**\n * Unsubscribe from price updates.\n *\n * @param subscriptionId - The ID of the subscription to cancel.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n subscription.cleanup();\n this.#activeSubscriptions.delete(subscriptionId);\n }\n }\n\n /**\n * Destroy the data source and clean up all subscriptions.\n */\n destroy(): void {\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.cleanup();\n }\n this.#activeSubscriptions.clear();\n }\n}\n"]}