@metamask-previews/assets-controller 8.3.0-preview-d9626a5a2 → 8.3.1-preview-34aa73a7b
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.
- package/CHANGELOG.md +4 -1
- package/dist/data-sources/BackendWebsocketDataSource.cjs +0 -5
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
- package/dist/data-sources/BackendWebsocketDataSource.mjs +0 -5
- package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
- package/dist/selectors/balance.cjs +0 -4
- package/dist/selectors/balance.cjs.map +1 -1
- package/dist/selectors/balance.d.cts.map +1 -1
- package/dist/selectors/balance.d.mts.map +1 -1
- package/dist/selectors/balance.mjs +0 -4
- package/dist/selectors/balance.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [8.3.1]
|
|
11
|
+
|
|
10
12
|
### Fixed
|
|
11
13
|
|
|
12
14
|
- Fix sub-`1e-7` dust balance amounts being serialized in scientific-notation form (e.g. `"1e-18"`) instead of plain decimal, which caused crashes in downstream `BigInt()`-based consumers ([#8982](https://github.com/MetaMask/core/pull/8982))
|
|
@@ -559,7 +561,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
559
561
|
- Refactor `RpcDataSource` to delegate polling to `BalanceFetcher` and `TokenDetector` services ([#7709](https://github.com/MetaMask/core/pull/7709))
|
|
560
562
|
- Refactor `BalanceFetcher` and `TokenDetector` to extend `StaticIntervalPollingControllerOnly` for independent polling management ([#7709](https://github.com/MetaMask/core/pull/7709))
|
|
561
563
|
|
|
562
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@8.3.
|
|
564
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@8.3.1...HEAD
|
|
565
|
+
[8.3.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@8.3.0...@metamask/assets-controller@8.3.1
|
|
563
566
|
[8.3.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@8.2.0...@metamask/assets-controller@8.3.0
|
|
564
567
|
[8.2.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@8.1.0...@metamask/assets-controller@8.2.0
|
|
565
568
|
[8.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@8.0.2...@metamask/assets-controller@8.1.0
|
|
@@ -476,11 +476,6 @@ async function _BackendWebsocketDataSource_initializeActiveChains() {
|
|
|
476
476
|
const rawBalanceStr = postBalance.amount.startsWith('0x')
|
|
477
477
|
? BigInt(postBalance.amount).toString()
|
|
478
478
|
: postBalance.amount;
|
|
479
|
-
// Convert to human-readable using asset decimals (match RpcDataSource / pipeline format).
|
|
480
|
-
// `.toFixed()` (no args) — not `.toString()` — because BigNumber's default
|
|
481
|
-
// `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation
|
|
482
|
-
// for sub-1e-7 values (e.g. `"1e-18"`), which downstream `BigInt()` parsers
|
|
483
|
-
// reject and crash on (MMBUGS-772).
|
|
484
479
|
const humanReadableAmount = new bignumber_js_1.default(rawBalanceStr)
|
|
485
480
|
.dividedBy(new bignumber_js_1.default(10).pow(asset.decimals))
|
|
486
481
|
.toFixed();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackendWebsocketDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BackendWebSocketServiceActions,\n BackendWebSocketServiceEvents,\n ServerNotificationMessage,\n WebSocketSubscription,\n WebSocketState,\n AccountActivityMessage,\n BalanceUpdate,\n} from '@metamask/core-backend';\nimport type { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetMetadata,\n AssetBalance,\n DataResponse,\n} from '../types';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'BackendWebsocketDataSource';\nconst CHANNEL_TYPE = 'account-activity.v1';\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that BackendWebsocketDataSource can call\nexport type BackendWebsocketDataSourceAllowedActions =\n BackendWebSocketServiceActions;\n\n// Allowed events that BackendWebsocketDataSource can subscribe to\nexport type BackendWebsocketDataSourceAllowedEvents =\n BackendWebSocketServiceEvents;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type BackendWebsocketDataSourceState = DataSourceState;\n\nconst defaultState: BackendWebsocketDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type BackendWebsocketDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** ApiPlatformClient for fetching supported networks at init (same as AccountsApiDataSource). */\n queryApiClient: ApiPlatformClient;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: Caip19AssetId) => boolean;\n state?: Partial<BackendWebsocketDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Extract namespace from a CAIP-2 chain ID.\n * E.g., \"eip155:1\" -> \"eip155\", \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\" -> \"solana\"\n *\n * @param chainId - The CAIP-2 chain ID to extract namespace from.\n * @returns The namespace portion of the chain ID.\n */\nfunction extractNamespace(chainId: ChainId): string {\n const [namespace] = chainId.split(':');\n return namespace;\n}\n\n/** Namespaces we always subscribe to for account activity (EVM + Solana). */\nconst ACCOUNT_ACTIVITY_NAMESPACES = ['eip155', 'solana'] as const;\n\n/**\n * Get unique namespaces for account-activity subscriptions.\n * Always includes eip155 and solana so we subscribe to both EVM and Solana account activity,\n * plus any additional namespaces from the requested chain IDs.\n *\n * @param chainIds - Array of CAIP-2 chain IDs (from the subscription request).\n * @returns Array of unique namespaces (at least eip155 and solana).\n */\nfunction getNamespacesForAccountActivity(chainIds: ChainId[]): string[] {\n const namespaces = new Set<string>(ACCOUNT_ACTIVITY_NAMESPACES);\n for (const chainId of chainIds) {\n namespaces.add(extractNamespace(chainId));\n }\n return Array.from(namespaces);\n}\n\n/**\n * Returns the address to use for account-activity subscription in the given namespace.\n * EIP-155 accounts use hex (0x...) address; Solana accounts use base58.\n * Returns null if this account type does not have an address in that namespace.\n *\n * @param account - Internal account (type + address).\n * @param account.type - Account type (e.g. \"eip155:eoa\", \"solana:data-account\").\n * @param account.address - Account address (hex for eip155, base58 for solana).\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @returns The address for that namespace, or null if the account does not support the namespace.\n */\nfunction getAddressForAccountActivity(\n account: { type: string; address: string },\n namespace: string,\n): string | null {\n if (namespace === 'eip155') {\n return account.type.startsWith('eip155') ? account.address : null;\n }\n if (namespace === 'solana') {\n return account.type.startsWith('solana') ? account.address : null;\n }\n // Other namespaces (e.g. from chainIds): use address if account type matches namespace\n const typePrefix = `${namespace}:`;\n return account.type.startsWith(typePrefix) ? account.address : null;\n}\n\n/**\n * Build WebSocket channel name for account activity using CAIP-10 wildcard format.\n * Uses 0 as the chain reference to subscribe to all chains in the namespace.\n * EIP-155 addresses are lowercased (hex); Solana addresses are left as-is (base58).\n *\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @param address - The account address (hex for eip155, base58 for solana).\n * @returns The WebSocket channel name.\n */\nfunction buildAccountActivityChannel(\n namespace: string,\n address: string,\n): string {\n const formatted = namespace === 'eip155' ? address.toLowerCase() : address;\n return `${CHANNEL_TYPE}.${namespace}:0:${formatted}`;\n}\n\n/**\n * Normalize API chain identifier to CAIP-2 ChainId.\n * Passes through strings already in CAIP-2 form (e.g. eip155:1, solana:5eykt...).\n * Converts bare decimals to eip155:decimal.\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdOrDecimal - Chain ID string (CAIP-2 or decimal) or decimal number.\n * @returns CAIP-2 ChainId.\n */\nfunction toChainId(chainIdOrDecimal: number | string): ChainId {\n if (typeof chainIdOrDecimal === 'string') {\n if (isCaipChainId(chainIdOrDecimal)) {\n return chainIdOrDecimal;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdOrDecimal);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(chainIdOrDecimal));\n}\n\n// Note: AccountActivityMessage and BalanceUpdate types are imported from @metamask/core-backend\n\n// ============================================================================\n// BACKEND WEBSOCKET DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for receiving real-time balance updates via WebSocket.\n *\n * This data source connects directly to BackendWebSocketService to receive\n * push notifications for account balance changes. Unlike AccountsApiDataSource\n * which polls for data, this provides instant updates.\n *\n * Uses Messenger pattern for all interactions:\n * - Calls BackendWebSocketService methods via messenger actions\n * - Exposes its own actions for AssetsController to call\n * - Publishes events for AssetsController to subscribe to\n *\n * Actions exposed:\n * - BackendWebsocketDataSource:getActiveChains\n * - BackendWebsocketDataSource:subscribe\n * - BackendWebsocketDataSource:unsubscribe\n *\n * Events published:\n * - BackendWebsocketDataSource:activeChainsUpdated\n * - BackendWebsocketDataSource:assetsUpdated\n *\n * Actions called (from BackendWebSocketService):\n * - BackendWebSocketService:subscribe\n * - BackendWebSocketService:getConnectionInfo\n * - BackendWebSocketService:findSubscriptionsByChannelPrefix\n */\nconst DEFAULT_CHAINS_REFRESH_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes\n\nexport class BackendWebsocketDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n BackendWebsocketDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #apiClient: ApiPlatformClient;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #isNativeAsset: (assetId: Caip19AssetId) => boolean;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Chains the backend API reports as supported (preserved across disconnects). */\n #supportedChains: ChainId[] = [];\n\n /** Whether the WebSocket is currently connected. Chains are only claimed when true. */\n #isConnected = false;\n\n /** WebSocket subscriptions by our internal subscription ID */\n readonly #wsSubscriptions: Map<string, WebSocketSubscription> = new Map();\n\n /** Pending subscription requests to process when WebSocket connects */\n readonly #pendingSubscriptions: Map<string, SubscriptionRequest> = new Map();\n\n /** Store original subscription requests for reconnection */\n readonly #subscriptionRequests: Map<string, SubscriptionRequest> = new Map();\n\n constructor(options: BackendWebsocketDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#apiClient = options.queryApiClient;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#isNativeAsset = options.isNativeAsset;\n\n this.#subscribeToEvents();\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only claim chains if the websocket is already connected.\n // If not connected, chains stay unclaimed so AccountsApiDataSource\n // can pick them up via polling. They'll be claimed on reconnect.\n if (this.#isConnected) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n this.#chainsRefreshTimer = setInterval(() => {\n this.#refreshActiveChains().catch(console.error);\n }, DEFAULT_CHAINS_REFRESH_INTERVAL_MS);\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only update activeChains if connected; otherwise keep them unclaimed.\n if (!this.#isConnected) {\n return;\n }\n\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n return response.fullSupport.map(toChainId);\n }\n\n #subscribeToEvents(): void {\n type ConnectionStatePayload = {\n state: WebSocketState;\n [key: string]: unknown;\n };\n // Listen for WebSocket connection state changes (event not in AssetsControllerEvents).\n (\n this.#messenger as unknown as {\n subscribe: (e: string, h: (p: ConnectionStatePayload) => void) => void;\n }\n ).subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n (connectionInfo: ConnectionStatePayload) => {\n if (connectionInfo.state === ('connected' as WebSocketState)) {\n this.#isConnected = true;\n this.#handleReconnect();\n } else if (\n connectionInfo.state === ('disconnected' as WebSocketState)\n ) {\n this.#isConnected = false;\n this.#handleDisconnect();\n }\n },\n );\n }\n\n /**\n * Sync active chains from AccountsApiDataSource.\n * When the data source invokes the onActiveChainsUpdated callback, the\n * controller processes the active chains update (no messenger call; controller already updated).\n *\n * @param chains - Updated active chain IDs from AccountsApiDataSource.\n */\n setActiveChainsFromAccountsApi(chains: ChainId[]): void {\n this.updateActiveChains(chains, () => undefined);\n }\n\n /**\n * Handle WebSocket disconnection.\n * Moves all active subscriptions to pending for re-subscription on reconnect.\n */\n #handleDisconnect(): void {\n log('WebSocket disconnected, releasing chains for fallback', {\n activeSubscriptionCount: this.activeSubscriptions.size,\n wsSubscriptionCount: this.#wsSubscriptions.size,\n chainCount: this.state.activeChains.length,\n });\n\n // Move active subscriptions to pending for re-subscription\n for (const [subscriptionId] of this.activeSubscriptions) {\n const originalRequest = this.#subscriptionRequests.get(subscriptionId);\n if (originalRequest) {\n this.#pendingSubscriptions.set(subscriptionId, {\n ...originalRequest,\n isUpdate: false,\n });\n }\n }\n\n // Clear WebSocket subscriptions (server-side already cleared)\n this.#wsSubscriptions.clear();\n\n // Clear active subscriptions (they're no longer valid)\n this.activeSubscriptions.clear();\n\n // Release chains so the chain-claiming loop assigns them to\n // AccountsApiDataSource (polling fallback) on the next #subscribeAssets.\n const previous = [...this.state.activeChains];\n if (previous.length > 0) {\n this.updateActiveChains([], (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n /**\n * Handle WebSocket reconnection.\n * Clears stale pending subscriptions and restores activeChains so the\n * chain-claiming loop re-assigns them to this data source, triggering\n * fresh subscriptions with current accounts and chains.\n */\n #handleReconnect(): void {\n log('WebSocket reconnected, reclaiming chains', {\n supportedChainCount: this.#supportedChains.length,\n pendingSubscriptionCount: this.#pendingSubscriptions.size,\n });\n\n // Discard stale pending subscriptions captured at disconnect time.\n // The chain reclaim below triggers #onActiveChainsUpdated →\n // #subscribeAssets() in AssetsController, which creates fresh\n // subscriptions with current accounts and chains. Processing the\n // stale pending entries afterwards would overwrite those with\n // outdated request data.\n this.#pendingSubscriptions.clear();\n\n if (this.#supportedChains.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(this.#supportedChains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n // ============================================================================\n // ACTIVE CHAINS\n // ============================================================================\n\n /**\n * Update active chains when AccountsApiDataSource reports new supported chains.\n *\n * @param chains - Array of supported chain IDs.\n */\n updateSupportedChains(chains: ChainId[]): void {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Filter to active chains only\n const chainsToSubscribe = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n const addresses = request.accountsWithSupportedChains.map(\n (a) => a.account.address,\n );\n\n if (addresses.length === 0) {\n return;\n }\n\n // Check WebSocket connection status\n try {\n const connectionInfo = this.#messenger.call(\n 'BackendWebSocketService:getConnectionInfo',\n );\n if (connectionInfo.state !== ('connected' as WebSocketState)) {\n // Store the subscription request to process when WebSocket connects\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n } catch {\n // Store anyway - will be processed when we can connect\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n\n // Remove from pending if it was there (we're processing it now)\n this.#pendingSubscriptions.delete(subscriptionId);\n\n // Handle subscription update\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n // Check if accounts changed - if so, we need to re-subscribe to different channels\n const existingAddresses = existing.addresses ?? [];\n const addressesChanged =\n addresses.length !== existingAddresses.length ||\n addresses.some((addr) => !existingAddresses.includes(addr));\n\n if (!addressesChanged) {\n // Only chains changed - just update chains and return\n existing.chains = chainsToSubscribe;\n return;\n }\n // Accounts changed - fall through to re-subscribe with new channels\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n // Always subscribe to eip155 and solana account activity, plus any namespaces from requested chains\n const namespaces = getNamespacesForAccountActivity(chainsToSubscribe);\n\n // Build channel names: use namespace-appropriate address per account (eip155 = hex, solana = base58)\n const channels: string[] = [];\n for (const namespace of namespaces) {\n for (const { account } of request.accountsWithSupportedChains) {\n const address = getAddressForAccountActivity(account, namespace);\n if (address) {\n channels.push(buildAccountActivityChannel(namespace, address));\n }\n }\n }\n\n try {\n // Create WebSocket subscription\n const wsSubscription = await this.#messenger.call(\n 'BackendWebSocketService:subscribe',\n {\n channels,\n channelType: CHANNEL_TYPE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleNotification(notification, subscriptionId);\n },\n },\n );\n\n // Store WebSocket subscription\n this.#wsSubscriptions.set(subscriptionId, wsSubscription);\n\n // Store in abstract class tracking\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n const wsSub = this.#wsSubscriptions.get(subscriptionId);\n if (wsSub) {\n wsSub.unsubscribe().catch((unsubErr: unknown) => {\n log('Error unsubscribing', { subscriptionId, error: unsubErr });\n });\n this.#wsSubscriptions.delete(subscriptionId);\n }\n // Also clean up the stored request\n this.#subscriptionRequests.delete(subscriptionId);\n },\n chains: chainsToSubscribe,\n addresses,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Store original request for reconnection\n this.#subscriptionRequests.set(subscriptionId, subscriptionRequest);\n } catch (error) {\n log('WebSocket subscription FAILED', {\n subscriptionId,\n error,\n chains: chainsToSubscribe,\n });\n }\n }\n\n // ============================================================================\n // NOTIFICATION HANDLING\n // ============================================================================\n\n #handleNotification(\n notification: ServerNotificationMessage,\n subscriptionId: string,\n ): void {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n const request = this.#subscriptionRequests.get(subscriptionId)?.request;\n if (!request) {\n return;\n }\n\n const activityMessage =\n notification.data as unknown as AccountActivityMessage;\n const { address, tx, updates } = activityMessage;\n\n if (!address || !tx || !updates) {\n return;\n }\n\n // Extract chain ID from transaction (CAIP-2 format, e.g., \"eip155:8453\")\n const chainId = tx.chain as ChainId;\n\n // Find matching account in request (eip155: case-insensitive hex; solana: exact base58)\n const account = request.accountsWithSupportedChains\n .map((entry) => entry.account)\n .find((a) =>\n a.address.startsWith('0x')\n ? a.address.toLowerCase() === address.toLowerCase()\n : a.address === address,\n );\n if (!account) {\n return;\n }\n const accountId = account.id;\n\n // Process all balance updates from the activity message\n const response = this.#processBalanceUpdates(updates, chainId, accountId);\n\n if (Object.keys(response).length > 0 && subscription) {\n Promise.resolve(subscription.onAssetsUpdate(response)).catch(\n console.error,\n );\n }\n } catch (error) {\n log('Error handling notification', error);\n }\n }\n\n /**\n * Process balance updates from AccountActivityMessage.\n * Each update contains asset info, post-transaction balance, and transfer details.\n *\n * @param updates - Array of balance updates from the activity message.\n * @param _chainId - The chain ID (unused but kept for context).\n * @param accountId - The account ID to process updates for.\n * @returns DataResponse containing processed balance and metadata.\n */\n #processBalanceUpdates(\n updates: BalanceUpdate[],\n _chainId: ChainId,\n accountId: string,\n ): DataResponse {\n const assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>> = {\n [accountId]: {},\n };\n const assetsMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n\n for (const update of updates) {\n const { asset, postBalance } = update;\n\n if (!asset || !postBalance) {\n continue;\n }\n\n // Asset type is in CAIP format: \"eip155:1/erc20:0x...\" or \"eip155:1/slip44:60\"\n // We can use it directly as the asset ID\n const assetId = asset.type as Caip19AssetId;\n\n // Determine token type from asset type string\n const isNative = this.#isNativeAsset(assetId);\n const tokenType = isNative ? 'native' : 'erc20';\n\n // We assume decimals are always present; skip malformed updates\n if (asset.decimals === undefined) {\n continue;\n }\n\n // Parse raw balance (hex like \"0x26f0e5\" or decimal string)\n const rawBalanceStr = postBalance.amount.startsWith('0x')\n ? BigInt(postBalance.amount).toString()\n : postBalance.amount;\n\n // Convert to human-readable using asset decimals (match RpcDataSource / pipeline format).\n // `.toFixed()` (no args) — not `.toString()` — because BigNumber's default\n // `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation\n // for sub-1e-7 values (e.g. `\"1e-18\"`), which downstream `BigInt()` parsers\n // reject and crash on (MMBUGS-772).\n const humanReadableAmount = new BigNumberJS(rawBalanceStr)\n .dividedBy(new BigNumberJS(10).pow(asset.decimals))\n .toFixed();\n\n assetsBalance[accountId][assetId] = {\n amount: humanReadableAmount,\n };\n\n assetsMetadata[assetId] = {\n type: tokenType,\n symbol: asset.unit,\n name: asset.unit, // Use unit as name (actual name may not be in the message)\n decimals: asset.decimals,\n };\n }\n\n const response: DataResponse = { updateMode: 'merge' };\n if (Object.keys(assetsBalance[accountId]).length > 0) {\n response.assetsBalance = assetsBalance;\n response.assetsInfo = assetsMetadata;\n }\n\n return response;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n this.#chainsRefreshTimer = null;\n }\n\n // Clean up WebSocket subscriptions\n // Convert to array first to avoid modifying map during iteration\n const subscriptions = [...this.#wsSubscriptions.values()];\n for (const wsSub of subscriptions) {\n try {\n // Fire and forget - don't await in destroy\n wsSub.unsubscribe().catch(() => {\n // Ignore errors during cleanup\n });\n } catch {\n // Ignore errors during cleanup\n }\n }\n this.#wsSubscriptions.clear();\n\n // Clean up base class subscriptions\n super.destroy();\n }\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Creates a BackendWebsocketDataSource instance.\n *\n * @param options - Configuration options for the data source.\n * @returns A new BackendWebsocketDataSource instance.\n */\nexport function createBackendWebsocketDataSource(\n options: BackendWebsocketDataSourceOptions,\n): BackendWebsocketDataSource {\n return new BackendWebsocketDataSource(options);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"BackendWebsocketDataSource.cjs","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BackendWebSocketServiceActions,\n BackendWebSocketServiceEvents,\n ServerNotificationMessage,\n WebSocketSubscription,\n WebSocketState,\n AccountActivityMessage,\n BalanceUpdate,\n} from '@metamask/core-backend';\nimport type { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetMetadata,\n AssetBalance,\n DataResponse,\n} from '../types';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'BackendWebsocketDataSource';\nconst CHANNEL_TYPE = 'account-activity.v1';\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that BackendWebsocketDataSource can call\nexport type BackendWebsocketDataSourceAllowedActions =\n BackendWebSocketServiceActions;\n\n// Allowed events that BackendWebsocketDataSource can subscribe to\nexport type BackendWebsocketDataSourceAllowedEvents =\n BackendWebSocketServiceEvents;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type BackendWebsocketDataSourceState = DataSourceState;\n\nconst defaultState: BackendWebsocketDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type BackendWebsocketDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** ApiPlatformClient for fetching supported networks at init (same as AccountsApiDataSource). */\n queryApiClient: ApiPlatformClient;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: Caip19AssetId) => boolean;\n state?: Partial<BackendWebsocketDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Extract namespace from a CAIP-2 chain ID.\n * E.g., \"eip155:1\" -> \"eip155\", \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\" -> \"solana\"\n *\n * @param chainId - The CAIP-2 chain ID to extract namespace from.\n * @returns The namespace portion of the chain ID.\n */\nfunction extractNamespace(chainId: ChainId): string {\n const [namespace] = chainId.split(':');\n return namespace;\n}\n\n/** Namespaces we always subscribe to for account activity (EVM + Solana). */\nconst ACCOUNT_ACTIVITY_NAMESPACES = ['eip155', 'solana'] as const;\n\n/**\n * Get unique namespaces for account-activity subscriptions.\n * Always includes eip155 and solana so we subscribe to both EVM and Solana account activity,\n * plus any additional namespaces from the requested chain IDs.\n *\n * @param chainIds - Array of CAIP-2 chain IDs (from the subscription request).\n * @returns Array of unique namespaces (at least eip155 and solana).\n */\nfunction getNamespacesForAccountActivity(chainIds: ChainId[]): string[] {\n const namespaces = new Set<string>(ACCOUNT_ACTIVITY_NAMESPACES);\n for (const chainId of chainIds) {\n namespaces.add(extractNamespace(chainId));\n }\n return Array.from(namespaces);\n}\n\n/**\n * Returns the address to use for account-activity subscription in the given namespace.\n * EIP-155 accounts use hex (0x...) address; Solana accounts use base58.\n * Returns null if this account type does not have an address in that namespace.\n *\n * @param account - Internal account (type + address).\n * @param account.type - Account type (e.g. \"eip155:eoa\", \"solana:data-account\").\n * @param account.address - Account address (hex for eip155, base58 for solana).\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @returns The address for that namespace, or null if the account does not support the namespace.\n */\nfunction getAddressForAccountActivity(\n account: { type: string; address: string },\n namespace: string,\n): string | null {\n if (namespace === 'eip155') {\n return account.type.startsWith('eip155') ? account.address : null;\n }\n if (namespace === 'solana') {\n return account.type.startsWith('solana') ? account.address : null;\n }\n // Other namespaces (e.g. from chainIds): use address if account type matches namespace\n const typePrefix = `${namespace}:`;\n return account.type.startsWith(typePrefix) ? account.address : null;\n}\n\n/**\n * Build WebSocket channel name for account activity using CAIP-10 wildcard format.\n * Uses 0 as the chain reference to subscribe to all chains in the namespace.\n * EIP-155 addresses are lowercased (hex); Solana addresses are left as-is (base58).\n *\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @param address - The account address (hex for eip155, base58 for solana).\n * @returns The WebSocket channel name.\n */\nfunction buildAccountActivityChannel(\n namespace: string,\n address: string,\n): string {\n const formatted = namespace === 'eip155' ? address.toLowerCase() : address;\n return `${CHANNEL_TYPE}.${namespace}:0:${formatted}`;\n}\n\n/**\n * Normalize API chain identifier to CAIP-2 ChainId.\n * Passes through strings already in CAIP-2 form (e.g. eip155:1, solana:5eykt...).\n * Converts bare decimals to eip155:decimal.\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdOrDecimal - Chain ID string (CAIP-2 or decimal) or decimal number.\n * @returns CAIP-2 ChainId.\n */\nfunction toChainId(chainIdOrDecimal: number | string): ChainId {\n if (typeof chainIdOrDecimal === 'string') {\n if (isCaipChainId(chainIdOrDecimal)) {\n return chainIdOrDecimal;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdOrDecimal);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(chainIdOrDecimal));\n}\n\n// Note: AccountActivityMessage and BalanceUpdate types are imported from @metamask/core-backend\n\n// ============================================================================\n// BACKEND WEBSOCKET DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for receiving real-time balance updates via WebSocket.\n *\n * This data source connects directly to BackendWebSocketService to receive\n * push notifications for account balance changes. Unlike AccountsApiDataSource\n * which polls for data, this provides instant updates.\n *\n * Uses Messenger pattern for all interactions:\n * - Calls BackendWebSocketService methods via messenger actions\n * - Exposes its own actions for AssetsController to call\n * - Publishes events for AssetsController to subscribe to\n *\n * Actions exposed:\n * - BackendWebsocketDataSource:getActiveChains\n * - BackendWebsocketDataSource:subscribe\n * - BackendWebsocketDataSource:unsubscribe\n *\n * Events published:\n * - BackendWebsocketDataSource:activeChainsUpdated\n * - BackendWebsocketDataSource:assetsUpdated\n *\n * Actions called (from BackendWebSocketService):\n * - BackendWebSocketService:subscribe\n * - BackendWebSocketService:getConnectionInfo\n * - BackendWebSocketService:findSubscriptionsByChannelPrefix\n */\nconst DEFAULT_CHAINS_REFRESH_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes\n\nexport class BackendWebsocketDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n BackendWebsocketDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #apiClient: ApiPlatformClient;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #isNativeAsset: (assetId: Caip19AssetId) => boolean;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Chains the backend API reports as supported (preserved across disconnects). */\n #supportedChains: ChainId[] = [];\n\n /** Whether the WebSocket is currently connected. Chains are only claimed when true. */\n #isConnected = false;\n\n /** WebSocket subscriptions by our internal subscription ID */\n readonly #wsSubscriptions: Map<string, WebSocketSubscription> = new Map();\n\n /** Pending subscription requests to process when WebSocket connects */\n readonly #pendingSubscriptions: Map<string, SubscriptionRequest> = new Map();\n\n /** Store original subscription requests for reconnection */\n readonly #subscriptionRequests: Map<string, SubscriptionRequest> = new Map();\n\n constructor(options: BackendWebsocketDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#apiClient = options.queryApiClient;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#isNativeAsset = options.isNativeAsset;\n\n this.#subscribeToEvents();\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only claim chains if the websocket is already connected.\n // If not connected, chains stay unclaimed so AccountsApiDataSource\n // can pick them up via polling. They'll be claimed on reconnect.\n if (this.#isConnected) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n this.#chainsRefreshTimer = setInterval(() => {\n this.#refreshActiveChains().catch(console.error);\n }, DEFAULT_CHAINS_REFRESH_INTERVAL_MS);\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only update activeChains if connected; otherwise keep them unclaimed.\n if (!this.#isConnected) {\n return;\n }\n\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n return response.fullSupport.map(toChainId);\n }\n\n #subscribeToEvents(): void {\n type ConnectionStatePayload = {\n state: WebSocketState;\n [key: string]: unknown;\n };\n // Listen for WebSocket connection state changes (event not in AssetsControllerEvents).\n (\n this.#messenger as unknown as {\n subscribe: (e: string, h: (p: ConnectionStatePayload) => void) => void;\n }\n ).subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n (connectionInfo: ConnectionStatePayload) => {\n if (connectionInfo.state === ('connected' as WebSocketState)) {\n this.#isConnected = true;\n this.#handleReconnect();\n } else if (\n connectionInfo.state === ('disconnected' as WebSocketState)\n ) {\n this.#isConnected = false;\n this.#handleDisconnect();\n }\n },\n );\n }\n\n /**\n * Sync active chains from AccountsApiDataSource.\n * When the data source invokes the onActiveChainsUpdated callback, the\n * controller processes the active chains update (no messenger call; controller already updated).\n *\n * @param chains - Updated active chain IDs from AccountsApiDataSource.\n */\n setActiveChainsFromAccountsApi(chains: ChainId[]): void {\n this.updateActiveChains(chains, () => undefined);\n }\n\n /**\n * Handle WebSocket disconnection.\n * Moves all active subscriptions to pending for re-subscription on reconnect.\n */\n #handleDisconnect(): void {\n log('WebSocket disconnected, releasing chains for fallback', {\n activeSubscriptionCount: this.activeSubscriptions.size,\n wsSubscriptionCount: this.#wsSubscriptions.size,\n chainCount: this.state.activeChains.length,\n });\n\n // Move active subscriptions to pending for re-subscription\n for (const [subscriptionId] of this.activeSubscriptions) {\n const originalRequest = this.#subscriptionRequests.get(subscriptionId);\n if (originalRequest) {\n this.#pendingSubscriptions.set(subscriptionId, {\n ...originalRequest,\n isUpdate: false,\n });\n }\n }\n\n // Clear WebSocket subscriptions (server-side already cleared)\n this.#wsSubscriptions.clear();\n\n // Clear active subscriptions (they're no longer valid)\n this.activeSubscriptions.clear();\n\n // Release chains so the chain-claiming loop assigns them to\n // AccountsApiDataSource (polling fallback) on the next #subscribeAssets.\n const previous = [...this.state.activeChains];\n if (previous.length > 0) {\n this.updateActiveChains([], (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n /**\n * Handle WebSocket reconnection.\n * Clears stale pending subscriptions and restores activeChains so the\n * chain-claiming loop re-assigns them to this data source, triggering\n * fresh subscriptions with current accounts and chains.\n */\n #handleReconnect(): void {\n log('WebSocket reconnected, reclaiming chains', {\n supportedChainCount: this.#supportedChains.length,\n pendingSubscriptionCount: this.#pendingSubscriptions.size,\n });\n\n // Discard stale pending subscriptions captured at disconnect time.\n // The chain reclaim below triggers #onActiveChainsUpdated →\n // #subscribeAssets() in AssetsController, which creates fresh\n // subscriptions with current accounts and chains. Processing the\n // stale pending entries afterwards would overwrite those with\n // outdated request data.\n this.#pendingSubscriptions.clear();\n\n if (this.#supportedChains.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(this.#supportedChains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n // ============================================================================\n // ACTIVE CHAINS\n // ============================================================================\n\n /**\n * Update active chains when AccountsApiDataSource reports new supported chains.\n *\n * @param chains - Array of supported chain IDs.\n */\n updateSupportedChains(chains: ChainId[]): void {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Filter to active chains only\n const chainsToSubscribe = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n const addresses = request.accountsWithSupportedChains.map(\n (a) => a.account.address,\n );\n\n if (addresses.length === 0) {\n return;\n }\n\n // Check WebSocket connection status\n try {\n const connectionInfo = this.#messenger.call(\n 'BackendWebSocketService:getConnectionInfo',\n );\n if (connectionInfo.state !== ('connected' as WebSocketState)) {\n // Store the subscription request to process when WebSocket connects\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n } catch {\n // Store anyway - will be processed when we can connect\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n\n // Remove from pending if it was there (we're processing it now)\n this.#pendingSubscriptions.delete(subscriptionId);\n\n // Handle subscription update\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n // Check if accounts changed - if so, we need to re-subscribe to different channels\n const existingAddresses = existing.addresses ?? [];\n const addressesChanged =\n addresses.length !== existingAddresses.length ||\n addresses.some((addr) => !existingAddresses.includes(addr));\n\n if (!addressesChanged) {\n // Only chains changed - just update chains and return\n existing.chains = chainsToSubscribe;\n return;\n }\n // Accounts changed - fall through to re-subscribe with new channels\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n // Always subscribe to eip155 and solana account activity, plus any namespaces from requested chains\n const namespaces = getNamespacesForAccountActivity(chainsToSubscribe);\n\n // Build channel names: use namespace-appropriate address per account (eip155 = hex, solana = base58)\n const channels: string[] = [];\n for (const namespace of namespaces) {\n for (const { account } of request.accountsWithSupportedChains) {\n const address = getAddressForAccountActivity(account, namespace);\n if (address) {\n channels.push(buildAccountActivityChannel(namespace, address));\n }\n }\n }\n\n try {\n // Create WebSocket subscription\n const wsSubscription = await this.#messenger.call(\n 'BackendWebSocketService:subscribe',\n {\n channels,\n channelType: CHANNEL_TYPE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleNotification(notification, subscriptionId);\n },\n },\n );\n\n // Store WebSocket subscription\n this.#wsSubscriptions.set(subscriptionId, wsSubscription);\n\n // Store in abstract class tracking\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n const wsSub = this.#wsSubscriptions.get(subscriptionId);\n if (wsSub) {\n wsSub.unsubscribe().catch((unsubErr: unknown) => {\n log('Error unsubscribing', { subscriptionId, error: unsubErr });\n });\n this.#wsSubscriptions.delete(subscriptionId);\n }\n // Also clean up the stored request\n this.#subscriptionRequests.delete(subscriptionId);\n },\n chains: chainsToSubscribe,\n addresses,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Store original request for reconnection\n this.#subscriptionRequests.set(subscriptionId, subscriptionRequest);\n } catch (error) {\n log('WebSocket subscription FAILED', {\n subscriptionId,\n error,\n chains: chainsToSubscribe,\n });\n }\n }\n\n // ============================================================================\n // NOTIFICATION HANDLING\n // ============================================================================\n\n #handleNotification(\n notification: ServerNotificationMessage,\n subscriptionId: string,\n ): void {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n const request = this.#subscriptionRequests.get(subscriptionId)?.request;\n if (!request) {\n return;\n }\n\n const activityMessage =\n notification.data as unknown as AccountActivityMessage;\n const { address, tx, updates } = activityMessage;\n\n if (!address || !tx || !updates) {\n return;\n }\n\n // Extract chain ID from transaction (CAIP-2 format, e.g., \"eip155:8453\")\n const chainId = tx.chain as ChainId;\n\n // Find matching account in request (eip155: case-insensitive hex; solana: exact base58)\n const account = request.accountsWithSupportedChains\n .map((entry) => entry.account)\n .find((a) =>\n a.address.startsWith('0x')\n ? a.address.toLowerCase() === address.toLowerCase()\n : a.address === address,\n );\n if (!account) {\n return;\n }\n const accountId = account.id;\n\n // Process all balance updates from the activity message\n const response = this.#processBalanceUpdates(updates, chainId, accountId);\n\n if (Object.keys(response).length > 0 && subscription) {\n Promise.resolve(subscription.onAssetsUpdate(response)).catch(\n console.error,\n );\n }\n } catch (error) {\n log('Error handling notification', error);\n }\n }\n\n /**\n * Process balance updates from AccountActivityMessage.\n * Each update contains asset info, post-transaction balance, and transfer details.\n *\n * @param updates - Array of balance updates from the activity message.\n * @param _chainId - The chain ID (unused but kept for context).\n * @param accountId - The account ID to process updates for.\n * @returns DataResponse containing processed balance and metadata.\n */\n #processBalanceUpdates(\n updates: BalanceUpdate[],\n _chainId: ChainId,\n accountId: string,\n ): DataResponse {\n const assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>> = {\n [accountId]: {},\n };\n const assetsMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n\n for (const update of updates) {\n const { asset, postBalance } = update;\n\n if (!asset || !postBalance) {\n continue;\n }\n\n // Asset type is in CAIP format: \"eip155:1/erc20:0x...\" or \"eip155:1/slip44:60\"\n // We can use it directly as the asset ID\n const assetId = asset.type as Caip19AssetId;\n\n // Determine token type from asset type string\n const isNative = this.#isNativeAsset(assetId);\n const tokenType = isNative ? 'native' : 'erc20';\n\n // We assume decimals are always present; skip malformed updates\n if (asset.decimals === undefined) {\n continue;\n }\n\n // Parse raw balance (hex like \"0x26f0e5\" or decimal string)\n const rawBalanceStr = postBalance.amount.startsWith('0x')\n ? BigInt(postBalance.amount).toString()\n : postBalance.amount;\n\n const humanReadableAmount = new BigNumberJS(rawBalanceStr)\n .dividedBy(new BigNumberJS(10).pow(asset.decimals))\n .toFixed();\n\n assetsBalance[accountId][assetId] = {\n amount: humanReadableAmount,\n };\n\n assetsMetadata[assetId] = {\n type: tokenType,\n symbol: asset.unit,\n name: asset.unit, // Use unit as name (actual name may not be in the message)\n decimals: asset.decimals,\n };\n }\n\n const response: DataResponse = { updateMode: 'merge' };\n if (Object.keys(assetsBalance[accountId]).length > 0) {\n response.assetsBalance = assetsBalance;\n response.assetsInfo = assetsMetadata;\n }\n\n return response;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n this.#chainsRefreshTimer = null;\n }\n\n // Clean up WebSocket subscriptions\n // Convert to array first to avoid modifying map during iteration\n const subscriptions = [...this.#wsSubscriptions.values()];\n for (const wsSub of subscriptions) {\n try {\n // Fire and forget - don't await in destroy\n wsSub.unsubscribe().catch(() => {\n // Ignore errors during cleanup\n });\n } catch {\n // Ignore errors during cleanup\n }\n }\n this.#wsSubscriptions.clear();\n\n // Clean up base class subscriptions\n super.destroy();\n }\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Creates a BackendWebsocketDataSource instance.\n *\n * @param options - Configuration options for the data source.\n * @returns A new BackendWebsocketDataSource instance.\n */\nexport function createBackendWebsocketDataSource(\n options: BackendWebsocketDataSourceOptions,\n): BackendWebsocketDataSource {\n return new BackendWebsocketDataSource(options);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackendWebsocketDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;AAqIF,qBAAa,0BAA2B,SAAQ,kBAAkB,CAChE,OAAO,eAAe,EACtB,+BAA+B,CAChC;;gBA+Ba,OAAO,EAAE,iCAAiC;IAsGtD;;;;;;OAMG;IACH,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IA0EvD;;;;OAIG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IAWxC,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"BackendWebsocketDataSource.d.cts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;AAqIF,qBAAa,0BAA2B,SAAQ,kBAAkB,CAChE,OAAO,eAAe,EACtB,+BAA+B,CAChC;;gBA+Ba,OAAO,EAAE,iCAAiC;IAsGtD;;;;;;OAMG;IACH,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IA0EvD;;;;OAIG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IAWxC,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiPxE,OAAO,IAAI,IAAI;CAwBhB;AAMD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,0BAA0B,CAE5B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackendWebsocketDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;AAqIF,qBAAa,0BAA2B,SAAQ,kBAAkB,CAChE,OAAO,eAAe,EACtB,+BAA+B,CAChC;;gBA+Ba,OAAO,EAAE,iCAAiC;IAsGtD;;;;;;OAMG;IACH,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IA0EvD;;;;OAIG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IAWxC,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"BackendWebsocketDataSource.d.mts","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,6BAA6B,EAM9B,+BAA+B;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,+BAA+B;AAQhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,gCAA4B;AAErE,OAAO,KAAK,EACV,OAAO,EACP,aAAa,EAId,qBAAiB;AAClB,OAAO,EAAE,kBAAkB,EAAE,iCAA6B;AAC1D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACpB,iCAA6B;AAM9B,QAAA,MAAM,eAAe,+BAA+B,CAAC;AAUrD,MAAM,MAAM,wCAAwC,GAClD,8BAA8B,CAAC;AAGjC,MAAM,MAAM,uCAAuC,GACjD,6BAA6B,CAAC;AAMhC,MAAM,MAAM,+BAA+B,GAAG,eAAe,CAAC;AAU9D,MAAM,MAAM,iCAAiC,GAAG;IAC9C,mEAAmE;IACnE,SAAS,EAAE,yBAAyB,CAAC;IACrC,iGAAiG;IACjG,cAAc,EAAE,iBAAiB,CAAC;IAClC,qGAAqG;IACrG,qBAAqB,EAAE,CACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EAAE,EACjB,cAAc,EAAE,OAAO,EAAE,KACtB,IAAI,CAAC;IACV,uEAAuE;IACvE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;CAClD,CAAC;AAqIF,qBAAa,0BAA2B,SAAQ,kBAAkB,CAChE,OAAO,eAAe,EACtB,+BAA+B,CAChC;;gBA+Ba,OAAO,EAAE,iCAAiC;IAsGtD;;;;;;OAMG;IACH,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IA0EvD;;;;OAIG;IACH,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI;IAWxC,SAAS,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiPxE,OAAO,IAAI,IAAI;CAwBhB;AAMD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,0BAA0B,CAE5B"}
|
|
@@ -469,11 +469,6 @@ async function _BackendWebsocketDataSource_initializeActiveChains() {
|
|
|
469
469
|
const rawBalanceStr = postBalance.amount.startsWith('0x')
|
|
470
470
|
? BigInt(postBalance.amount).toString()
|
|
471
471
|
: postBalance.amount;
|
|
472
|
-
// Convert to human-readable using asset decimals (match RpcDataSource / pipeline format).
|
|
473
|
-
// `.toFixed()` (no args) — not `.toString()` — because BigNumber's default
|
|
474
|
-
// `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation
|
|
475
|
-
// for sub-1e-7 values (e.g. `"1e-18"`), which downstream `BigInt()` parsers
|
|
476
|
-
// reject and crash on (MMBUGS-772).
|
|
477
472
|
const humanReadableAmount = new BigNumberJS(rawBalanceStr)
|
|
478
473
|
.dividedBy(new BigNumberJS(10).pow(asset.decimals))
|
|
479
474
|
.toFixed();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackendWebsocketDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BackendWebSocketServiceActions,\n BackendWebSocketServiceEvents,\n ServerNotificationMessage,\n WebSocketSubscription,\n WebSocketState,\n AccountActivityMessage,\n BalanceUpdate,\n} from '@metamask/core-backend';\nimport type { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetMetadata,\n AssetBalance,\n DataResponse,\n} from '../types';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'BackendWebsocketDataSource';\nconst CHANNEL_TYPE = 'account-activity.v1';\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that BackendWebsocketDataSource can call\nexport type BackendWebsocketDataSourceAllowedActions =\n BackendWebSocketServiceActions;\n\n// Allowed events that BackendWebsocketDataSource can subscribe to\nexport type BackendWebsocketDataSourceAllowedEvents =\n BackendWebSocketServiceEvents;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type BackendWebsocketDataSourceState = DataSourceState;\n\nconst defaultState: BackendWebsocketDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type BackendWebsocketDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** ApiPlatformClient for fetching supported networks at init (same as AccountsApiDataSource). */\n queryApiClient: ApiPlatformClient;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: Caip19AssetId) => boolean;\n state?: Partial<BackendWebsocketDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Extract namespace from a CAIP-2 chain ID.\n * E.g., \"eip155:1\" -> \"eip155\", \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\" -> \"solana\"\n *\n * @param chainId - The CAIP-2 chain ID to extract namespace from.\n * @returns The namespace portion of the chain ID.\n */\nfunction extractNamespace(chainId: ChainId): string {\n const [namespace] = chainId.split(':');\n return namespace;\n}\n\n/** Namespaces we always subscribe to for account activity (EVM + Solana). */\nconst ACCOUNT_ACTIVITY_NAMESPACES = ['eip155', 'solana'] as const;\n\n/**\n * Get unique namespaces for account-activity subscriptions.\n * Always includes eip155 and solana so we subscribe to both EVM and Solana account activity,\n * plus any additional namespaces from the requested chain IDs.\n *\n * @param chainIds - Array of CAIP-2 chain IDs (from the subscription request).\n * @returns Array of unique namespaces (at least eip155 and solana).\n */\nfunction getNamespacesForAccountActivity(chainIds: ChainId[]): string[] {\n const namespaces = new Set<string>(ACCOUNT_ACTIVITY_NAMESPACES);\n for (const chainId of chainIds) {\n namespaces.add(extractNamespace(chainId));\n }\n return Array.from(namespaces);\n}\n\n/**\n * Returns the address to use for account-activity subscription in the given namespace.\n * EIP-155 accounts use hex (0x...) address; Solana accounts use base58.\n * Returns null if this account type does not have an address in that namespace.\n *\n * @param account - Internal account (type + address).\n * @param account.type - Account type (e.g. \"eip155:eoa\", \"solana:data-account\").\n * @param account.address - Account address (hex for eip155, base58 for solana).\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @returns The address for that namespace, or null if the account does not support the namespace.\n */\nfunction getAddressForAccountActivity(\n account: { type: string; address: string },\n namespace: string,\n): string | null {\n if (namespace === 'eip155') {\n return account.type.startsWith('eip155') ? account.address : null;\n }\n if (namespace === 'solana') {\n return account.type.startsWith('solana') ? account.address : null;\n }\n // Other namespaces (e.g. from chainIds): use address if account type matches namespace\n const typePrefix = `${namespace}:`;\n return account.type.startsWith(typePrefix) ? account.address : null;\n}\n\n/**\n * Build WebSocket channel name for account activity using CAIP-10 wildcard format.\n * Uses 0 as the chain reference to subscribe to all chains in the namespace.\n * EIP-155 addresses are lowercased (hex); Solana addresses are left as-is (base58).\n *\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @param address - The account address (hex for eip155, base58 for solana).\n * @returns The WebSocket channel name.\n */\nfunction buildAccountActivityChannel(\n namespace: string,\n address: string,\n): string {\n const formatted = namespace === 'eip155' ? address.toLowerCase() : address;\n return `${CHANNEL_TYPE}.${namespace}:0:${formatted}`;\n}\n\n/**\n * Normalize API chain identifier to CAIP-2 ChainId.\n * Passes through strings already in CAIP-2 form (e.g. eip155:1, solana:5eykt...).\n * Converts bare decimals to eip155:decimal.\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdOrDecimal - Chain ID string (CAIP-2 or decimal) or decimal number.\n * @returns CAIP-2 ChainId.\n */\nfunction toChainId(chainIdOrDecimal: number | string): ChainId {\n if (typeof chainIdOrDecimal === 'string') {\n if (isCaipChainId(chainIdOrDecimal)) {\n return chainIdOrDecimal;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdOrDecimal);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(chainIdOrDecimal));\n}\n\n// Note: AccountActivityMessage and BalanceUpdate types are imported from @metamask/core-backend\n\n// ============================================================================\n// BACKEND WEBSOCKET DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for receiving real-time balance updates via WebSocket.\n *\n * This data source connects directly to BackendWebSocketService to receive\n * push notifications for account balance changes. Unlike AccountsApiDataSource\n * which polls for data, this provides instant updates.\n *\n * Uses Messenger pattern for all interactions:\n * - Calls BackendWebSocketService methods via messenger actions\n * - Exposes its own actions for AssetsController to call\n * - Publishes events for AssetsController to subscribe to\n *\n * Actions exposed:\n * - BackendWebsocketDataSource:getActiveChains\n * - BackendWebsocketDataSource:subscribe\n * - BackendWebsocketDataSource:unsubscribe\n *\n * Events published:\n * - BackendWebsocketDataSource:activeChainsUpdated\n * - BackendWebsocketDataSource:assetsUpdated\n *\n * Actions called (from BackendWebSocketService):\n * - BackendWebSocketService:subscribe\n * - BackendWebSocketService:getConnectionInfo\n * - BackendWebSocketService:findSubscriptionsByChannelPrefix\n */\nconst DEFAULT_CHAINS_REFRESH_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes\n\nexport class BackendWebsocketDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n BackendWebsocketDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #apiClient: ApiPlatformClient;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #isNativeAsset: (assetId: Caip19AssetId) => boolean;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Chains the backend API reports as supported (preserved across disconnects). */\n #supportedChains: ChainId[] = [];\n\n /** Whether the WebSocket is currently connected. Chains are only claimed when true. */\n #isConnected = false;\n\n /** WebSocket subscriptions by our internal subscription ID */\n readonly #wsSubscriptions: Map<string, WebSocketSubscription> = new Map();\n\n /** Pending subscription requests to process when WebSocket connects */\n readonly #pendingSubscriptions: Map<string, SubscriptionRequest> = new Map();\n\n /** Store original subscription requests for reconnection */\n readonly #subscriptionRequests: Map<string, SubscriptionRequest> = new Map();\n\n constructor(options: BackendWebsocketDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#apiClient = options.queryApiClient;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#isNativeAsset = options.isNativeAsset;\n\n this.#subscribeToEvents();\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only claim chains if the websocket is already connected.\n // If not connected, chains stay unclaimed so AccountsApiDataSource\n // can pick them up via polling. They'll be claimed on reconnect.\n if (this.#isConnected) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n this.#chainsRefreshTimer = setInterval(() => {\n this.#refreshActiveChains().catch(console.error);\n }, DEFAULT_CHAINS_REFRESH_INTERVAL_MS);\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only update activeChains if connected; otherwise keep them unclaimed.\n if (!this.#isConnected) {\n return;\n }\n\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n return response.fullSupport.map(toChainId);\n }\n\n #subscribeToEvents(): void {\n type ConnectionStatePayload = {\n state: WebSocketState;\n [key: string]: unknown;\n };\n // Listen for WebSocket connection state changes (event not in AssetsControllerEvents).\n (\n this.#messenger as unknown as {\n subscribe: (e: string, h: (p: ConnectionStatePayload) => void) => void;\n }\n ).subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n (connectionInfo: ConnectionStatePayload) => {\n if (connectionInfo.state === ('connected' as WebSocketState)) {\n this.#isConnected = true;\n this.#handleReconnect();\n } else if (\n connectionInfo.state === ('disconnected' as WebSocketState)\n ) {\n this.#isConnected = false;\n this.#handleDisconnect();\n }\n },\n );\n }\n\n /**\n * Sync active chains from AccountsApiDataSource.\n * When the data source invokes the onActiveChainsUpdated callback, the\n * controller processes the active chains update (no messenger call; controller already updated).\n *\n * @param chains - Updated active chain IDs from AccountsApiDataSource.\n */\n setActiveChainsFromAccountsApi(chains: ChainId[]): void {\n this.updateActiveChains(chains, () => undefined);\n }\n\n /**\n * Handle WebSocket disconnection.\n * Moves all active subscriptions to pending for re-subscription on reconnect.\n */\n #handleDisconnect(): void {\n log('WebSocket disconnected, releasing chains for fallback', {\n activeSubscriptionCount: this.activeSubscriptions.size,\n wsSubscriptionCount: this.#wsSubscriptions.size,\n chainCount: this.state.activeChains.length,\n });\n\n // Move active subscriptions to pending for re-subscription\n for (const [subscriptionId] of this.activeSubscriptions) {\n const originalRequest = this.#subscriptionRequests.get(subscriptionId);\n if (originalRequest) {\n this.#pendingSubscriptions.set(subscriptionId, {\n ...originalRequest,\n isUpdate: false,\n });\n }\n }\n\n // Clear WebSocket subscriptions (server-side already cleared)\n this.#wsSubscriptions.clear();\n\n // Clear active subscriptions (they're no longer valid)\n this.activeSubscriptions.clear();\n\n // Release chains so the chain-claiming loop assigns them to\n // AccountsApiDataSource (polling fallback) on the next #subscribeAssets.\n const previous = [...this.state.activeChains];\n if (previous.length > 0) {\n this.updateActiveChains([], (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n /**\n * Handle WebSocket reconnection.\n * Clears stale pending subscriptions and restores activeChains so the\n * chain-claiming loop re-assigns them to this data source, triggering\n * fresh subscriptions with current accounts and chains.\n */\n #handleReconnect(): void {\n log('WebSocket reconnected, reclaiming chains', {\n supportedChainCount: this.#supportedChains.length,\n pendingSubscriptionCount: this.#pendingSubscriptions.size,\n });\n\n // Discard stale pending subscriptions captured at disconnect time.\n // The chain reclaim below triggers #onActiveChainsUpdated →\n // #subscribeAssets() in AssetsController, which creates fresh\n // subscriptions with current accounts and chains. Processing the\n // stale pending entries afterwards would overwrite those with\n // outdated request data.\n this.#pendingSubscriptions.clear();\n\n if (this.#supportedChains.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(this.#supportedChains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n // ============================================================================\n // ACTIVE CHAINS\n // ============================================================================\n\n /**\n * Update active chains when AccountsApiDataSource reports new supported chains.\n *\n * @param chains - Array of supported chain IDs.\n */\n updateSupportedChains(chains: ChainId[]): void {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Filter to active chains only\n const chainsToSubscribe = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n const addresses = request.accountsWithSupportedChains.map(\n (a) => a.account.address,\n );\n\n if (addresses.length === 0) {\n return;\n }\n\n // Check WebSocket connection status\n try {\n const connectionInfo = this.#messenger.call(\n 'BackendWebSocketService:getConnectionInfo',\n );\n if (connectionInfo.state !== ('connected' as WebSocketState)) {\n // Store the subscription request to process when WebSocket connects\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n } catch {\n // Store anyway - will be processed when we can connect\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n\n // Remove from pending if it was there (we're processing it now)\n this.#pendingSubscriptions.delete(subscriptionId);\n\n // Handle subscription update\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n // Check if accounts changed - if so, we need to re-subscribe to different channels\n const existingAddresses = existing.addresses ?? [];\n const addressesChanged =\n addresses.length !== existingAddresses.length ||\n addresses.some((addr) => !existingAddresses.includes(addr));\n\n if (!addressesChanged) {\n // Only chains changed - just update chains and return\n existing.chains = chainsToSubscribe;\n return;\n }\n // Accounts changed - fall through to re-subscribe with new channels\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n // Always subscribe to eip155 and solana account activity, plus any namespaces from requested chains\n const namespaces = getNamespacesForAccountActivity(chainsToSubscribe);\n\n // Build channel names: use namespace-appropriate address per account (eip155 = hex, solana = base58)\n const channels: string[] = [];\n for (const namespace of namespaces) {\n for (const { account } of request.accountsWithSupportedChains) {\n const address = getAddressForAccountActivity(account, namespace);\n if (address) {\n channels.push(buildAccountActivityChannel(namespace, address));\n }\n }\n }\n\n try {\n // Create WebSocket subscription\n const wsSubscription = await this.#messenger.call(\n 'BackendWebSocketService:subscribe',\n {\n channels,\n channelType: CHANNEL_TYPE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleNotification(notification, subscriptionId);\n },\n },\n );\n\n // Store WebSocket subscription\n this.#wsSubscriptions.set(subscriptionId, wsSubscription);\n\n // Store in abstract class tracking\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n const wsSub = this.#wsSubscriptions.get(subscriptionId);\n if (wsSub) {\n wsSub.unsubscribe().catch((unsubErr: unknown) => {\n log('Error unsubscribing', { subscriptionId, error: unsubErr });\n });\n this.#wsSubscriptions.delete(subscriptionId);\n }\n // Also clean up the stored request\n this.#subscriptionRequests.delete(subscriptionId);\n },\n chains: chainsToSubscribe,\n addresses,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Store original request for reconnection\n this.#subscriptionRequests.set(subscriptionId, subscriptionRequest);\n } catch (error) {\n log('WebSocket subscription FAILED', {\n subscriptionId,\n error,\n chains: chainsToSubscribe,\n });\n }\n }\n\n // ============================================================================\n // NOTIFICATION HANDLING\n // ============================================================================\n\n #handleNotification(\n notification: ServerNotificationMessage,\n subscriptionId: string,\n ): void {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n const request = this.#subscriptionRequests.get(subscriptionId)?.request;\n if (!request) {\n return;\n }\n\n const activityMessage =\n notification.data as unknown as AccountActivityMessage;\n const { address, tx, updates } = activityMessage;\n\n if (!address || !tx || !updates) {\n return;\n }\n\n // Extract chain ID from transaction (CAIP-2 format, e.g., \"eip155:8453\")\n const chainId = tx.chain as ChainId;\n\n // Find matching account in request (eip155: case-insensitive hex; solana: exact base58)\n const account = request.accountsWithSupportedChains\n .map((entry) => entry.account)\n .find((a) =>\n a.address.startsWith('0x')\n ? a.address.toLowerCase() === address.toLowerCase()\n : a.address === address,\n );\n if (!account) {\n return;\n }\n const accountId = account.id;\n\n // Process all balance updates from the activity message\n const response = this.#processBalanceUpdates(updates, chainId, accountId);\n\n if (Object.keys(response).length > 0 && subscription) {\n Promise.resolve(subscription.onAssetsUpdate(response)).catch(\n console.error,\n );\n }\n } catch (error) {\n log('Error handling notification', error);\n }\n }\n\n /**\n * Process balance updates from AccountActivityMessage.\n * Each update contains asset info, post-transaction balance, and transfer details.\n *\n * @param updates - Array of balance updates from the activity message.\n * @param _chainId - The chain ID (unused but kept for context).\n * @param accountId - The account ID to process updates for.\n * @returns DataResponse containing processed balance and metadata.\n */\n #processBalanceUpdates(\n updates: BalanceUpdate[],\n _chainId: ChainId,\n accountId: string,\n ): DataResponse {\n const assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>> = {\n [accountId]: {},\n };\n const assetsMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n\n for (const update of updates) {\n const { asset, postBalance } = update;\n\n if (!asset || !postBalance) {\n continue;\n }\n\n // Asset type is in CAIP format: \"eip155:1/erc20:0x...\" or \"eip155:1/slip44:60\"\n // We can use it directly as the asset ID\n const assetId = asset.type as Caip19AssetId;\n\n // Determine token type from asset type string\n const isNative = this.#isNativeAsset(assetId);\n const tokenType = isNative ? 'native' : 'erc20';\n\n // We assume decimals are always present; skip malformed updates\n if (asset.decimals === undefined) {\n continue;\n }\n\n // Parse raw balance (hex like \"0x26f0e5\" or decimal string)\n const rawBalanceStr = postBalance.amount.startsWith('0x')\n ? BigInt(postBalance.amount).toString()\n : postBalance.amount;\n\n // Convert to human-readable using asset decimals (match RpcDataSource / pipeline format).\n // `.toFixed()` (no args) — not `.toString()` — because BigNumber's default\n // `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation\n // for sub-1e-7 values (e.g. `\"1e-18\"`), which downstream `BigInt()` parsers\n // reject and crash on (MMBUGS-772).\n const humanReadableAmount = new BigNumberJS(rawBalanceStr)\n .dividedBy(new BigNumberJS(10).pow(asset.decimals))\n .toFixed();\n\n assetsBalance[accountId][assetId] = {\n amount: humanReadableAmount,\n };\n\n assetsMetadata[assetId] = {\n type: tokenType,\n symbol: asset.unit,\n name: asset.unit, // Use unit as name (actual name may not be in the message)\n decimals: asset.decimals,\n };\n }\n\n const response: DataResponse = { updateMode: 'merge' };\n if (Object.keys(assetsBalance[accountId]).length > 0) {\n response.assetsBalance = assetsBalance;\n response.assetsInfo = assetsMetadata;\n }\n\n return response;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n this.#chainsRefreshTimer = null;\n }\n\n // Clean up WebSocket subscriptions\n // Convert to array first to avoid modifying map during iteration\n const subscriptions = [...this.#wsSubscriptions.values()];\n for (const wsSub of subscriptions) {\n try {\n // Fire and forget - don't await in destroy\n wsSub.unsubscribe().catch(() => {\n // Ignore errors during cleanup\n });\n } catch {\n // Ignore errors during cleanup\n }\n }\n this.#wsSubscriptions.clear();\n\n // Clean up base class subscriptions\n super.destroy();\n }\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Creates a BackendWebsocketDataSource instance.\n *\n * @param options - Configuration options for the data source.\n * @returns A new BackendWebsocketDataSource instance.\n */\nexport function createBackendWebsocketDataSource(\n options: BackendWebsocketDataSourceOptions,\n): BackendWebsocketDataSource {\n return new BackendWebsocketDataSource(options);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"BackendWebsocketDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/BackendWebsocketDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n BackendWebSocketServiceActions,\n BackendWebSocketServiceEvents,\n ServerNotificationMessage,\n WebSocketSubscription,\n WebSocketState,\n AccountActivityMessage,\n BalanceUpdate,\n} from '@metamask/core-backend';\nimport type { ApiPlatformClient } from '@metamask/core-backend';\nimport {\n isCaipChainId,\n KnownCaipNamespace,\n toCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n ChainId,\n Caip19AssetId,\n AssetMetadata,\n AssetBalance,\n DataResponse,\n} from '../types';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nconst CONTROLLER_NAME = 'BackendWebsocketDataSource';\nconst CHANNEL_TYPE = 'account-activity.v1';\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n// Allowed actions that BackendWebsocketDataSource can call\nexport type BackendWebsocketDataSourceAllowedActions =\n BackendWebSocketServiceActions;\n\n// Allowed events that BackendWebsocketDataSource can subscribe to\nexport type BackendWebsocketDataSourceAllowedEvents =\n BackendWebSocketServiceEvents;\n\n// ============================================================================\n// STATE\n// ============================================================================\n\nexport type BackendWebsocketDataSourceState = DataSourceState;\n\nconst defaultState: BackendWebsocketDataSourceState = {\n activeChains: [],\n};\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type BackendWebsocketDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** ApiPlatformClient for fetching supported networks at init (same as AccountsApiDataSource). */\n queryApiClient: ApiPlatformClient;\n /** Called when active chains are updated. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /** Determines whether a CAIP-19 asset ID represents a native asset. */\n isNativeAsset: (assetId: Caip19AssetId) => boolean;\n state?: Partial<BackendWebsocketDataSourceState>;\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Extract namespace from a CAIP-2 chain ID.\n * E.g., \"eip155:1\" -> \"eip155\", \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\" -> \"solana\"\n *\n * @param chainId - The CAIP-2 chain ID to extract namespace from.\n * @returns The namespace portion of the chain ID.\n */\nfunction extractNamespace(chainId: ChainId): string {\n const [namespace] = chainId.split(':');\n return namespace;\n}\n\n/** Namespaces we always subscribe to for account activity (EVM + Solana). */\nconst ACCOUNT_ACTIVITY_NAMESPACES = ['eip155', 'solana'] as const;\n\n/**\n * Get unique namespaces for account-activity subscriptions.\n * Always includes eip155 and solana so we subscribe to both EVM and Solana account activity,\n * plus any additional namespaces from the requested chain IDs.\n *\n * @param chainIds - Array of CAIP-2 chain IDs (from the subscription request).\n * @returns Array of unique namespaces (at least eip155 and solana).\n */\nfunction getNamespacesForAccountActivity(chainIds: ChainId[]): string[] {\n const namespaces = new Set<string>(ACCOUNT_ACTIVITY_NAMESPACES);\n for (const chainId of chainIds) {\n namespaces.add(extractNamespace(chainId));\n }\n return Array.from(namespaces);\n}\n\n/**\n * Returns the address to use for account-activity subscription in the given namespace.\n * EIP-155 accounts use hex (0x...) address; Solana accounts use base58.\n * Returns null if this account type does not have an address in that namespace.\n *\n * @param account - Internal account (type + address).\n * @param account.type - Account type (e.g. \"eip155:eoa\", \"solana:data-account\").\n * @param account.address - Account address (hex for eip155, base58 for solana).\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @returns The address for that namespace, or null if the account does not support the namespace.\n */\nfunction getAddressForAccountActivity(\n account: { type: string; address: string },\n namespace: string,\n): string | null {\n if (namespace === 'eip155') {\n return account.type.startsWith('eip155') ? account.address : null;\n }\n if (namespace === 'solana') {\n return account.type.startsWith('solana') ? account.address : null;\n }\n // Other namespaces (e.g. from chainIds): use address if account type matches namespace\n const typePrefix = `${namespace}:`;\n return account.type.startsWith(typePrefix) ? account.address : null;\n}\n\n/**\n * Build WebSocket channel name for account activity using CAIP-10 wildcard format.\n * Uses 0 as the chain reference to subscribe to all chains in the namespace.\n * EIP-155 addresses are lowercased (hex); Solana addresses are left as-is (base58).\n *\n * @param namespace - The chain namespace (e.g., \"eip155\", \"solana\").\n * @param address - The account address (hex for eip155, base58 for solana).\n * @returns The WebSocket channel name.\n */\nfunction buildAccountActivityChannel(\n namespace: string,\n address: string,\n): string {\n const formatted = namespace === 'eip155' ? address.toLowerCase() : address;\n return `${CHANNEL_TYPE}.${namespace}:0:${formatted}`;\n}\n\n/**\n * Normalize API chain identifier to CAIP-2 ChainId.\n * Passes through strings already in CAIP-2 form (e.g. eip155:1, solana:5eykt...).\n * Converts bare decimals to eip155:decimal.\n * Uses @metamask/utils for CAIP parsing.\n *\n * @param chainIdOrDecimal - Chain ID string (CAIP-2 or decimal) or decimal number.\n * @returns CAIP-2 ChainId.\n */\nfunction toChainId(chainIdOrDecimal: number | string): ChainId {\n if (typeof chainIdOrDecimal === 'string') {\n if (isCaipChainId(chainIdOrDecimal)) {\n return chainIdOrDecimal;\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, chainIdOrDecimal);\n }\n return toCaipChainId(KnownCaipNamespace.Eip155, String(chainIdOrDecimal));\n}\n\n// Note: AccountActivityMessage and BalanceUpdate types are imported from @metamask/core-backend\n\n// ============================================================================\n// BACKEND WEBSOCKET DATA SOURCE\n// ============================================================================\n\n/**\n * Data source for receiving real-time balance updates via WebSocket.\n *\n * This data source connects directly to BackendWebSocketService to receive\n * push notifications for account balance changes. Unlike AccountsApiDataSource\n * which polls for data, this provides instant updates.\n *\n * Uses Messenger pattern for all interactions:\n * - Calls BackendWebSocketService methods via messenger actions\n * - Exposes its own actions for AssetsController to call\n * - Publishes events for AssetsController to subscribe to\n *\n * Actions exposed:\n * - BackendWebsocketDataSource:getActiveChains\n * - BackendWebsocketDataSource:subscribe\n * - BackendWebsocketDataSource:unsubscribe\n *\n * Events published:\n * - BackendWebsocketDataSource:activeChainsUpdated\n * - BackendWebsocketDataSource:assetsUpdated\n *\n * Actions called (from BackendWebSocketService):\n * - BackendWebSocketService:subscribe\n * - BackendWebSocketService:getConnectionInfo\n * - BackendWebSocketService:findSubscriptionsByChannelPrefix\n */\nconst DEFAULT_CHAINS_REFRESH_INTERVAL_MS = 20 * 60 * 1000; // 20 minutes\n\nexport class BackendWebsocketDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n BackendWebsocketDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #apiClient: ApiPlatformClient;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #isNativeAsset: (assetId: Caip19AssetId) => boolean;\n\n /** Chains refresh timer */\n #chainsRefreshTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Chains the backend API reports as supported (preserved across disconnects). */\n #supportedChains: ChainId[] = [];\n\n /** Whether the WebSocket is currently connected. Chains are only claimed when true. */\n #isConnected = false;\n\n /** WebSocket subscriptions by our internal subscription ID */\n readonly #wsSubscriptions: Map<string, WebSocketSubscription> = new Map();\n\n /** Pending subscription requests to process when WebSocket connects */\n readonly #pendingSubscriptions: Map<string, SubscriptionRequest> = new Map();\n\n /** Store original subscription requests for reconnection */\n readonly #subscriptionRequests: Map<string, SubscriptionRequest> = new Map();\n\n constructor(options: BackendWebsocketDataSourceOptions) {\n super(CONTROLLER_NAME, {\n ...defaultState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#apiClient = options.queryApiClient;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#isNativeAsset = options.isNativeAsset;\n\n this.#subscribeToEvents();\n this.#initializeActiveChains().catch(console.error);\n }\n\n // ============================================================================\n // INITIALIZATION\n // ============================================================================\n\n async #initializeActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only claim chains if the websocket is already connected.\n // If not connected, chains stay unclaimed so AccountsApiDataSource\n // can pick them up via polling. They'll be claimed on reconnect.\n if (this.#isConnected) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n this.#chainsRefreshTimer = setInterval(() => {\n this.#refreshActiveChains().catch(console.error);\n }, DEFAULT_CHAINS_REFRESH_INTERVAL_MS);\n } catch (error) {\n log('Failed to fetch active chains', error);\n }\n }\n\n async #refreshActiveChains(): Promise<void> {\n try {\n const chains = await this.#fetchActiveChains();\n this.#supportedChains = chains;\n\n // Only update activeChains if connected; otherwise keep them unclaimed.\n if (!this.#isConnected) {\n return;\n }\n\n const previousChains = new Set(this.state.activeChains);\n const newChains = new Set(chains);\n\n const added = chains.filter((chain) => !previousChains.has(chain));\n const removed = Array.from(previousChains).filter(\n (chain) => !newChains.has(chain),\n );\n\n if (added.length > 0 || removed.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n } catch (error) {\n log('Failed to refresh active chains', error);\n }\n }\n\n async #fetchActiveChains(): Promise<ChainId[]> {\n const response = await this.#apiClient.accounts.fetchV2SupportedNetworks();\n return response.fullSupport.map(toChainId);\n }\n\n #subscribeToEvents(): void {\n type ConnectionStatePayload = {\n state: WebSocketState;\n [key: string]: unknown;\n };\n // Listen for WebSocket connection state changes (event not in AssetsControllerEvents).\n (\n this.#messenger as unknown as {\n subscribe: (e: string, h: (p: ConnectionStatePayload) => void) => void;\n }\n ).subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n (connectionInfo: ConnectionStatePayload) => {\n if (connectionInfo.state === ('connected' as WebSocketState)) {\n this.#isConnected = true;\n this.#handleReconnect();\n } else if (\n connectionInfo.state === ('disconnected' as WebSocketState)\n ) {\n this.#isConnected = false;\n this.#handleDisconnect();\n }\n },\n );\n }\n\n /**\n * Sync active chains from AccountsApiDataSource.\n * When the data source invokes the onActiveChainsUpdated callback, the\n * controller processes the active chains update (no messenger call; controller already updated).\n *\n * @param chains - Updated active chain IDs from AccountsApiDataSource.\n */\n setActiveChainsFromAccountsApi(chains: ChainId[]): void {\n this.updateActiveChains(chains, () => undefined);\n }\n\n /**\n * Handle WebSocket disconnection.\n * Moves all active subscriptions to pending for re-subscription on reconnect.\n */\n #handleDisconnect(): void {\n log('WebSocket disconnected, releasing chains for fallback', {\n activeSubscriptionCount: this.activeSubscriptions.size,\n wsSubscriptionCount: this.#wsSubscriptions.size,\n chainCount: this.state.activeChains.length,\n });\n\n // Move active subscriptions to pending for re-subscription\n for (const [subscriptionId] of this.activeSubscriptions) {\n const originalRequest = this.#subscriptionRequests.get(subscriptionId);\n if (originalRequest) {\n this.#pendingSubscriptions.set(subscriptionId, {\n ...originalRequest,\n isUpdate: false,\n });\n }\n }\n\n // Clear WebSocket subscriptions (server-side already cleared)\n this.#wsSubscriptions.clear();\n\n // Clear active subscriptions (they're no longer valid)\n this.activeSubscriptions.clear();\n\n // Release chains so the chain-claiming loop assigns them to\n // AccountsApiDataSource (polling fallback) on the next #subscribeAssets.\n const previous = [...this.state.activeChains];\n if (previous.length > 0) {\n this.updateActiveChains([], (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n /**\n * Handle WebSocket reconnection.\n * Clears stale pending subscriptions and restores activeChains so the\n * chain-claiming loop re-assigns them to this data source, triggering\n * fresh subscriptions with current accounts and chains.\n */\n #handleReconnect(): void {\n log('WebSocket reconnected, reclaiming chains', {\n supportedChainCount: this.#supportedChains.length,\n pendingSubscriptionCount: this.#pendingSubscriptions.size,\n });\n\n // Discard stale pending subscriptions captured at disconnect time.\n // The chain reclaim below triggers #onActiveChainsUpdated →\n // #subscribeAssets() in AssetsController, which creates fresh\n // subscriptions with current accounts and chains. Processing the\n // stale pending entries afterwards would overwrite those with\n // outdated request data.\n this.#pendingSubscriptions.clear();\n\n if (this.#supportedChains.length > 0) {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(this.#supportedChains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n }\n\n // ============================================================================\n // ACTIVE CHAINS\n // ============================================================================\n\n /**\n * Update active chains when AccountsApiDataSource reports new supported chains.\n *\n * @param chains - Array of supported chain IDs.\n */\n updateSupportedChains(chains: ChainId[]): void {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(chains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n // ============================================================================\n // SUBSCRIBE\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n // Filter to active chains only\n const chainsToSubscribe = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n const addresses = request.accountsWithSupportedChains.map(\n (a) => a.account.address,\n );\n\n if (addresses.length === 0) {\n return;\n }\n\n // Check WebSocket connection status\n try {\n const connectionInfo = this.#messenger.call(\n 'BackendWebSocketService:getConnectionInfo',\n );\n if (connectionInfo.state !== ('connected' as WebSocketState)) {\n // Store the subscription request to process when WebSocket connects\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n } catch {\n // Store anyway - will be processed when we can connect\n this.#pendingSubscriptions.set(subscriptionId, subscriptionRequest);\n return;\n }\n\n // Remove from pending if it was there (we're processing it now)\n this.#pendingSubscriptions.delete(subscriptionId);\n\n // Handle subscription update\n if (isUpdate) {\n const existing = this.activeSubscriptions.get(subscriptionId);\n if (existing) {\n // Check if accounts changed - if so, we need to re-subscribe to different channels\n const existingAddresses = existing.addresses ?? [];\n const addressesChanged =\n addresses.length !== existingAddresses.length ||\n addresses.some((addr) => !existingAddresses.includes(addr));\n\n if (!addressesChanged) {\n // Only chains changed - just update chains and return\n existing.chains = chainsToSubscribe;\n return;\n }\n // Accounts changed - fall through to re-subscribe with new channels\n }\n }\n\n // Clean up existing subscription if any\n await this.unsubscribe(subscriptionId);\n\n // Always subscribe to eip155 and solana account activity, plus any namespaces from requested chains\n const namespaces = getNamespacesForAccountActivity(chainsToSubscribe);\n\n // Build channel names: use namespace-appropriate address per account (eip155 = hex, solana = base58)\n const channels: string[] = [];\n for (const namespace of namespaces) {\n for (const { account } of request.accountsWithSupportedChains) {\n const address = getAddressForAccountActivity(account, namespace);\n if (address) {\n channels.push(buildAccountActivityChannel(namespace, address));\n }\n }\n }\n\n try {\n // Create WebSocket subscription\n const wsSubscription = await this.#messenger.call(\n 'BackendWebSocketService:subscribe',\n {\n channels,\n channelType: CHANNEL_TYPE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleNotification(notification, subscriptionId);\n },\n },\n );\n\n // Store WebSocket subscription\n this.#wsSubscriptions.set(subscriptionId, wsSubscription);\n\n // Store in abstract class tracking\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n const wsSub = this.#wsSubscriptions.get(subscriptionId);\n if (wsSub) {\n wsSub.unsubscribe().catch((unsubErr: unknown) => {\n log('Error unsubscribing', { subscriptionId, error: unsubErr });\n });\n this.#wsSubscriptions.delete(subscriptionId);\n }\n // Also clean up the stored request\n this.#subscriptionRequests.delete(subscriptionId);\n },\n chains: chainsToSubscribe,\n addresses,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Store original request for reconnection\n this.#subscriptionRequests.set(subscriptionId, subscriptionRequest);\n } catch (error) {\n log('WebSocket subscription FAILED', {\n subscriptionId,\n error,\n chains: chainsToSubscribe,\n });\n }\n }\n\n // ============================================================================\n // NOTIFICATION HANDLING\n // ============================================================================\n\n #handleNotification(\n notification: ServerNotificationMessage,\n subscriptionId: string,\n ): void {\n try {\n const subscription = this.activeSubscriptions.get(subscriptionId);\n const request = this.#subscriptionRequests.get(subscriptionId)?.request;\n if (!request) {\n return;\n }\n\n const activityMessage =\n notification.data as unknown as AccountActivityMessage;\n const { address, tx, updates } = activityMessage;\n\n if (!address || !tx || !updates) {\n return;\n }\n\n // Extract chain ID from transaction (CAIP-2 format, e.g., \"eip155:8453\")\n const chainId = tx.chain as ChainId;\n\n // Find matching account in request (eip155: case-insensitive hex; solana: exact base58)\n const account = request.accountsWithSupportedChains\n .map((entry) => entry.account)\n .find((a) =>\n a.address.startsWith('0x')\n ? a.address.toLowerCase() === address.toLowerCase()\n : a.address === address,\n );\n if (!account) {\n return;\n }\n const accountId = account.id;\n\n // Process all balance updates from the activity message\n const response = this.#processBalanceUpdates(updates, chainId, accountId);\n\n if (Object.keys(response).length > 0 && subscription) {\n Promise.resolve(subscription.onAssetsUpdate(response)).catch(\n console.error,\n );\n }\n } catch (error) {\n log('Error handling notification', error);\n }\n }\n\n /**\n * Process balance updates from AccountActivityMessage.\n * Each update contains asset info, post-transaction balance, and transfer details.\n *\n * @param updates - Array of balance updates from the activity message.\n * @param _chainId - The chain ID (unused but kept for context).\n * @param accountId - The account ID to process updates for.\n * @returns DataResponse containing processed balance and metadata.\n */\n #processBalanceUpdates(\n updates: BalanceUpdate[],\n _chainId: ChainId,\n accountId: string,\n ): DataResponse {\n const assetsBalance: Record<string, Record<Caip19AssetId, AssetBalance>> = {\n [accountId]: {},\n };\n const assetsMetadata: Record<Caip19AssetId, AssetMetadata> = {};\n\n for (const update of updates) {\n const { asset, postBalance } = update;\n\n if (!asset || !postBalance) {\n continue;\n }\n\n // Asset type is in CAIP format: \"eip155:1/erc20:0x...\" or \"eip155:1/slip44:60\"\n // We can use it directly as the asset ID\n const assetId = asset.type as Caip19AssetId;\n\n // Determine token type from asset type string\n const isNative = this.#isNativeAsset(assetId);\n const tokenType = isNative ? 'native' : 'erc20';\n\n // We assume decimals are always present; skip malformed updates\n if (asset.decimals === undefined) {\n continue;\n }\n\n // Parse raw balance (hex like \"0x26f0e5\" or decimal string)\n const rawBalanceStr = postBalance.amount.startsWith('0x')\n ? BigInt(postBalance.amount).toString()\n : postBalance.amount;\n\n const humanReadableAmount = new BigNumberJS(rawBalanceStr)\n .dividedBy(new BigNumberJS(10).pow(asset.decimals))\n .toFixed();\n\n assetsBalance[accountId][assetId] = {\n amount: humanReadableAmount,\n };\n\n assetsMetadata[assetId] = {\n type: tokenType,\n symbol: asset.unit,\n name: asset.unit, // Use unit as name (actual name may not be in the message)\n decimals: asset.decimals,\n };\n }\n\n const response: DataResponse = { updateMode: 'merge' };\n if (Object.keys(assetsBalance[accountId]).length > 0) {\n response.assetsBalance = assetsBalance;\n response.assetsInfo = assetsMetadata;\n }\n\n return response;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n if (this.#chainsRefreshTimer) {\n clearInterval(this.#chainsRefreshTimer);\n this.#chainsRefreshTimer = null;\n }\n\n // Clean up WebSocket subscriptions\n // Convert to array first to avoid modifying map during iteration\n const subscriptions = [...this.#wsSubscriptions.values()];\n for (const wsSub of subscriptions) {\n try {\n // Fire and forget - don't await in destroy\n wsSub.unsubscribe().catch(() => {\n // Ignore errors during cleanup\n });\n } catch {\n // Ignore errors during cleanup\n }\n }\n this.#wsSubscriptions.clear();\n\n // Clean up base class subscriptions\n super.destroy();\n }\n}\n\n// ============================================================================\n// FACTORY FUNCTION\n// ============================================================================\n\n/**\n * Creates a BackendWebsocketDataSource instance.\n *\n * @param options - Configuration options for the data source.\n * @returns A new BackendWebsocketDataSource instance.\n */\nexport function createBackendWebsocketDataSource(\n options: BackendWebsocketDataSourceOptions,\n): BackendWebsocketDataSource {\n return new BackendWebsocketDataSource(options);\n}\n"]}
|
|
@@ -281,10 +281,6 @@ function getAggregatedBalanceForAccount(state, selectedInternalAccount, enabledN
|
|
|
281
281
|
const { amount } = row;
|
|
282
282
|
const entry = {
|
|
283
283
|
assetId,
|
|
284
|
-
// `.toFixed()` — not `.toString()` — because BigNumber's default
|
|
285
|
-
// `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation
|
|
286
|
-
// for sub-1e-7 values (e.g. `"1e-18"`), which downstream `BigInt()`
|
|
287
|
-
// parsers reject (MMBUGS-772).
|
|
288
284
|
amount: amount.toFixed(),
|
|
289
285
|
...(row.decimals === undefined ? {} : { decimals: row.decimals }),
|
|
290
286
|
...(row.symbol === undefined ? {} : { symbol: row.symbol }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balance.cjs","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport {\n KnownCaipNamespace,\n isStrictHexString,\n parseCaipAssetType,\n parseCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerState } from '../AssetsController';\nimport type {\n AccountId,\n AssetBalance,\n AssetMetadata,\n AssetPreferences,\n Caip19AssetId,\n} from '../types';\n\n// ============================================================================\n// TRACE NAMES — used in Sentry spans (search these strings in Discover)\n// ============================================================================\nconst TRACE_AGGREGATED_BALANCE_SELECTOR = 'AggregatedBalanceSelector';\n\nexport type EnabledNetworkMap =\n | Record<string, Record<string, boolean>>\n | undefined;\n\nexport type AggregatedBalanceEntry = {\n assetId: Caip19AssetId;\n amount: string;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nexport type AggregatedBalanceForAccount = {\n entries: AggregatedBalanceEntry[];\n totalBalanceInFiat?: number;\n pricePercentChange1d?: number;\n};\n\ntype AccountLike = { id: AccountId };\nexport type AccountsById = Record<AccountId, InternalAccount>;\n\ntype PriceDatum = { price: number; pricePercentChange1d: number };\n\nconst ZERO_PRICE: PriceDatum = { price: 0, pricePercentChange1d: 0 };\n\nconst getAmountFromBalance = (balance: AssetBalance): string => {\n if (typeof balance === 'object' && balance !== null && 'amount' in balance) {\n const { amount } = balance as { amount?: unknown };\n return typeof amount === 'string' ? amount : '0';\n }\n return '0';\n};\n\nconst toBigNumberOrZero = (value: string): BigNumberJS => {\n const parsed = new BigNumberJS(value);\n return parsed.isNaN() || !parsed.isFinite() ? new BigNumberJS(0) : parsed;\n};\n\n/**\n * When state contains raw base units (e.g. SPORE \"16201541034.639288184\" with 9 decimals),\n * scale to human (16.2) before pricing. Only scale when amount >= 10^decimals so we don't\n * double-scale amounts that are already human (e.g. \"1\", \"0.227285\").\n *\n * @param amountRaw - Amount from state (may be raw or human).\n * @param decimals - Token decimals from metadata.\n * @returns Human amount for display and fiat (amountRaw or amountRaw / 10^decimals).\n */\nconst scaleToHumanIfRaw = (\n amountRaw: BigNumberJS,\n decimals: number,\n): BigNumberJS => {\n if (decimals <= 0) {\n return amountRaw;\n }\n const scale = new BigNumberJS(10).pow(decimals);\n if (amountRaw.lt(scale)) {\n return amountRaw;\n }\n return amountRaw.dividedBy(scale);\n};\n\nconst getPriceDatumFast = (\n assetsPrice: AssetsControllerState['assetsPrice'] | undefined,\n assetId: Caip19AssetId,\n): PriceDatum => {\n const raw = assetsPrice?.[assetId];\n if (!raw || typeof raw !== 'object') {\n return ZERO_PRICE;\n }\n const { price, pricePercentChange1d } = raw as {\n price?: unknown;\n pricePercentChange1d?: unknown;\n };\n return {\n price: typeof price === 'number' && Number.isFinite(price) ? price : 0,\n pricePercentChange1d:\n typeof pricePercentChange1d === 'number' &&\n Number.isFinite(pricePercentChange1d)\n ? pricePercentChange1d\n : 0,\n };\n};\n\n/**\n * Enablement lookup optimized:\n * - no array allocations\n * - early returns\n *\n * @param map - Enabled network map (namespace -> storageKey -> boolean)\n * @param id - Chain id as Hex or CAIP-2\n * @returns True if the chain is enabled or map is undefined\n */\nconst isChainEnabledByMap = (\n map: EnabledNetworkMap,\n id: Hex | CaipChainId,\n): boolean => {\n if (!map) {\n return true;\n }\n\n if (isStrictHexString(id)) {\n return Boolean(map[KnownCaipNamespace.Eip155]?.[id]);\n }\n\n const { namespace, reference } = parseCaipChainId(id);\n const namespaceMap = map[namespace];\n if (!namespaceMap) {\n return false;\n }\n\n // exact CAIP-2 id / reference\n if (namespaceMap[id] || namespaceMap[reference]) {\n return true;\n }\n\n // EVM: hex storage key\n if (namespace === KnownCaipNamespace.Eip155) {\n try {\n const storageKey = toHex(reference);\n return Boolean(namespaceMap[storageKey]);\n } catch {\n const parsedRef = Number.parseInt(reference, 10);\n if (Number.isFinite(parsedRef)) {\n return Boolean(namespaceMap[`0x${parsedRef.toString(16)}`]);\n }\n }\n }\n\n return false;\n};\n\n/**\n * Cache parsing results per assetId to avoid parseCaipAssetType/parseCaipChainId\n * being called multiple times across filtering + grouping + pricing.\n */\ntype AssetParseInfo = {\n chainId: CaipChainId;\n isEvm: boolean;\n};\n\nconst makeAssetInfoCache = (): Map<Caip19AssetId, AssetParseInfo> =>\n new Map<Caip19AssetId, AssetParseInfo>();\n\nconst getAssetInfo = (\n cache: Map<Caip19AssetId, AssetParseInfo>,\n assetId: Caip19AssetId,\n): AssetParseInfo => {\n const cached = cache.get(assetId);\n if (cached) {\n return cached;\n }\n const { chainId } = parseCaipAssetType(assetId);\n const { namespace } = parseCaipChainId(chainId);\n const info = { chainId, isEvm: namespace === KnownCaipNamespace.Eip155 };\n cache.set(assetId, info);\n return info;\n};\n\n/**\n * Merge across accounts without building per-account entries arrays.\n * Uses BigNumber for amount accumulation to avoid float precision loss.\n */\ntype AggRow = {\n amount: BigNumberJS;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nfunction mergeBalancesIntoMap(args: {\n out: Map<Caip19AssetId, AggRow>;\n accountBalances: Record<Caip19AssetId, AssetBalance>;\n metadata: Record<Caip19AssetId, AssetMetadata>;\n assetPreferences?: Record<Caip19AssetId, AssetPreferences>;\n enabledNetworkMap?: EnabledNetworkMap;\n assetInfoCache: Map<Caip19AssetId, AssetParseInfo>;\n}): void {\n const {\n out,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n } = args;\n\n for (const assetId in accountBalances) {\n if (!Object.prototype.hasOwnProperty.call(accountBalances, assetId)) {\n continue;\n }\n const typedAssetId = assetId as Caip19AssetId;\n\n if (assetPreferences?.[typedAssetId]?.hidden) {\n continue;\n }\n\n const info = getAssetInfo(assetInfoCache, typedAssetId);\n if (!isChainEnabledByMap(enabledNetworkMap, info.chainId)) {\n continue;\n }\n\n const amountStr = getAmountFromBalance(accountBalances[typedAssetId]);\n let amountBn = toBigNumberOrZero(amountStr);\n const meta = metadata[typedAssetId];\n if (meta?.decimals !== undefined) {\n amountBn = scaleToHumanIfRaw(amountBn, meta.decimals);\n }\n if (amountBn.isZero()) {\n continue; // skip zeros early to reduce map pressure\n }\n\n const existing = out.get(typedAssetId);\n if (existing) {\n existing.amount = existing.amount.plus(amountBn);\n continue;\n }\n\n out.set(typedAssetId, {\n amount: amountBn,\n decimals: meta?.decimals,\n symbol: meta?.symbol,\n name: meta?.name,\n });\n }\n}\n\nexport function getGroupIdForAccount(\n accountTreeState: AccountTreeControllerState,\n accountId: AccountId,\n): string | undefined {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n for (const wallet of Object.values(wallets)) {\n for (const [groupId, group] of Object.entries(wallet?.groups ?? {})) {\n const accounts = group?.accounts;\n if (Array.isArray(accounts) && accounts.includes(accountId)) {\n return groupId;\n }\n }\n }\n return undefined;\n}\n\nexport function getInternalAccountsForGroup(\n accountTreeState: AccountTreeControllerState,\n accountsById: AccountsById,\n groupId: string,\n): InternalAccount[] {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return [];\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (!group?.accounts) {\n continue;\n }\n const result: InternalAccount[] = [];\n for (const id of group.accounts) {\n const acct = accountsById[id];\n if (acct) {\n result.push(acct);\n }\n }\n return result;\n }\n return [];\n}\n\nfunction getAccountIdsInSameGroup(\n accountTreeState: AccountTreeControllerState,\n selectedAccountId: AccountId,\n): AccountId[] | undefined {\n const groupId = getGroupIdForAccount(accountTreeState, selectedAccountId);\n if (!groupId) {\n return undefined;\n }\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (group?.accounts) {\n return [...group.accounts];\n }\n }\n return undefined;\n}\n\nfunction resolveAccountsToAggregate(args: {\n selectedInternalAccount: InternalAccount;\n accountTreeState?: AccountTreeControllerState;\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[];\n accountsById?: AccountsById;\n}): AccountLike[] {\n const {\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n } = args;\n\n if (internalAccountsOrAccountIds && internalAccountsOrAccountIds.length > 0) {\n const first = internalAccountsOrAccountIds[0];\n if (typeof first === 'string') {\n const ids = internalAccountsOrAccountIds as AccountId[];\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n return internalAccountsOrAccountIds as InternalAccount[];\n }\n\n if (\n accountTreeState &&\n accountsById &&\n Object.keys(accountsById).length > 0\n ) {\n const groupId = getGroupIdForAccount(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (groupId) {\n const groupAccounts = getInternalAccountsForGroup(\n accountTreeState,\n accountsById,\n groupId,\n );\n if (groupAccounts.length > 0) {\n return groupAccounts;\n }\n }\n }\n\n if (accountTreeState) {\n const ids = getAccountIdsInSameGroup(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (ids && ids.length > 0) {\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n }\n\n return [selectedInternalAccount];\n}\n\nexport function getAggregatedBalanceForAccount(\n state: AssetsControllerState,\n selectedInternalAccount: InternalAccount,\n enabledNetworkMap?: EnabledNetworkMap,\n accountTreeState?: AccountTreeControllerState,\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[],\n accountsById?: AccountsById,\n trace?: TraceCallback,\n): AggregatedBalanceForAccount {\n const startTime = trace ? performance.now() : 0;\n const { assetsBalance, assetsInfo, assetPreferences, assetsPrice } = state;\n\n const metadata = (assetsInfo ?? {}) as Record<Caip19AssetId, AssetMetadata>;\n\n const hasPrices =\n Boolean(assetsPrice) &&\n ((): boolean => {\n for (const key in assetsPrice) {\n if (Object.prototype.hasOwnProperty.call(assetsPrice, key)) {\n return true;\n }\n }\n return false;\n })();\n\n const accountsToAggregate = resolveAccountsToAggregate({\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n });\n\n const assetInfoCache = makeAssetInfoCache();\n const merged = new Map<Caip19AssetId, AggRow>();\n\n for (const account of accountsToAggregate) {\n const accountId = account.id;\n const accountBalances =\n assetsBalance?.[accountId] ?? ({} as Record<Caip19AssetId, AssetBalance>);\n\n mergeBalancesIntoMap({\n out: merged,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n });\n }\n\n // Materialize entries once\n const entries: AggregatedBalanceEntry[] = new Array(merged.size);\n let idx = 0;\n\n // If prices exist, compute totals in a single pass over merged.\n let totalBalanceInFiat = 0;\n let weightedNumerator = 0;\n\n for (const [assetId, row] of merged.entries()) {\n const { amount } = row;\n const entry: AggregatedBalanceEntry = {\n assetId,\n // `.toFixed()` — not `.toString()` — because BigNumber's default\n // `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation\n // for sub-1e-7 values (e.g. `\"1e-18\"`), which downstream `BigInt()`\n // parsers reject (MMBUGS-772).\n amount: amount.toFixed(),\n ...(row.decimals === undefined ? {} : { decimals: row.decimals }),\n ...(row.symbol === undefined ? {} : { symbol: row.symbol }),\n ...(row.name === undefined ? {} : { name: row.name }),\n };\n entries[idx] = entry;\n idx += 1;\n\n if (hasPrices) {\n const { price, pricePercentChange1d } = getPriceDatumFast(\n assetsPrice,\n assetId,\n );\n const contribution = amount.multipliedBy(price).toNumber();\n if (contribution > 0) {\n totalBalanceInFiat += contribution;\n weightedNumerator += contribution * pricePercentChange1d;\n }\n }\n }\n\n if (trace) {\n const durationMs = performance.now() - startTime;\n const uniqueNetworks = new Set<CaipChainId>();\n for (const assetId of merged.keys()) {\n const info = getAssetInfo(assetInfoCache, assetId);\n uniqueNetworks.add(info.chainId);\n }\n trace(\n {\n name: TRACE_AGGREGATED_BALANCE_SELECTOR,\n data: {\n duration_ms: durationMs,\n asset_count: merged.size,\n network_count: uniqueNetworks.size,\n account_count: accountsToAggregate.length,\n },\n tags: { controller: 'AssetsController' },\n },\n () => undefined,\n ).catch(() => {\n // Telemetry failure must not break.\n });\n }\n\n if (hasPrices) {\n const pricePercentChange1d =\n totalBalanceInFiat > 0 ? weightedNumerator / totalBalanceInFiat : 0;\n return {\n entries,\n totalBalanceInFiat,\n pricePercentChange1d,\n };\n }\n\n return { entries };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"balance.cjs","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport {\n KnownCaipNamespace,\n isStrictHexString,\n parseCaipAssetType,\n parseCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerState } from '../AssetsController';\nimport type {\n AccountId,\n AssetBalance,\n AssetMetadata,\n AssetPreferences,\n Caip19AssetId,\n} from '../types';\n\n// ============================================================================\n// TRACE NAMES — used in Sentry spans (search these strings in Discover)\n// ============================================================================\nconst TRACE_AGGREGATED_BALANCE_SELECTOR = 'AggregatedBalanceSelector';\n\nexport type EnabledNetworkMap =\n | Record<string, Record<string, boolean>>\n | undefined;\n\nexport type AggregatedBalanceEntry = {\n assetId: Caip19AssetId;\n amount: string;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nexport type AggregatedBalanceForAccount = {\n entries: AggregatedBalanceEntry[];\n totalBalanceInFiat?: number;\n pricePercentChange1d?: number;\n};\n\ntype AccountLike = { id: AccountId };\nexport type AccountsById = Record<AccountId, InternalAccount>;\n\ntype PriceDatum = { price: number; pricePercentChange1d: number };\n\nconst ZERO_PRICE: PriceDatum = { price: 0, pricePercentChange1d: 0 };\n\nconst getAmountFromBalance = (balance: AssetBalance): string => {\n if (typeof balance === 'object' && balance !== null && 'amount' in balance) {\n const { amount } = balance as { amount?: unknown };\n return typeof amount === 'string' ? amount : '0';\n }\n return '0';\n};\n\nconst toBigNumberOrZero = (value: string): BigNumberJS => {\n const parsed = new BigNumberJS(value);\n return parsed.isNaN() || !parsed.isFinite() ? new BigNumberJS(0) : parsed;\n};\n\n/**\n * When state contains raw base units (e.g. SPORE \"16201541034.639288184\" with 9 decimals),\n * scale to human (16.2) before pricing. Only scale when amount >= 10^decimals so we don't\n * double-scale amounts that are already human (e.g. \"1\", \"0.227285\").\n *\n * @param amountRaw - Amount from state (may be raw or human).\n * @param decimals - Token decimals from metadata.\n * @returns Human amount for display and fiat (amountRaw or amountRaw / 10^decimals).\n */\nconst scaleToHumanIfRaw = (\n amountRaw: BigNumberJS,\n decimals: number,\n): BigNumberJS => {\n if (decimals <= 0) {\n return amountRaw;\n }\n const scale = new BigNumberJS(10).pow(decimals);\n if (amountRaw.lt(scale)) {\n return amountRaw;\n }\n return amountRaw.dividedBy(scale);\n};\n\nconst getPriceDatumFast = (\n assetsPrice: AssetsControllerState['assetsPrice'] | undefined,\n assetId: Caip19AssetId,\n): PriceDatum => {\n const raw = assetsPrice?.[assetId];\n if (!raw || typeof raw !== 'object') {\n return ZERO_PRICE;\n }\n const { price, pricePercentChange1d } = raw as {\n price?: unknown;\n pricePercentChange1d?: unknown;\n };\n return {\n price: typeof price === 'number' && Number.isFinite(price) ? price : 0,\n pricePercentChange1d:\n typeof pricePercentChange1d === 'number' &&\n Number.isFinite(pricePercentChange1d)\n ? pricePercentChange1d\n : 0,\n };\n};\n\n/**\n * Enablement lookup optimized:\n * - no array allocations\n * - early returns\n *\n * @param map - Enabled network map (namespace -> storageKey -> boolean)\n * @param id - Chain id as Hex or CAIP-2\n * @returns True if the chain is enabled or map is undefined\n */\nconst isChainEnabledByMap = (\n map: EnabledNetworkMap,\n id: Hex | CaipChainId,\n): boolean => {\n if (!map) {\n return true;\n }\n\n if (isStrictHexString(id)) {\n return Boolean(map[KnownCaipNamespace.Eip155]?.[id]);\n }\n\n const { namespace, reference } = parseCaipChainId(id);\n const namespaceMap = map[namespace];\n if (!namespaceMap) {\n return false;\n }\n\n // exact CAIP-2 id / reference\n if (namespaceMap[id] || namespaceMap[reference]) {\n return true;\n }\n\n // EVM: hex storage key\n if (namespace === KnownCaipNamespace.Eip155) {\n try {\n const storageKey = toHex(reference);\n return Boolean(namespaceMap[storageKey]);\n } catch {\n const parsedRef = Number.parseInt(reference, 10);\n if (Number.isFinite(parsedRef)) {\n return Boolean(namespaceMap[`0x${parsedRef.toString(16)}`]);\n }\n }\n }\n\n return false;\n};\n\n/**\n * Cache parsing results per assetId to avoid parseCaipAssetType/parseCaipChainId\n * being called multiple times across filtering + grouping + pricing.\n */\ntype AssetParseInfo = {\n chainId: CaipChainId;\n isEvm: boolean;\n};\n\nconst makeAssetInfoCache = (): Map<Caip19AssetId, AssetParseInfo> =>\n new Map<Caip19AssetId, AssetParseInfo>();\n\nconst getAssetInfo = (\n cache: Map<Caip19AssetId, AssetParseInfo>,\n assetId: Caip19AssetId,\n): AssetParseInfo => {\n const cached = cache.get(assetId);\n if (cached) {\n return cached;\n }\n const { chainId } = parseCaipAssetType(assetId);\n const { namespace } = parseCaipChainId(chainId);\n const info = { chainId, isEvm: namespace === KnownCaipNamespace.Eip155 };\n cache.set(assetId, info);\n return info;\n};\n\n/**\n * Merge across accounts without building per-account entries arrays.\n * Uses BigNumber for amount accumulation to avoid float precision loss.\n */\ntype AggRow = {\n amount: BigNumberJS;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nfunction mergeBalancesIntoMap(args: {\n out: Map<Caip19AssetId, AggRow>;\n accountBalances: Record<Caip19AssetId, AssetBalance>;\n metadata: Record<Caip19AssetId, AssetMetadata>;\n assetPreferences?: Record<Caip19AssetId, AssetPreferences>;\n enabledNetworkMap?: EnabledNetworkMap;\n assetInfoCache: Map<Caip19AssetId, AssetParseInfo>;\n}): void {\n const {\n out,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n } = args;\n\n for (const assetId in accountBalances) {\n if (!Object.prototype.hasOwnProperty.call(accountBalances, assetId)) {\n continue;\n }\n const typedAssetId = assetId as Caip19AssetId;\n\n if (assetPreferences?.[typedAssetId]?.hidden) {\n continue;\n }\n\n const info = getAssetInfo(assetInfoCache, typedAssetId);\n if (!isChainEnabledByMap(enabledNetworkMap, info.chainId)) {\n continue;\n }\n\n const amountStr = getAmountFromBalance(accountBalances[typedAssetId]);\n let amountBn = toBigNumberOrZero(amountStr);\n const meta = metadata[typedAssetId];\n if (meta?.decimals !== undefined) {\n amountBn = scaleToHumanIfRaw(amountBn, meta.decimals);\n }\n if (amountBn.isZero()) {\n continue; // skip zeros early to reduce map pressure\n }\n\n const existing = out.get(typedAssetId);\n if (existing) {\n existing.amount = existing.amount.plus(amountBn);\n continue;\n }\n\n out.set(typedAssetId, {\n amount: amountBn,\n decimals: meta?.decimals,\n symbol: meta?.symbol,\n name: meta?.name,\n });\n }\n}\n\nexport function getGroupIdForAccount(\n accountTreeState: AccountTreeControllerState,\n accountId: AccountId,\n): string | undefined {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n for (const wallet of Object.values(wallets)) {\n for (const [groupId, group] of Object.entries(wallet?.groups ?? {})) {\n const accounts = group?.accounts;\n if (Array.isArray(accounts) && accounts.includes(accountId)) {\n return groupId;\n }\n }\n }\n return undefined;\n}\n\nexport function getInternalAccountsForGroup(\n accountTreeState: AccountTreeControllerState,\n accountsById: AccountsById,\n groupId: string,\n): InternalAccount[] {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return [];\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (!group?.accounts) {\n continue;\n }\n const result: InternalAccount[] = [];\n for (const id of group.accounts) {\n const acct = accountsById[id];\n if (acct) {\n result.push(acct);\n }\n }\n return result;\n }\n return [];\n}\n\nfunction getAccountIdsInSameGroup(\n accountTreeState: AccountTreeControllerState,\n selectedAccountId: AccountId,\n): AccountId[] | undefined {\n const groupId = getGroupIdForAccount(accountTreeState, selectedAccountId);\n if (!groupId) {\n return undefined;\n }\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (group?.accounts) {\n return [...group.accounts];\n }\n }\n return undefined;\n}\n\nfunction resolveAccountsToAggregate(args: {\n selectedInternalAccount: InternalAccount;\n accountTreeState?: AccountTreeControllerState;\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[];\n accountsById?: AccountsById;\n}): AccountLike[] {\n const {\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n } = args;\n\n if (internalAccountsOrAccountIds && internalAccountsOrAccountIds.length > 0) {\n const first = internalAccountsOrAccountIds[0];\n if (typeof first === 'string') {\n const ids = internalAccountsOrAccountIds as AccountId[];\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n return internalAccountsOrAccountIds as InternalAccount[];\n }\n\n if (\n accountTreeState &&\n accountsById &&\n Object.keys(accountsById).length > 0\n ) {\n const groupId = getGroupIdForAccount(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (groupId) {\n const groupAccounts = getInternalAccountsForGroup(\n accountTreeState,\n accountsById,\n groupId,\n );\n if (groupAccounts.length > 0) {\n return groupAccounts;\n }\n }\n }\n\n if (accountTreeState) {\n const ids = getAccountIdsInSameGroup(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (ids && ids.length > 0) {\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n }\n\n return [selectedInternalAccount];\n}\n\nexport function getAggregatedBalanceForAccount(\n state: AssetsControllerState,\n selectedInternalAccount: InternalAccount,\n enabledNetworkMap?: EnabledNetworkMap,\n accountTreeState?: AccountTreeControllerState,\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[],\n accountsById?: AccountsById,\n trace?: TraceCallback,\n): AggregatedBalanceForAccount {\n const startTime = trace ? performance.now() : 0;\n const { assetsBalance, assetsInfo, assetPreferences, assetsPrice } = state;\n\n const metadata = (assetsInfo ?? {}) as Record<Caip19AssetId, AssetMetadata>;\n\n const hasPrices =\n Boolean(assetsPrice) &&\n ((): boolean => {\n for (const key in assetsPrice) {\n if (Object.prototype.hasOwnProperty.call(assetsPrice, key)) {\n return true;\n }\n }\n return false;\n })();\n\n const accountsToAggregate = resolveAccountsToAggregate({\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n });\n\n const assetInfoCache = makeAssetInfoCache();\n const merged = new Map<Caip19AssetId, AggRow>();\n\n for (const account of accountsToAggregate) {\n const accountId = account.id;\n const accountBalances =\n assetsBalance?.[accountId] ?? ({} as Record<Caip19AssetId, AssetBalance>);\n\n mergeBalancesIntoMap({\n out: merged,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n });\n }\n\n // Materialize entries once\n const entries: AggregatedBalanceEntry[] = new Array(merged.size);\n let idx = 0;\n\n // If prices exist, compute totals in a single pass over merged.\n let totalBalanceInFiat = 0;\n let weightedNumerator = 0;\n\n for (const [assetId, row] of merged.entries()) {\n const { amount } = row;\n const entry: AggregatedBalanceEntry = {\n assetId,\n amount: amount.toFixed(),\n ...(row.decimals === undefined ? {} : { decimals: row.decimals }),\n ...(row.symbol === undefined ? {} : { symbol: row.symbol }),\n ...(row.name === undefined ? {} : { name: row.name }),\n };\n entries[idx] = entry;\n idx += 1;\n\n if (hasPrices) {\n const { price, pricePercentChange1d } = getPriceDatumFast(\n assetsPrice,\n assetId,\n );\n const contribution = amount.multipliedBy(price).toNumber();\n if (contribution > 0) {\n totalBalanceInFiat += contribution;\n weightedNumerator += contribution * pricePercentChange1d;\n }\n }\n }\n\n if (trace) {\n const durationMs = performance.now() - startTime;\n const uniqueNetworks = new Set<CaipChainId>();\n for (const assetId of merged.keys()) {\n const info = getAssetInfo(assetInfoCache, assetId);\n uniqueNetworks.add(info.chainId);\n }\n trace(\n {\n name: TRACE_AGGREGATED_BALANCE_SELECTOR,\n data: {\n duration_ms: durationMs,\n asset_count: merged.size,\n network_count: uniqueNetworks.size,\n account_count: accountsToAggregate.length,\n },\n tags: { controller: 'AssetsController' },\n },\n () => undefined,\n ).catch(() => {\n // Telemetry failure must not break.\n });\n }\n\n if (hasPrices) {\n const pricePercentChange1d =\n totalBalanceInFiat > 0 ? weightedNumerator / totalBalanceInFiat : 0;\n return {\n entries,\n totalBalanceInFiat,\n pricePercentChange1d,\n };\n }\n\n return { entries };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balance.d.cts","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,0CAA0C;AAEpF,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAUtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gCAA4B;AACjE,OAAO,KAAK,EACV,SAAS,EAIT,aAAa,EACd,qBAAiB;AAOlB,MAAM,MAAM,iBAAiB,GACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,SAAS,CAAC;AAEd,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAGF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AA+M9D,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,0BAA0B,EAC5C,SAAS,EAAE,SAAS,GACnB,MAAM,GAAG,SAAS,CAcpB;AAED,wBAAgB,2BAA2B,CACzC,gBAAgB,EAAE,0BAA0B,EAC5C,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,GACd,eAAe,EAAE,CA0BnB;AA6FD,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,qBAAqB,EAC5B,uBAAuB,EAAE,eAAe,EACxC,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,gBAAgB,CAAC,EAAE,0BAA0B,EAC7C,4BAA4B,CAAC,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,EAC9D,YAAY,CAAC,EAAE,YAAY,EAC3B,KAAK,CAAC,EAAE,aAAa,GACpB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"balance.d.cts","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,0CAA0C;AAEpF,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAUtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gCAA4B;AACjE,OAAO,KAAK,EACV,SAAS,EAIT,aAAa,EACd,qBAAiB;AAOlB,MAAM,MAAM,iBAAiB,GACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,SAAS,CAAC;AAEd,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAGF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AA+M9D,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,0BAA0B,EAC5C,SAAS,EAAE,SAAS,GACnB,MAAM,GAAG,SAAS,CAcpB;AAED,wBAAgB,2BAA2B,CACzC,gBAAgB,EAAE,0BAA0B,EAC5C,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,GACd,eAAe,EAAE,CA0BnB;AA6FD,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,qBAAqB,EAC5B,uBAAuB,EAAE,eAAe,EACxC,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,gBAAgB,CAAC,EAAE,0BAA0B,EAC7C,4BAA4B,CAAC,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,EAC9D,YAAY,CAAC,EAAE,YAAY,EAC3B,KAAK,CAAC,EAAE,aAAa,GACpB,2BAA2B,CA8G7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balance.d.mts","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,0CAA0C;AAEpF,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAUtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gCAA4B;AACjE,OAAO,KAAK,EACV,SAAS,EAIT,aAAa,EACd,qBAAiB;AAOlB,MAAM,MAAM,iBAAiB,GACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,SAAS,CAAC;AAEd,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAGF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AA+M9D,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,0BAA0B,EAC5C,SAAS,EAAE,SAAS,GACnB,MAAM,GAAG,SAAS,CAcpB;AAED,wBAAgB,2BAA2B,CACzC,gBAAgB,EAAE,0BAA0B,EAC5C,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,GACd,eAAe,EAAE,CA0BnB;AA6FD,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,qBAAqB,EAC5B,uBAAuB,EAAE,eAAe,EACxC,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,gBAAgB,CAAC,EAAE,0BAA0B,EAC7C,4BAA4B,CAAC,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,EAC9D,YAAY,CAAC,EAAE,YAAY,EAC3B,KAAK,CAAC,EAAE,aAAa,GACpB,2BAA2B,
|
|
1
|
+
{"version":3,"file":"balance.d.mts","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,0CAA0C;AAEpF,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AAUtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,gCAA4B;AACjE,OAAO,KAAK,EACV,SAAS,EAIT,aAAa,EACd,qBAAiB;AAOlB,MAAM,MAAM,iBAAiB,GACzB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,SAAS,CAAC;AAEd,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAGF,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;AA+M9D,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,0BAA0B,EAC5C,SAAS,EAAE,SAAS,GACnB,MAAM,GAAG,SAAS,CAcpB;AAED,wBAAgB,2BAA2B,CACzC,gBAAgB,EAAE,0BAA0B,EAC5C,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,MAAM,GACd,eAAe,EAAE,CA0BnB;AA6FD,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,qBAAqB,EAC5B,uBAAuB,EAAE,eAAe,EACxC,iBAAiB,CAAC,EAAE,iBAAiB,EACrC,gBAAgB,CAAC,EAAE,0BAA0B,EAC7C,4BAA4B,CAAC,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,EAC9D,YAAY,CAAC,EAAE,YAAY,EAC3B,KAAK,CAAC,EAAE,aAAa,GACpB,2BAA2B,CA8G7B"}
|
|
@@ -273,10 +273,6 @@ export function getAggregatedBalanceForAccount(state, selectedInternalAccount, e
|
|
|
273
273
|
const { amount } = row;
|
|
274
274
|
const entry = {
|
|
275
275
|
assetId,
|
|
276
|
-
// `.toFixed()` — not `.toString()` — because BigNumber's default
|
|
277
|
-
// `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation
|
|
278
|
-
// for sub-1e-7 values (e.g. `"1e-18"`), which downstream `BigInt()`
|
|
279
|
-
// parsers reject (MMBUGS-772).
|
|
280
276
|
amount: amount.toFixed(),
|
|
281
277
|
...(row.decimals === undefined ? {} : { decimals: row.decimals }),
|
|
282
278
|
...(row.symbol === undefined ? {} : { symbol: row.symbol }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balance.mjs","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport {\n KnownCaipNamespace,\n isStrictHexString,\n parseCaipAssetType,\n parseCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerState } from '../AssetsController';\nimport type {\n AccountId,\n AssetBalance,\n AssetMetadata,\n AssetPreferences,\n Caip19AssetId,\n} from '../types';\n\n// ============================================================================\n// TRACE NAMES — used in Sentry spans (search these strings in Discover)\n// ============================================================================\nconst TRACE_AGGREGATED_BALANCE_SELECTOR = 'AggregatedBalanceSelector';\n\nexport type EnabledNetworkMap =\n | Record<string, Record<string, boolean>>\n | undefined;\n\nexport type AggregatedBalanceEntry = {\n assetId: Caip19AssetId;\n amount: string;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nexport type AggregatedBalanceForAccount = {\n entries: AggregatedBalanceEntry[];\n totalBalanceInFiat?: number;\n pricePercentChange1d?: number;\n};\n\ntype AccountLike = { id: AccountId };\nexport type AccountsById = Record<AccountId, InternalAccount>;\n\ntype PriceDatum = { price: number; pricePercentChange1d: number };\n\nconst ZERO_PRICE: PriceDatum = { price: 0, pricePercentChange1d: 0 };\n\nconst getAmountFromBalance = (balance: AssetBalance): string => {\n if (typeof balance === 'object' && balance !== null && 'amount' in balance) {\n const { amount } = balance as { amount?: unknown };\n return typeof amount === 'string' ? amount : '0';\n }\n return '0';\n};\n\nconst toBigNumberOrZero = (value: string): BigNumberJS => {\n const parsed = new BigNumberJS(value);\n return parsed.isNaN() || !parsed.isFinite() ? new BigNumberJS(0) : parsed;\n};\n\n/**\n * When state contains raw base units (e.g. SPORE \"16201541034.639288184\" with 9 decimals),\n * scale to human (16.2) before pricing. Only scale when amount >= 10^decimals so we don't\n * double-scale amounts that are already human (e.g. \"1\", \"0.227285\").\n *\n * @param amountRaw - Amount from state (may be raw or human).\n * @param decimals - Token decimals from metadata.\n * @returns Human amount for display and fiat (amountRaw or amountRaw / 10^decimals).\n */\nconst scaleToHumanIfRaw = (\n amountRaw: BigNumberJS,\n decimals: number,\n): BigNumberJS => {\n if (decimals <= 0) {\n return amountRaw;\n }\n const scale = new BigNumberJS(10).pow(decimals);\n if (amountRaw.lt(scale)) {\n return amountRaw;\n }\n return amountRaw.dividedBy(scale);\n};\n\nconst getPriceDatumFast = (\n assetsPrice: AssetsControllerState['assetsPrice'] | undefined,\n assetId: Caip19AssetId,\n): PriceDatum => {\n const raw = assetsPrice?.[assetId];\n if (!raw || typeof raw !== 'object') {\n return ZERO_PRICE;\n }\n const { price, pricePercentChange1d } = raw as {\n price?: unknown;\n pricePercentChange1d?: unknown;\n };\n return {\n price: typeof price === 'number' && Number.isFinite(price) ? price : 0,\n pricePercentChange1d:\n typeof pricePercentChange1d === 'number' &&\n Number.isFinite(pricePercentChange1d)\n ? pricePercentChange1d\n : 0,\n };\n};\n\n/**\n * Enablement lookup optimized:\n * - no array allocations\n * - early returns\n *\n * @param map - Enabled network map (namespace -> storageKey -> boolean)\n * @param id - Chain id as Hex or CAIP-2\n * @returns True if the chain is enabled or map is undefined\n */\nconst isChainEnabledByMap = (\n map: EnabledNetworkMap,\n id: Hex | CaipChainId,\n): boolean => {\n if (!map) {\n return true;\n }\n\n if (isStrictHexString(id)) {\n return Boolean(map[KnownCaipNamespace.Eip155]?.[id]);\n }\n\n const { namespace, reference } = parseCaipChainId(id);\n const namespaceMap = map[namespace];\n if (!namespaceMap) {\n return false;\n }\n\n // exact CAIP-2 id / reference\n if (namespaceMap[id] || namespaceMap[reference]) {\n return true;\n }\n\n // EVM: hex storage key\n if (namespace === KnownCaipNamespace.Eip155) {\n try {\n const storageKey = toHex(reference);\n return Boolean(namespaceMap[storageKey]);\n } catch {\n const parsedRef = Number.parseInt(reference, 10);\n if (Number.isFinite(parsedRef)) {\n return Boolean(namespaceMap[`0x${parsedRef.toString(16)}`]);\n }\n }\n }\n\n return false;\n};\n\n/**\n * Cache parsing results per assetId to avoid parseCaipAssetType/parseCaipChainId\n * being called multiple times across filtering + grouping + pricing.\n */\ntype AssetParseInfo = {\n chainId: CaipChainId;\n isEvm: boolean;\n};\n\nconst makeAssetInfoCache = (): Map<Caip19AssetId, AssetParseInfo> =>\n new Map<Caip19AssetId, AssetParseInfo>();\n\nconst getAssetInfo = (\n cache: Map<Caip19AssetId, AssetParseInfo>,\n assetId: Caip19AssetId,\n): AssetParseInfo => {\n const cached = cache.get(assetId);\n if (cached) {\n return cached;\n }\n const { chainId } = parseCaipAssetType(assetId);\n const { namespace } = parseCaipChainId(chainId);\n const info = { chainId, isEvm: namespace === KnownCaipNamespace.Eip155 };\n cache.set(assetId, info);\n return info;\n};\n\n/**\n * Merge across accounts without building per-account entries arrays.\n * Uses BigNumber for amount accumulation to avoid float precision loss.\n */\ntype AggRow = {\n amount: BigNumberJS;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nfunction mergeBalancesIntoMap(args: {\n out: Map<Caip19AssetId, AggRow>;\n accountBalances: Record<Caip19AssetId, AssetBalance>;\n metadata: Record<Caip19AssetId, AssetMetadata>;\n assetPreferences?: Record<Caip19AssetId, AssetPreferences>;\n enabledNetworkMap?: EnabledNetworkMap;\n assetInfoCache: Map<Caip19AssetId, AssetParseInfo>;\n}): void {\n const {\n out,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n } = args;\n\n for (const assetId in accountBalances) {\n if (!Object.prototype.hasOwnProperty.call(accountBalances, assetId)) {\n continue;\n }\n const typedAssetId = assetId as Caip19AssetId;\n\n if (assetPreferences?.[typedAssetId]?.hidden) {\n continue;\n }\n\n const info = getAssetInfo(assetInfoCache, typedAssetId);\n if (!isChainEnabledByMap(enabledNetworkMap, info.chainId)) {\n continue;\n }\n\n const amountStr = getAmountFromBalance(accountBalances[typedAssetId]);\n let amountBn = toBigNumberOrZero(amountStr);\n const meta = metadata[typedAssetId];\n if (meta?.decimals !== undefined) {\n amountBn = scaleToHumanIfRaw(amountBn, meta.decimals);\n }\n if (amountBn.isZero()) {\n continue; // skip zeros early to reduce map pressure\n }\n\n const existing = out.get(typedAssetId);\n if (existing) {\n existing.amount = existing.amount.plus(amountBn);\n continue;\n }\n\n out.set(typedAssetId, {\n amount: amountBn,\n decimals: meta?.decimals,\n symbol: meta?.symbol,\n name: meta?.name,\n });\n }\n}\n\nexport function getGroupIdForAccount(\n accountTreeState: AccountTreeControllerState,\n accountId: AccountId,\n): string | undefined {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n for (const wallet of Object.values(wallets)) {\n for (const [groupId, group] of Object.entries(wallet?.groups ?? {})) {\n const accounts = group?.accounts;\n if (Array.isArray(accounts) && accounts.includes(accountId)) {\n return groupId;\n }\n }\n }\n return undefined;\n}\n\nexport function getInternalAccountsForGroup(\n accountTreeState: AccountTreeControllerState,\n accountsById: AccountsById,\n groupId: string,\n): InternalAccount[] {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return [];\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (!group?.accounts) {\n continue;\n }\n const result: InternalAccount[] = [];\n for (const id of group.accounts) {\n const acct = accountsById[id];\n if (acct) {\n result.push(acct);\n }\n }\n return result;\n }\n return [];\n}\n\nfunction getAccountIdsInSameGroup(\n accountTreeState: AccountTreeControllerState,\n selectedAccountId: AccountId,\n): AccountId[] | undefined {\n const groupId = getGroupIdForAccount(accountTreeState, selectedAccountId);\n if (!groupId) {\n return undefined;\n }\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (group?.accounts) {\n return [...group.accounts];\n }\n }\n return undefined;\n}\n\nfunction resolveAccountsToAggregate(args: {\n selectedInternalAccount: InternalAccount;\n accountTreeState?: AccountTreeControllerState;\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[];\n accountsById?: AccountsById;\n}): AccountLike[] {\n const {\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n } = args;\n\n if (internalAccountsOrAccountIds && internalAccountsOrAccountIds.length > 0) {\n const first = internalAccountsOrAccountIds[0];\n if (typeof first === 'string') {\n const ids = internalAccountsOrAccountIds as AccountId[];\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n return internalAccountsOrAccountIds as InternalAccount[];\n }\n\n if (\n accountTreeState &&\n accountsById &&\n Object.keys(accountsById).length > 0\n ) {\n const groupId = getGroupIdForAccount(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (groupId) {\n const groupAccounts = getInternalAccountsForGroup(\n accountTreeState,\n accountsById,\n groupId,\n );\n if (groupAccounts.length > 0) {\n return groupAccounts;\n }\n }\n }\n\n if (accountTreeState) {\n const ids = getAccountIdsInSameGroup(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (ids && ids.length > 0) {\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n }\n\n return [selectedInternalAccount];\n}\n\nexport function getAggregatedBalanceForAccount(\n state: AssetsControllerState,\n selectedInternalAccount: InternalAccount,\n enabledNetworkMap?: EnabledNetworkMap,\n accountTreeState?: AccountTreeControllerState,\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[],\n accountsById?: AccountsById,\n trace?: TraceCallback,\n): AggregatedBalanceForAccount {\n const startTime = trace ? performance.now() : 0;\n const { assetsBalance, assetsInfo, assetPreferences, assetsPrice } = state;\n\n const metadata = (assetsInfo ?? {}) as Record<Caip19AssetId, AssetMetadata>;\n\n const hasPrices =\n Boolean(assetsPrice) &&\n ((): boolean => {\n for (const key in assetsPrice) {\n if (Object.prototype.hasOwnProperty.call(assetsPrice, key)) {\n return true;\n }\n }\n return false;\n })();\n\n const accountsToAggregate = resolveAccountsToAggregate({\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n });\n\n const assetInfoCache = makeAssetInfoCache();\n const merged = new Map<Caip19AssetId, AggRow>();\n\n for (const account of accountsToAggregate) {\n const accountId = account.id;\n const accountBalances =\n assetsBalance?.[accountId] ?? ({} as Record<Caip19AssetId, AssetBalance>);\n\n mergeBalancesIntoMap({\n out: merged,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n });\n }\n\n // Materialize entries once\n const entries: AggregatedBalanceEntry[] = new Array(merged.size);\n let idx = 0;\n\n // If prices exist, compute totals in a single pass over merged.\n let totalBalanceInFiat = 0;\n let weightedNumerator = 0;\n\n for (const [assetId, row] of merged.entries()) {\n const { amount } = row;\n const entry: AggregatedBalanceEntry = {\n assetId,\n // `.toFixed()` — not `.toString()` — because BigNumber's default\n // `EXPONENTIAL_AT: [-7, 21]` makes `.toString()` emit scientific notation\n // for sub-1e-7 values (e.g. `\"1e-18\"`), which downstream `BigInt()`\n // parsers reject (MMBUGS-772).\n amount: amount.toFixed(),\n ...(row.decimals === undefined ? {} : { decimals: row.decimals }),\n ...(row.symbol === undefined ? {} : { symbol: row.symbol }),\n ...(row.name === undefined ? {} : { name: row.name }),\n };\n entries[idx] = entry;\n idx += 1;\n\n if (hasPrices) {\n const { price, pricePercentChange1d } = getPriceDatumFast(\n assetsPrice,\n assetId,\n );\n const contribution = amount.multipliedBy(price).toNumber();\n if (contribution > 0) {\n totalBalanceInFiat += contribution;\n weightedNumerator += contribution * pricePercentChange1d;\n }\n }\n }\n\n if (trace) {\n const durationMs = performance.now() - startTime;\n const uniqueNetworks = new Set<CaipChainId>();\n for (const assetId of merged.keys()) {\n const info = getAssetInfo(assetInfoCache, assetId);\n uniqueNetworks.add(info.chainId);\n }\n trace(\n {\n name: TRACE_AGGREGATED_BALANCE_SELECTOR,\n data: {\n duration_ms: durationMs,\n asset_count: merged.size,\n network_count: uniqueNetworks.size,\n account_count: accountsToAggregate.length,\n },\n tags: { controller: 'AssetsController' },\n },\n () => undefined,\n ).catch(() => {\n // Telemetry failure must not break.\n });\n }\n\n if (hasPrices) {\n const pricePercentChange1d =\n totalBalanceInFiat > 0 ? weightedNumerator / totalBalanceInFiat : 0;\n return {\n entries,\n totalBalanceInFiat,\n pricePercentChange1d,\n };\n }\n\n return { entries };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"balance.mjs","sourceRoot":"","sources":["../../src/selectors/balance.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountTreeControllerState } from '@metamask/account-tree-controller';\nimport { toHex } from '@metamask/controller-utils';\nimport type { TraceCallback } from '@metamask/controller-utils';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport {\n KnownCaipNamespace,\n isStrictHexString,\n parseCaipAssetType,\n parseCaipChainId,\n} from '@metamask/utils';\nimport BigNumberJS from 'bignumber.js';\n\nimport type { AssetsControllerState } from '../AssetsController';\nimport type {\n AccountId,\n AssetBalance,\n AssetMetadata,\n AssetPreferences,\n Caip19AssetId,\n} from '../types';\n\n// ============================================================================\n// TRACE NAMES — used in Sentry spans (search these strings in Discover)\n// ============================================================================\nconst TRACE_AGGREGATED_BALANCE_SELECTOR = 'AggregatedBalanceSelector';\n\nexport type EnabledNetworkMap =\n | Record<string, Record<string, boolean>>\n | undefined;\n\nexport type AggregatedBalanceEntry = {\n assetId: Caip19AssetId;\n amount: string;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nexport type AggregatedBalanceForAccount = {\n entries: AggregatedBalanceEntry[];\n totalBalanceInFiat?: number;\n pricePercentChange1d?: number;\n};\n\ntype AccountLike = { id: AccountId };\nexport type AccountsById = Record<AccountId, InternalAccount>;\n\ntype PriceDatum = { price: number; pricePercentChange1d: number };\n\nconst ZERO_PRICE: PriceDatum = { price: 0, pricePercentChange1d: 0 };\n\nconst getAmountFromBalance = (balance: AssetBalance): string => {\n if (typeof balance === 'object' && balance !== null && 'amount' in balance) {\n const { amount } = balance as { amount?: unknown };\n return typeof amount === 'string' ? amount : '0';\n }\n return '0';\n};\n\nconst toBigNumberOrZero = (value: string): BigNumberJS => {\n const parsed = new BigNumberJS(value);\n return parsed.isNaN() || !parsed.isFinite() ? new BigNumberJS(0) : parsed;\n};\n\n/**\n * When state contains raw base units (e.g. SPORE \"16201541034.639288184\" with 9 decimals),\n * scale to human (16.2) before pricing. Only scale when amount >= 10^decimals so we don't\n * double-scale amounts that are already human (e.g. \"1\", \"0.227285\").\n *\n * @param amountRaw - Amount from state (may be raw or human).\n * @param decimals - Token decimals from metadata.\n * @returns Human amount for display and fiat (amountRaw or amountRaw / 10^decimals).\n */\nconst scaleToHumanIfRaw = (\n amountRaw: BigNumberJS,\n decimals: number,\n): BigNumberJS => {\n if (decimals <= 0) {\n return amountRaw;\n }\n const scale = new BigNumberJS(10).pow(decimals);\n if (amountRaw.lt(scale)) {\n return amountRaw;\n }\n return amountRaw.dividedBy(scale);\n};\n\nconst getPriceDatumFast = (\n assetsPrice: AssetsControllerState['assetsPrice'] | undefined,\n assetId: Caip19AssetId,\n): PriceDatum => {\n const raw = assetsPrice?.[assetId];\n if (!raw || typeof raw !== 'object') {\n return ZERO_PRICE;\n }\n const { price, pricePercentChange1d } = raw as {\n price?: unknown;\n pricePercentChange1d?: unknown;\n };\n return {\n price: typeof price === 'number' && Number.isFinite(price) ? price : 0,\n pricePercentChange1d:\n typeof pricePercentChange1d === 'number' &&\n Number.isFinite(pricePercentChange1d)\n ? pricePercentChange1d\n : 0,\n };\n};\n\n/**\n * Enablement lookup optimized:\n * - no array allocations\n * - early returns\n *\n * @param map - Enabled network map (namespace -> storageKey -> boolean)\n * @param id - Chain id as Hex or CAIP-2\n * @returns True if the chain is enabled or map is undefined\n */\nconst isChainEnabledByMap = (\n map: EnabledNetworkMap,\n id: Hex | CaipChainId,\n): boolean => {\n if (!map) {\n return true;\n }\n\n if (isStrictHexString(id)) {\n return Boolean(map[KnownCaipNamespace.Eip155]?.[id]);\n }\n\n const { namespace, reference } = parseCaipChainId(id);\n const namespaceMap = map[namespace];\n if (!namespaceMap) {\n return false;\n }\n\n // exact CAIP-2 id / reference\n if (namespaceMap[id] || namespaceMap[reference]) {\n return true;\n }\n\n // EVM: hex storage key\n if (namespace === KnownCaipNamespace.Eip155) {\n try {\n const storageKey = toHex(reference);\n return Boolean(namespaceMap[storageKey]);\n } catch {\n const parsedRef = Number.parseInt(reference, 10);\n if (Number.isFinite(parsedRef)) {\n return Boolean(namespaceMap[`0x${parsedRef.toString(16)}`]);\n }\n }\n }\n\n return false;\n};\n\n/**\n * Cache parsing results per assetId to avoid parseCaipAssetType/parseCaipChainId\n * being called multiple times across filtering + grouping + pricing.\n */\ntype AssetParseInfo = {\n chainId: CaipChainId;\n isEvm: boolean;\n};\n\nconst makeAssetInfoCache = (): Map<Caip19AssetId, AssetParseInfo> =>\n new Map<Caip19AssetId, AssetParseInfo>();\n\nconst getAssetInfo = (\n cache: Map<Caip19AssetId, AssetParseInfo>,\n assetId: Caip19AssetId,\n): AssetParseInfo => {\n const cached = cache.get(assetId);\n if (cached) {\n return cached;\n }\n const { chainId } = parseCaipAssetType(assetId);\n const { namespace } = parseCaipChainId(chainId);\n const info = { chainId, isEvm: namespace === KnownCaipNamespace.Eip155 };\n cache.set(assetId, info);\n return info;\n};\n\n/**\n * Merge across accounts without building per-account entries arrays.\n * Uses BigNumber for amount accumulation to avoid float precision loss.\n */\ntype AggRow = {\n amount: BigNumberJS;\n decimals?: number;\n symbol?: string;\n name?: string;\n};\n\nfunction mergeBalancesIntoMap(args: {\n out: Map<Caip19AssetId, AggRow>;\n accountBalances: Record<Caip19AssetId, AssetBalance>;\n metadata: Record<Caip19AssetId, AssetMetadata>;\n assetPreferences?: Record<Caip19AssetId, AssetPreferences>;\n enabledNetworkMap?: EnabledNetworkMap;\n assetInfoCache: Map<Caip19AssetId, AssetParseInfo>;\n}): void {\n const {\n out,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n } = args;\n\n for (const assetId in accountBalances) {\n if (!Object.prototype.hasOwnProperty.call(accountBalances, assetId)) {\n continue;\n }\n const typedAssetId = assetId as Caip19AssetId;\n\n if (assetPreferences?.[typedAssetId]?.hidden) {\n continue;\n }\n\n const info = getAssetInfo(assetInfoCache, typedAssetId);\n if (!isChainEnabledByMap(enabledNetworkMap, info.chainId)) {\n continue;\n }\n\n const amountStr = getAmountFromBalance(accountBalances[typedAssetId]);\n let amountBn = toBigNumberOrZero(amountStr);\n const meta = metadata[typedAssetId];\n if (meta?.decimals !== undefined) {\n amountBn = scaleToHumanIfRaw(amountBn, meta.decimals);\n }\n if (amountBn.isZero()) {\n continue; // skip zeros early to reduce map pressure\n }\n\n const existing = out.get(typedAssetId);\n if (existing) {\n existing.amount = existing.amount.plus(amountBn);\n continue;\n }\n\n out.set(typedAssetId, {\n amount: amountBn,\n decimals: meta?.decimals,\n symbol: meta?.symbol,\n name: meta?.name,\n });\n }\n}\n\nexport function getGroupIdForAccount(\n accountTreeState: AccountTreeControllerState,\n accountId: AccountId,\n): string | undefined {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n for (const wallet of Object.values(wallets)) {\n for (const [groupId, group] of Object.entries(wallet?.groups ?? {})) {\n const accounts = group?.accounts;\n if (Array.isArray(accounts) && accounts.includes(accountId)) {\n return groupId;\n }\n }\n }\n return undefined;\n}\n\nexport function getInternalAccountsForGroup(\n accountTreeState: AccountTreeControllerState,\n accountsById: AccountsById,\n groupId: string,\n): InternalAccount[] {\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return [];\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (!group?.accounts) {\n continue;\n }\n const result: InternalAccount[] = [];\n for (const id of group.accounts) {\n const acct = accountsById[id];\n if (acct) {\n result.push(acct);\n }\n }\n return result;\n }\n return [];\n}\n\nfunction getAccountIdsInSameGroup(\n accountTreeState: AccountTreeControllerState,\n selectedAccountId: AccountId,\n): AccountId[] | undefined {\n const groupId = getGroupIdForAccount(accountTreeState, selectedAccountId);\n if (!groupId) {\n return undefined;\n }\n const wallets = accountTreeState.accountTree?.wallets;\n if (!wallets) {\n return undefined;\n }\n type GroupWithAccounts = { accounts?: AccountId[] };\n const getGroups = (\n walletItem: (typeof wallets)[keyof typeof wallets],\n ): Record<string, GroupWithAccounts> =>\n (walletItem?.groups ?? {}) as Record<string, GroupWithAccounts>;\n\n for (const wallet of Object.values(wallets)) {\n const group = getGroups(wallet)[groupId];\n if (group?.accounts) {\n return [...group.accounts];\n }\n }\n return undefined;\n}\n\nfunction resolveAccountsToAggregate(args: {\n selectedInternalAccount: InternalAccount;\n accountTreeState?: AccountTreeControllerState;\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[];\n accountsById?: AccountsById;\n}): AccountLike[] {\n const {\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n } = args;\n\n if (internalAccountsOrAccountIds && internalAccountsOrAccountIds.length > 0) {\n const first = internalAccountsOrAccountIds[0];\n if (typeof first === 'string') {\n const ids = internalAccountsOrAccountIds as AccountId[];\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n return internalAccountsOrAccountIds as InternalAccount[];\n }\n\n if (\n accountTreeState &&\n accountsById &&\n Object.keys(accountsById).length > 0\n ) {\n const groupId = getGroupIdForAccount(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (groupId) {\n const groupAccounts = getInternalAccountsForGroup(\n accountTreeState,\n accountsById,\n groupId,\n );\n if (groupAccounts.length > 0) {\n return groupAccounts;\n }\n }\n }\n\n if (accountTreeState) {\n const ids = getAccountIdsInSameGroup(\n accountTreeState,\n selectedInternalAccount.id,\n );\n if (ids && ids.length > 0) {\n const out: AccountLike[] = new Array(ids.length);\n for (let i = 0; i < ids.length; i++) {\n out[i] = { id: ids[i] };\n }\n return out;\n }\n }\n\n return [selectedInternalAccount];\n}\n\nexport function getAggregatedBalanceForAccount(\n state: AssetsControllerState,\n selectedInternalAccount: InternalAccount,\n enabledNetworkMap?: EnabledNetworkMap,\n accountTreeState?: AccountTreeControllerState,\n internalAccountsOrAccountIds?: InternalAccount[] | AccountId[],\n accountsById?: AccountsById,\n trace?: TraceCallback,\n): AggregatedBalanceForAccount {\n const startTime = trace ? performance.now() : 0;\n const { assetsBalance, assetsInfo, assetPreferences, assetsPrice } = state;\n\n const metadata = (assetsInfo ?? {}) as Record<Caip19AssetId, AssetMetadata>;\n\n const hasPrices =\n Boolean(assetsPrice) &&\n ((): boolean => {\n for (const key in assetsPrice) {\n if (Object.prototype.hasOwnProperty.call(assetsPrice, key)) {\n return true;\n }\n }\n return false;\n })();\n\n const accountsToAggregate = resolveAccountsToAggregate({\n selectedInternalAccount,\n accountTreeState,\n internalAccountsOrAccountIds,\n accountsById,\n });\n\n const assetInfoCache = makeAssetInfoCache();\n const merged = new Map<Caip19AssetId, AggRow>();\n\n for (const account of accountsToAggregate) {\n const accountId = account.id;\n const accountBalances =\n assetsBalance?.[accountId] ?? ({} as Record<Caip19AssetId, AssetBalance>);\n\n mergeBalancesIntoMap({\n out: merged,\n accountBalances,\n metadata,\n assetPreferences,\n enabledNetworkMap,\n assetInfoCache,\n });\n }\n\n // Materialize entries once\n const entries: AggregatedBalanceEntry[] = new Array(merged.size);\n let idx = 0;\n\n // If prices exist, compute totals in a single pass over merged.\n let totalBalanceInFiat = 0;\n let weightedNumerator = 0;\n\n for (const [assetId, row] of merged.entries()) {\n const { amount } = row;\n const entry: AggregatedBalanceEntry = {\n assetId,\n amount: amount.toFixed(),\n ...(row.decimals === undefined ? {} : { decimals: row.decimals }),\n ...(row.symbol === undefined ? {} : { symbol: row.symbol }),\n ...(row.name === undefined ? {} : { name: row.name }),\n };\n entries[idx] = entry;\n idx += 1;\n\n if (hasPrices) {\n const { price, pricePercentChange1d } = getPriceDatumFast(\n assetsPrice,\n assetId,\n );\n const contribution = amount.multipliedBy(price).toNumber();\n if (contribution > 0) {\n totalBalanceInFiat += contribution;\n weightedNumerator += contribution * pricePercentChange1d;\n }\n }\n }\n\n if (trace) {\n const durationMs = performance.now() - startTime;\n const uniqueNetworks = new Set<CaipChainId>();\n for (const assetId of merged.keys()) {\n const info = getAssetInfo(assetInfoCache, assetId);\n uniqueNetworks.add(info.chainId);\n }\n trace(\n {\n name: TRACE_AGGREGATED_BALANCE_SELECTOR,\n data: {\n duration_ms: durationMs,\n asset_count: merged.size,\n network_count: uniqueNetworks.size,\n account_count: accountsToAggregate.length,\n },\n tags: { controller: 'AssetsController' },\n },\n () => undefined,\n ).catch(() => {\n // Telemetry failure must not break.\n });\n }\n\n if (hasPrices) {\n const pricePercentChange1d =\n totalBalanceInFiat > 0 ? weightedNumerator / totalBalanceInFiat : 0;\n return {\n entries,\n totalBalanceInFiat,\n pricePercentChange1d,\n };\n }\n\n return { entries };\n}\n"]}
|
package/package.json
CHANGED