@metamask-previews/assets-controller 19.0.0-preview-9bee3d25c → 19.0.0-preview-c18f4a64e
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
CHANGED
|
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
### Changed
|
|
11
11
|
|
|
12
|
+
- Temporarily extend `SnapDataSource` v6 balance fetches, in a deletable block, to also request every token already stored in balance state for the requested chains, so a rollback to Snaps still refreshes tokens that Accounts API and the websocket already support. Remove that block once balance reads fully move to Accounts API ([#10819](https://github.com/MetaMask/core/pull/10819))
|
|
12
13
|
- Bump `@metamask/keyring-api` from `^24.1.0` to `^24.3.0` ([#10792](https://github.com/MetaMask/core/pull/10792), [#10844](https://github.com/MetaMask/core/pull/10844))
|
|
13
14
|
- Bump `@metamask/keyring-internal-api` from `^12.1.0` to `^12.1.2` ([#10792](https://github.com/MetaMask/core/pull/10792), [#10844](https://github.com/MetaMask/core/pull/10844))
|
|
14
15
|
- Bump `@metamask/keyring-snap-client` from `^10.0.0` to `^10.0.1` ([#10792](https://github.com/MetaMask/core/pull/10792))
|
|
@@ -19,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
19
20
|
- Bump `@metamask/core-backend` from `^12.1.0` to `^12.2.0` ([#10857](https://github.com/MetaMask/core/pull/10857))
|
|
20
21
|
- Poll staked balances every hour instead of every 3 minutes. Subscribe still fetches immediately, and a confirmed transaction that touches the staking contract still refreshes the balance right away ([#10782](https://github.com/MetaMask/core/pull/10782))
|
|
21
22
|
- Remove staked balances from the fast asset pipeline ([#10782](https://github.com/MetaMask/core/pull/10782))
|
|
23
|
+
- Bump `@metamask/base-controller` from `^10.0.0` to `^10.1.0` ([#10864](https://github.com/MetaMask/core/pull/10864))
|
|
24
|
+
- Bump `@metamask/network-controller` from `^37.0.1` to `^37.1.0` ([#10864](https://github.com/MetaMask/core/pull/10864))
|
|
22
25
|
|
|
23
26
|
### Fixed
|
|
24
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapDataSource.d.ts","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SnapDataSource.d.ts","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"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"}
|
|
@@ -381,6 +381,8 @@ export class SnapDataSource extends AbstractDataSource {
|
|
|
381
381
|
// Step 1: Get the list of assets for this account
|
|
382
382
|
const accountAssets = await client.listAccountAssets(accountId);
|
|
383
383
|
const assetsToFetch = this.#selectAssetsToFetchV6(accountAssets ?? [], visibleAssetIds, supportedChainIds, hiddenAssetIds);
|
|
384
|
+
// TEMPORARY: delete this call with `#includeSnapRollbackBalanceStateTokens` after Snaps Migration.
|
|
385
|
+
this.#includeSnapRollbackBalanceStateTokens(accountId, assetsToFetch, supportedChainIds, hiddenAssetIds);
|
|
384
386
|
// Step 2: Get balances for those specific assets. An empty map is a
|
|
385
387
|
// failed fetch (or nothing to ask for), not a zero snapshot. Leave
|
|
386
388
|
// this account out so `full` cannot replace last-known amounts with 0.
|
|
@@ -473,6 +475,61 @@ export class SnapDataSource extends AbstractDataSource {
|
|
|
473
475
|
return Array.from(assetsToFetch.values());
|
|
474
476
|
}
|
|
475
477
|
// ============================================================================
|
|
478
|
+
// TEMPORARY: balance-state tokens while a chain can roll back to Snaps
|
|
479
|
+
//
|
|
480
|
+
// Delete this whole section, and the call marked TEMPORARY in `#fetchV6`,
|
|
481
|
+
// once balance reads fully move to Accounts API.
|
|
482
|
+
//
|
|
483
|
+
// The v6 request is the union of the snap's listed holdings, visible assets,
|
|
484
|
+
// and every token already in balance state for the chain. Accounts API and
|
|
485
|
+
// the websocket already return more tokens than the snap lists, so a rollback
|
|
486
|
+
// to the snap still refreshes that wider set. This section adds the
|
|
487
|
+
// balance-state part. Hidden assets stay out. Visible assets stay in the
|
|
488
|
+
// request even when they have no balance entry yet.
|
|
489
|
+
// ============================================================================
|
|
490
|
+
/**
|
|
491
|
+
* Append balance-state tokens for these chains onto the v6 request.
|
|
492
|
+
* Tokens already selected, hidden, or on another chain are left out.
|
|
493
|
+
*
|
|
494
|
+
* @param accountId - Account whose balances are being fetched.
|
|
495
|
+
* @param assetsToFetch - Asset IDs already chosen, mutated in place.
|
|
496
|
+
* @param supportedChainIds - Chains this snap was asked about.
|
|
497
|
+
* @param hiddenAssetIds - Asset IDs the user hid in this scope.
|
|
498
|
+
*/
|
|
499
|
+
#includeSnapRollbackBalanceStateTokens(accountId, assetsToFetch, supportedChainIds, hiddenAssetIds) {
|
|
500
|
+
const supportedChains = new Set(supportedChainIds);
|
|
501
|
+
const hidden = new Set(hiddenAssetIds.map((assetId) => assetId.toLowerCase()));
|
|
502
|
+
const present = new Set(assetsToFetch.map((assetId) => assetId.toLowerCase()));
|
|
503
|
+
const balanceAssetIds = Object.keys(this.#getAssetsState().assetsBalance[accountId] ?? {});
|
|
504
|
+
for (const assetId of balanceAssetIds) {
|
|
505
|
+
const normalizedAssetId = assetId.toLowerCase();
|
|
506
|
+
if (present.has(normalizedAssetId) || hidden.has(normalizedAssetId)) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (!this.#isSnapRollbackAssetOnChains(assetId, supportedChains)) {
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
present.add(normalizedAssetId);
|
|
513
|
+
assetsToFetch.push(assetId);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Whether an asset ID belongs to one of the chains in this request.
|
|
518
|
+
* Unparseable IDs are treated as out of scope.
|
|
519
|
+
*
|
|
520
|
+
* @param assetId - CAIP-19 asset ID.
|
|
521
|
+
* @param supportedChains - Chains this snap was asked about.
|
|
522
|
+
* @returns True when the asset's chain is in scope.
|
|
523
|
+
*/
|
|
524
|
+
#isSnapRollbackAssetOnChains(assetId, supportedChains) {
|
|
525
|
+
try {
|
|
526
|
+
return supportedChains.has(extractChainFromAssetId(assetId));
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// ============================================================================
|
|
476
533
|
// MIDDLEWARE
|
|
477
534
|
// ============================================================================
|
|
478
535
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapDataSource.js","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Balance, CaipAssetType } from '@metamask/keyring-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type {\n Caveat,\n GetPermissions,\n PermissionConstraint,\n PermissionControllerStateChange,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapInstalledEvent,\n} from '@metamask/snaps-controllers';\nimport type { Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType, SnapCaveatType } from '@metamask/snaps-utils';\nimport { parseCaipAssetType } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController.js';\nimport { projectLogger, createModuleLogger } from '../logger.js';\nimport type {\n AssetBalance,\n AssetsControllerState,\n ChainId,\n Caip19AssetId,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types.js';\nimport type { GetAssetVisibility } from '../utils/assetVisibility.js';\nimport { getZeroAssetBalance } from '../utils/getZeroAssetBalance.js';\nimport { AbstractDataSource } from './AbstractDataSource.js';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource.js';\n\n// ============================================================================\n// SNAP KEYRING EVENT TYPES\n// ============================================================================\n\n/**\n * Payload for AccountsController:accountBalancesUpdated event.\n * Re-published from SnapKeyring:accountBalancesUpdated.\n */\nexport type AccountBalancesUpdatedEventPayload = {\n balances: {\n [accountId: string]: {\n [assetId: string]: {\n amount: string;\n unit: string;\n metadata?: Record<string, Json>;\n };\n };\n };\n};\n\n/**\n * Event from AccountsController when snap balances are updated.\n */\nexport type AccountsControllerAccountBalancesUpdatedEvent = {\n type: 'AccountsController:accountBalancesUpdated';\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nconst log = createModuleLogger(projectLogger, 'SnapDataSource');\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nexport const SNAP_DATA_SOURCE_NAME = 'SnapDataSource';\n\n/** The permission name for snap keyring endowment */\nexport const KEYRING_PERMISSION = 'endowment:keyring';\n\n/** The permission name for snap assets endowment (contains chainIds) */\nexport const ASSETS_PERMISSION = 'endowment:assets';\n\n// ============================================================================\n// PERMISSION UTILITIES\n// ============================================================================\n\n/**\n * Getter function to get the chainIds caveat from a permission.\n *\n * This does basic validation of the caveat, but does not validate the type or\n * value of the namespaces object itself, as this is handled by the\n * `PermissionsController` when the permission is requested.\n *\n * @param permission - The permission to get the `chainIds` caveat from.\n * @returns An array of `chainIds` that the snap supports, or null if none.\n */\nexport function getChainIdsCaveat(\n permission?: PermissionConstraint,\n): ChainId[] | null {\n if (!permission?.caveats) {\n return null;\n }\n\n const caveat = permission.caveats.find(\n (permCaveat) => permCaveat.type === SnapCaveatType.ChainIds,\n ) as Caveat<string, string[]> | undefined;\n\n return caveat ? (caveat.value as ChainId[]) : null;\n}\n\n/**\n * Extracts the CAIP-2 chain ID from a CAIP-19 asset ID.\n * e.g., \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501\" -> \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\"\n * Uses @metamask/utils parseCaipAssetType for CAIP parsing.\n *\n * @param assetId - The CAIP-19 asset ID to extract chain from.\n * @returns The CAIP-2 chain ID portion of the asset ID.\n */\nexport function extractChainFromAssetId(assetId: string): ChainId {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n return parsed.chainId;\n}\n\n// ============================================================================\n// STATE\n// ============================================================================\n\n/**\n * State for the SnapDataSource.\n * Uses dynamic snap discovery - chains are populated from PermissionController.\n */\nexport type SnapDataSourceState = {\n /**\n * Mapping of chain IDs to snap IDs that support them.\n * Used to filter which accounts to process for a given chain request.\n */\n chainToSnap: Record<ChainId, string>;\n} & DataSourceState;\n\nconst defaultSnapState: SnapDataSourceState = {\n activeChains: [],\n chainToSnap: {},\n};\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Allowed events that SnapDataSource can subscribe to.\n */\nexport type SnapDataSourceAllowedEvents =\n | AccountsControllerAccountBalancesUpdatedEvent\n | PermissionControllerStateChange\n | SnapControllerSnapInstalledEvent;\n\nexport type SnapDataSourceAllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type SnapDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when this data source's active chains change. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /**\n * Called directly with snap-sourced balance updates (from\n * AccountsController:accountBalancesUpdated), independent of whether the\n * controller currently has an active subscription for the chain.\n */\n onAssetsUpdate: (response: DataResponse) => void | Promise<void>;\n /** Whether authoritative v6 balance snapshots are enabled. */\n isBalanceV6Enabled: () => boolean;\n /** Resolves native, pinned, default, and hidden assets for a request scope. */\n getAssetVisibility: GetAssetVisibility;\n /**\n * Current AssetsController state. Used to keep the last-known amount when\n * a v6 snap snapshot omits a visible asset.\n */\n getAssetsState: () => AssetsControllerState;\n /** Configured networks to support (defaults to all snap networks) */\n configuredNetworks?: ChainId[];\n /** Default polling interval in ms for subscriptions */\n pollInterval?: number;\n /** Initial state */\n state?: Partial<SnapDataSourceState>;\n};\n\n// ============================================================================\n// SNAP DATA SOURCE\n// ============================================================================\n\n/**\n * Unified Snap data source that routes requests to the appropriate wallet snap\n * based on the chain ID prefix.\n *\n * @example\n * ```typescript\n * const snapDataSource = new SnapDataSource({\n * messenger,\n * onActiveChainsUpdated: (chains) => { /* ... *\\/ },\n * });\n *\n * // Fetch will automatically route to the correct snap\n * await snapDataSource.fetch({\n * chainIds: ['solana:mainnet', 'bip122:000000000019d6689c085ae165831e93'],\n * accountIds: ['account1'],\n * });\n * ```\n */\nexport class SnapDataSource extends AbstractDataSource<\n typeof SNAP_DATA_SOURCE_NAME,\n SnapDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #onAssetsUpdate: (response: DataResponse) => void | Promise<void>;\n\n readonly #isBalanceV6Enabled: () => boolean;\n\n readonly #getAssetVisibility: GetAssetVisibility;\n\n readonly #getAssetsState: () => AssetsControllerState;\n\n /** Bound handler for snap keyring balance updates, stored for cleanup */\n readonly #handleSnapBalancesUpdatedBound: (\n payload: AccountBalancesUpdatedEventPayload,\n ) => void;\n\n readonly #handlePermissionStateChangeBound: () => void;\n\n /** Cache of KeyringClient instances per snap ID to avoid re-instantiation */\n readonly #keyringClientCache: Map<string, KeyringClient> = new Map();\n\n constructor(options: SnapDataSourceOptions) {\n super(SNAP_DATA_SOURCE_NAME, {\n ...defaultSnapState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#onAssetsUpdate = options.onAssetsUpdate;\n this.#isBalanceV6Enabled = options.isBalanceV6Enabled;\n this.#getAssetVisibility = options.getAssetVisibility;\n this.#getAssetsState = options.getAssetsState;\n\n // Bind handlers for cleanup in destroy()\n this.#handleSnapBalancesUpdatedBound =\n this.#handleSnapBalancesUpdated.bind(this);\n this.#handlePermissionStateChangeBound =\n this.#discoverKeyringSnaps.bind(this);\n\n this.#subscribeToEvents();\n\n // Discover keyring-capable snaps and populate activeChains dynamically\n this.#discoverKeyringSnaps();\n }\n\n /**\n * Subscribe to all events needed by SnapDataSource.\n * Groups snap keyring events and permission change events.\n */\n #subscribeToEvents(): void {\n // Subscribe to snap keyring events and permission changes (not in AssetsControllerEvents).\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n messenger.subscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n // Rediscover keyring snaps when any snap gets installed\n messenger.subscribe('SnapController:snapInstalled', () => {\n this.#discoverKeyringSnaps();\n });\n }\n\n /**\n * Handle snap balance updates from the keyring.\n * Transforms the payload and publishes to AssetsController.\n *\n * @param payload - The balance update payload from AccountsController.\n */\n #handleSnapBalancesUpdated(\n payload: AccountBalancesUpdatedEventPayload,\n ): void {\n // Transform the snap keyring payload to DataResponse format\n let assetsBalance: NonNullable<DataResponse['assetsBalance']> | undefined;\n\n for (const [accountId, assets] of Object.entries(payload.balances)) {\n let accountAssets: Record<Caip19AssetId, AssetBalance> | undefined;\n\n for (const [assetId, balance] of Object.entries(assets)) {\n let chainId: ChainId;\n try {\n chainId = extractChainFromAssetId(assetId);\n } catch (error) {\n log('Skipping snap balance for malformed asset ID', {\n assetId,\n error,\n });\n continue;\n }\n if (this.#isChainSupportedBySnap(chainId)) {\n accountAssets ??= {};\n accountAssets[assetId as Caip19AssetId] = {\n amount: balance.amount,\n ...(balance.metadata ? { metadata: balance.metadata } : {}),\n };\n }\n }\n\n if (accountAssets) {\n assetsBalance ??= {};\n assetsBalance[accountId] = accountAssets;\n }\n }\n\n // Only report if we have snap-related updates\n if (assetsBalance) {\n const response: DataResponse = { assetsBalance, updateMode: 'merge' };\n Promise.resolve(this.#onAssetsUpdate(response)).catch(console.error);\n }\n }\n\n /**\n * Check if a chain ID is supported by any discovered snap.\n *\n * @param chainId - The CAIP-2 chain ID to check.\n * @returns True if we have a snap that supports this chain.\n */\n #isChainSupportedBySnap(chainId: ChainId): boolean {\n return this.state.activeChains.includes(chainId);\n }\n\n // ============================================================================\n // SNAP DISCOVERY (Dynamic via PermissionController)\n // ============================================================================\n\n /**\n * Get all runnable snaps from SnapController.\n * Runnable snaps are enabled and not blocked.\n *\n * @returns Array of runnable snaps.\n */\n #getRunnableSnaps(): Snap[] {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'SnapController:getRunnableSnaps',\n ) as Snap[];\n } catch (error) {\n log('Failed to get runnable snaps', error);\n return [];\n }\n }\n\n /**\n * Get permissions for a snap from PermissionController.\n *\n * @param snapId - The snap ID to get permissions for.\n * @returns The snap's permissions, or undefined if none.\n */\n #getSnapPermissions(\n snapId: string,\n ): SubjectPermissions<PermissionConstraint> | undefined {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'PermissionController:getPermissions',\n snapId,\n ) as SubjectPermissions<PermissionConstraint>;\n } catch (error) {\n log('Failed to get permissions for snap', { snapId, error });\n return undefined;\n }\n }\n\n /**\n * Discover all snaps with keyring capabilities and their supported chains.\n * Uses PermissionController to find snaps with endowment:keyring permission.\n * Updates chainToSnap mapping and activeChains.\n *\n * Called on initialization and whenever PermissionController state changes\n * (e.g., new snaps installed, permissions granted/revoked).\n *\n * @remarks\n * **Known limitation:** If discovery fails (e.g., SnapController not ready),\n * the data source continues with empty chainToSnap. This means no snap\n * chains will be supported until a re-discovery is triggered by a permission\n * change. Callers should be aware that initialization may complete with no\n * active chains.\n */\n #discoverKeyringSnaps(): void {\n try {\n const runnableSnaps = this.#getRunnableSnaps();\n const chainToSnap: Record<ChainId, string> = {};\n const supportedChains: ChainId[] = [];\n\n for (const snap of runnableSnaps) {\n const permissions = this.#getSnapPermissions(snap.id);\n // Must have endowment:keyring permission to be a keyring snap\n if (!permissions?.[KEYRING_PERMISSION]) {\n continue;\n }\n\n // Get chainIds caveat from the assets permission (not keyring permission)\n // The chainIds are stored in endowment:assets\n const assetsPermission = permissions[ASSETS_PERMISSION];\n const chainIds = getChainIdsCaveat(assetsPermission);\n\n // Map each chain to this snap (first snap wins if multiple support same chain)\n if (chainIds) {\n for (const chainId of chainIds) {\n if (!(chainId in chainToSnap)) {\n chainToSnap[chainId] = snap.id;\n supportedChains.push(chainId);\n }\n }\n }\n }\n\n // Update chainToSnap mapping\n this.state.chainToSnap = chainToSnap;\n\n // Notify if chains changed\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(supportedChains, (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n } catch (error) {\n log('Keyring snap discovery failed', { error });\n this.state.chainToSnap = {};\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains([], (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n // Guard against undefined request\n // Note: chainIds filtering is done by middleware/subscribe before calling fetch\n if (!request?.chainIds?.length) {\n return {};\n }\n\n if (this.#isBalanceV6Enabled()) {\n return this.#fetchV6(request);\n }\n\n return this.#fetchV5(request);\n }\n\n /**\n * v5 fetch. Unchanged from the pre-v6 handler; delete the v6 sibling first\n * if `assetsAccountsApiV6` is rolled back.\n *\n * @param request - The data request.\n * @returns Overlay (`merge`) balances from the snap keyring.\n */\n async #fetchV5(request: DataRequest): Promise<DataResponse> {\n if (!request?.accountsWithSupportedChains?.length) {\n return { assetsBalance: {}, assetsInfo: {}, updateMode: 'merge' };\n }\n\n const results: DataResponse = {\n assetsBalance: {},\n assetsInfo: {},\n updateMode: 'merge',\n };\n\n // Fetch balances for each account using its snap ID from metadata\n for (const { account } of request.accountsWithSupportedChains) {\n // Skip accounts without snap metadata (non-snap accounts)\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n continue;\n }\n\n // Skip accounts whose snap doesn't support any of the requested chains\n const snapSupportsRequestedChains = request.chainIds.some(\n (chainId) => this.state.chainToSnap[chainId] === snapId,\n );\n if (!snapSupportsRequestedChains) {\n continue;\n }\n\n const accountId = account.id;\n try {\n const client = this.#getKeyringClient(snapId);\n\n // Step 1: Get the list of assets for this account\n const accountAssets = await client.listAccountAssets(accountId);\n\n // If no assets, skip to next account\n if (!accountAssets || accountAssets.length === 0) {\n continue;\n }\n\n // Step 2: Get balances for those specific assets\n const balances: Record<CaipAssetType, Balance> =\n await client.getAccountBalances(accountId, accountAssets);\n\n // Transform keyring response to DataResponse format\n if (balances && typeof balances === 'object' && results.assetsBalance) {\n for (const [assetId, balance] of Object.entries(balances)) {\n results.assetsBalance[accountId] ??= {};\n const accountBalances = results.assetsBalance[accountId];\n if (accountBalances) {\n (accountBalances as Record<string, unknown>)[assetId] = {\n amount: balance.amount,\n ...(balance.metadata ? { metadata: balance.metadata } : {}),\n };\n }\n }\n }\n } catch {\n // Expected when account doesn't belong to this snap\n }\n }\n\n return results;\n }\n\n /**\n * v6 fetch: a complete snapshot of the requested account-chain slices.\n * Listed holdings and expected visible assets (native, pin, default\n * tracked) are requested together. Hidden assets are left out entirely.\n * Delete with the rest of the v6 path if `assetsAccountsApiV6` is rolled\n * back.\n *\n * @param request - The data request.\n * @returns Authoritative (`full`) balances for the requested slices.\n */\n async #fetchV6(request: DataRequest): Promise<DataResponse> {\n if (!request?.accountsWithSupportedChains?.length) {\n return { assetsBalance: {}, assetsInfo: {}, updateMode: 'full' };\n }\n\n const results: DataResponse = {\n assetsBalance: {},\n assetsInfo: {},\n updateMode: 'full',\n };\n\n // Fetch balances for each account using its snap ID from metadata\n for (const { account } of request.accountsWithSupportedChains) {\n // Skip accounts without snap metadata (non-snap accounts)\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n continue;\n }\n\n // Skip accounts whose snap doesn't support any of the requested chains\n const supportedChainIds = request.chainIds.filter(\n (chainId) => this.state.chainToSnap[chainId] === snapId,\n );\n if (supportedChainIds.length === 0) {\n continue;\n }\n\n const accountId = account.id;\n try {\n const client = this.#getKeyringClient(snapId);\n const { visibleAssetIds, hiddenAssetIds } = this.#getAssetVisibility(\n [accountId],\n supportedChainIds,\n );\n\n // Step 1: Get the list of assets for this account\n const accountAssets = await client.listAccountAssets(accountId);\n const assetsToFetch = this.#selectAssetsToFetchV6(\n accountAssets ?? [],\n visibleAssetIds,\n supportedChainIds,\n hiddenAssetIds,\n );\n\n // Step 2: Get balances for those specific assets. An empty map is a\n // failed fetch (or nothing to ask for), not a zero snapshot. Leave\n // this account out so `full` cannot replace last-known amounts with 0.\n const balances: Record<CaipAssetType, Balance> = assetsToFetch.length\n ? await client.getAccountBalances(accountId, assetsToFetch)\n : {};\n if (\n !balances ||\n typeof balances !== 'object' ||\n Object.keys(balances).length === 0\n ) {\n continue;\n }\n\n // Transform keyring response to DataResponse format\n const accountBalances: Record<string, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(balances)) {\n accountBalances[assetId] = {\n amount: balance.amount,\n ...(balance.metadata ? { metadata: balance.metadata } : {}),\n };\n }\n\n // Step 3: Guard against an incomplete snap response. A `full` replace\n // would drop any expected visible asset that was requested but omitted.\n // Keep the last-known amount when we have one; otherwise seed 0.\n this.#fillOmittedVisibleAssets(\n accountId,\n visibleAssetIds,\n accountBalances,\n );\n\n if (results.assetsBalance) {\n results.assetsBalance[accountId] = accountBalances;\n }\n } catch {\n // Snap failed or the account does not belong to this snap. Contribute\n // nothing so previous balances stay in state.\n }\n }\n\n return results;\n }\n\n /**\n * Put every omitted visible asset on the snapshot so `full` cannot drop it.\n * Reuse the amount already in state when one exists; otherwise seed `0`.\n *\n * @param accountId - Account whose balances were fetched.\n * @param visibleAssetIds - Native, pin, and default tracked IDs for this scope.\n * @param accountBalances - Snapshot being built, mutated in place.\n */\n #fillOmittedVisibleAssets(\n accountId: string,\n visibleAssetIds: Caip19AssetId[],\n accountBalances: Record<string, AssetBalance>,\n ): void {\n const previousByKey = new Map(\n Object.entries(this.#getAssetsState().assetsBalance[accountId] ?? {}).map(\n ([assetId, balance]) => [assetId.toLowerCase(), balance],\n ),\n );\n const presentKeys = new Set(\n Object.keys(accountBalances).map((assetId) => assetId.toLowerCase()),\n );\n\n for (const assetId of visibleAssetIds) {\n if (presentKeys.has(assetId.toLowerCase())) {\n continue;\n }\n\n const previous = previousByKey.get(assetId.toLowerCase());\n if (previous) {\n accountBalances[assetId] = { ...previous };\n continue;\n }\n\n accountBalances[assetId] = getZeroAssetBalance(assetId);\n }\n }\n\n /**\n * Union the snap's listed holdings with expected visible assets (native,\n * pin, default tracked), limited to the requested chains. Hidden assets\n * are dropped so they are neither fetched nor written back to state.\n *\n * @param accountAssets - Asset IDs the snap listed for the account.\n * @param visibleAssetIds - Native, pin, and default tracked IDs for this scope.\n * @param supportedChainIds - Chains this snap was asked about.\n * @param hiddenAssetIds - Asset IDs the user hid in this scope.\n * @returns Asset IDs to request balances for.\n */\n #selectAssetsToFetchV6(\n accountAssets: string[],\n visibleAssetIds: Caip19AssetId[],\n supportedChainIds: ChainId[],\n hiddenAssetIds: Caip19AssetId[],\n ): CaipAssetType[] {\n const supportedChains = new Set(supportedChainIds);\n const hidden = new Set(\n hiddenAssetIds.map((assetId) => assetId.toLowerCase()),\n );\n const assetsToFetch = new Map<string, CaipAssetType>();\n\n for (const assetId of [...accountAssets, ...visibleAssetIds]) {\n const normalizedAssetId = assetId.toLowerCase();\n if (\n assetsToFetch.has(normalizedAssetId) ||\n hidden.has(normalizedAssetId)\n ) {\n continue;\n }\n\n try {\n if (!supportedChains.has(extractChainFromAssetId(assetId))) {\n continue;\n }\n } catch {\n // Skip unparseable asset IDs\n continue;\n }\n\n assetsToFetch.set(normalizedAssetId, assetId as CaipAssetType);\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Snaps.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Filters request to only chains this data source supports\n * - Fetches balances for those chains for all accounts\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // Filter to chains this data source supports\n const supportedChains = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n // If no supported chains, skip and pass to next middleware\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n // Fetch for supported chains\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n // Merge response into context\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n if (response.assetsInfo) {\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n if (response.assetsPrice) {\n context.response.assetsPrice = {\n ...context.response.assetsPrice,\n ...response.assetsPrice,\n };\n }\n if (response.updateMode) {\n context.response = {\n ...context.response,\n updateMode: response.updateMode,\n };\n }\n\n // Determine successfully handled chains (exclude errors)\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Prepare context for next middleware\n let nextContext = context;\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n nextContext = {\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n };\n }\n\n // Call next middleware\n return next(nextContext);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE - Routes to appropriate snap(s)\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId } = subscriptionRequest;\n\n // Guard against undefined request or chainIds\n if (!request?.chainIds) {\n return;\n }\n\n // Filter to chains we have a snap for\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#isChainSupportedBySnap(chainId),\n );\n\n if (supportedChains.length === 0) {\n return;\n }\n\n try {\n const fetchResponse = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n if (Object.keys(fetchResponse.assetsBalance ?? {}).length > 0) {\n await this.#onAssetsUpdate(fetchResponse);\n }\n } catch (error) {\n log('Initial fetch failed', { subscriptionId, error });\n }\n }\n\n // ============================================================================\n // KEYRING CLIENT\n // ============================================================================\n\n /**\n * Gets a `KeyringClient` for a Snap.\n * Caches clients per snap ID to avoid re-instantiation across multiple calls.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getKeyringClient(snapId: string): KeyringClient {\n const cachedClient = this.#keyringClientCache.get(snapId);\n if (cachedClient) {\n return cachedClient;\n }\n\n const client = new KeyringClient({\n send: async (request: JsonRpcRequest): Promise<Json> =>\n await (\n this.#messenger as unknown as {\n call: (action: string, ...args: unknown[]) => Promise<Json> | Json;\n }\n ).call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n }),\n });\n\n this.#keyringClientCache.set(snapId, client);\n return client;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n // Unsubscribe from snap keyring events\n try {\n messenger.unsubscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from snap keyring events', { error });\n }\n\n // Unsubscribe from permission changes\n try {\n messenger.unsubscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from permission changes', { error });\n }\n\n // Clear keyring client cache\n this.#keyringClientCache.clear();\n }\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\nexport function createSnapDataSource(\n options: SnapDataSourceOptions,\n): SnapDataSource {\n return new SnapDataSource(options);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SnapDataSource.js","sourceRoot":"","sources":["../../src/data-sources/SnapDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Balance, CaipAssetType } from '@metamask/keyring-api';\nimport { KeyringClient } from '@metamask/keyring-snap-client';\nimport type {\n Caveat,\n GetPermissions,\n PermissionConstraint,\n PermissionControllerStateChange,\n SubjectPermissions,\n} from '@metamask/permission-controller';\nimport type {\n SnapControllerGetRunnableSnapsAction,\n SnapControllerHandleRequestAction,\n SnapControllerSnapInstalledEvent,\n} from '@metamask/snaps-controllers';\nimport type { Snap, SnapId } from '@metamask/snaps-sdk';\nimport { HandlerType, SnapCaveatType } from '@metamask/snaps-utils';\nimport { parseCaipAssetType } from '@metamask/utils';\nimport type { Json, JsonRpcRequest } from '@metamask/utils';\n\nimport type { AssetsControllerMessenger } from '../AssetsController.js';\nimport { projectLogger, createModuleLogger } from '../logger.js';\nimport type {\n AssetBalance,\n AssetsControllerState,\n ChainId,\n Caip19AssetId,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types.js';\nimport type { GetAssetVisibility } from '../utils/assetVisibility.js';\nimport { getZeroAssetBalance } from '../utils/getZeroAssetBalance.js';\nimport { AbstractDataSource } from './AbstractDataSource.js';\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource.js';\n\n// ============================================================================\n// SNAP KEYRING EVENT TYPES\n// ============================================================================\n\n/**\n * Payload for AccountsController:accountBalancesUpdated event.\n * Re-published from SnapKeyring:accountBalancesUpdated.\n */\nexport type AccountBalancesUpdatedEventPayload = {\n balances: {\n [accountId: string]: {\n [assetId: string]: {\n amount: string;\n unit: string;\n metadata?: Record<string, Json>;\n };\n };\n };\n};\n\n/**\n * Event from AccountsController when snap balances are updated.\n */\nexport type AccountsControllerAccountBalancesUpdatedEvent = {\n type: 'AccountsController:accountBalancesUpdated';\n payload: [AccountBalancesUpdatedEventPayload];\n};\n\nconst log = createModuleLogger(projectLogger, 'SnapDataSource');\n\n// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nexport const SNAP_DATA_SOURCE_NAME = 'SnapDataSource';\n\n/** The permission name for snap keyring endowment */\nexport const KEYRING_PERMISSION = 'endowment:keyring';\n\n/** The permission name for snap assets endowment (contains chainIds) */\nexport const ASSETS_PERMISSION = 'endowment:assets';\n\n// ============================================================================\n// PERMISSION UTILITIES\n// ============================================================================\n\n/**\n * Getter function to get the chainIds caveat from a permission.\n *\n * This does basic validation of the caveat, but does not validate the type or\n * value of the namespaces object itself, as this is handled by the\n * `PermissionsController` when the permission is requested.\n *\n * @param permission - The permission to get the `chainIds` caveat from.\n * @returns An array of `chainIds` that the snap supports, or null if none.\n */\nexport function getChainIdsCaveat(\n permission?: PermissionConstraint,\n): ChainId[] | null {\n if (!permission?.caveats) {\n return null;\n }\n\n const caveat = permission.caveats.find(\n (permCaveat) => permCaveat.type === SnapCaveatType.ChainIds,\n ) as Caveat<string, string[]> | undefined;\n\n return caveat ? (caveat.value as ChainId[]) : null;\n}\n\n/**\n * Extracts the CAIP-2 chain ID from a CAIP-19 asset ID.\n * e.g., \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501\" -> \"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\"\n * Uses @metamask/utils parseCaipAssetType for CAIP parsing.\n *\n * @param assetId - The CAIP-19 asset ID to extract chain from.\n * @returns The CAIP-2 chain ID portion of the asset ID.\n */\nexport function extractChainFromAssetId(assetId: string): ChainId {\n const parsed = parseCaipAssetType(assetId as CaipAssetType);\n return parsed.chainId;\n}\n\n// ============================================================================\n// STATE\n// ============================================================================\n\n/**\n * State for the SnapDataSource.\n * Uses dynamic snap discovery - chains are populated from PermissionController.\n */\nexport type SnapDataSourceState = {\n /**\n * Mapping of chain IDs to snap IDs that support them.\n * Used to filter which accounts to process for a given chain request.\n */\n chainToSnap: Record<ChainId, string>;\n} & DataSourceState;\n\nconst defaultSnapState: SnapDataSourceState = {\n activeChains: [],\n chainToSnap: {},\n};\n\n// ============================================================================\n// MESSENGER TYPES\n// ============================================================================\n\n/**\n * Allowed events that SnapDataSource can subscribe to.\n */\nexport type SnapDataSourceAllowedEvents =\n | AccountsControllerAccountBalancesUpdatedEvent\n | PermissionControllerStateChange\n | SnapControllerSnapInstalledEvent;\n\nexport type SnapDataSourceAllowedActions =\n | SnapControllerGetRunnableSnapsAction\n | SnapControllerHandleRequestAction\n | GetPermissions;\n\n// ============================================================================\n// OPTIONS\n// ============================================================================\n\nexport type SnapDataSourceOptions = {\n /** The AssetsController messenger (shared by all data sources). */\n messenger: AssetsControllerMessenger;\n /** Called when this data source's active chains change. Pass dataSourceName so the controller knows the source. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n /**\n * Called directly with snap-sourced balance updates (from\n * AccountsController:accountBalancesUpdated), independent of whether the\n * controller currently has an active subscription for the chain.\n */\n onAssetsUpdate: (response: DataResponse) => void | Promise<void>;\n /** Whether authoritative v6 balance snapshots are enabled. */\n isBalanceV6Enabled: () => boolean;\n /** Resolves native, pinned, default, and hidden assets for a request scope. */\n getAssetVisibility: GetAssetVisibility;\n /**\n * Current AssetsController state. Used to keep the last-known amount when\n * a v6 snap snapshot omits a visible asset.\n */\n getAssetsState: () => AssetsControllerState;\n /** Configured networks to support (defaults to all snap networks) */\n configuredNetworks?: ChainId[];\n /** Default polling interval in ms for subscriptions */\n pollInterval?: number;\n /** Initial state */\n state?: Partial<SnapDataSourceState>;\n};\n\n// ============================================================================\n// SNAP DATA SOURCE\n// ============================================================================\n\n/**\n * Unified Snap data source that routes requests to the appropriate wallet snap\n * based on the chain ID prefix.\n *\n * @example\n * ```typescript\n * const snapDataSource = new SnapDataSource({\n * messenger,\n * onActiveChainsUpdated: (chains) => { /* ... *\\/ },\n * });\n *\n * // Fetch will automatically route to the correct snap\n * await snapDataSource.fetch({\n * chainIds: ['solana:mainnet', 'bip122:000000000019d6689c085ae165831e93'],\n * accountIds: ['account1'],\n * });\n * ```\n */\nexport class SnapDataSource extends AbstractDataSource<\n typeof SNAP_DATA_SOURCE_NAME,\n SnapDataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #onAssetsUpdate: (response: DataResponse) => void | Promise<void>;\n\n readonly #isBalanceV6Enabled: () => boolean;\n\n readonly #getAssetVisibility: GetAssetVisibility;\n\n readonly #getAssetsState: () => AssetsControllerState;\n\n /** Bound handler for snap keyring balance updates, stored for cleanup */\n readonly #handleSnapBalancesUpdatedBound: (\n payload: AccountBalancesUpdatedEventPayload,\n ) => void;\n\n readonly #handlePermissionStateChangeBound: () => void;\n\n /** Cache of KeyringClient instances per snap ID to avoid re-instantiation */\n readonly #keyringClientCache: Map<string, KeyringClient> = new Map();\n\n constructor(options: SnapDataSourceOptions) {\n super(SNAP_DATA_SOURCE_NAME, {\n ...defaultSnapState,\n ...options.state,\n });\n\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#onAssetsUpdate = options.onAssetsUpdate;\n this.#isBalanceV6Enabled = options.isBalanceV6Enabled;\n this.#getAssetVisibility = options.getAssetVisibility;\n this.#getAssetsState = options.getAssetsState;\n\n // Bind handlers for cleanup in destroy()\n this.#handleSnapBalancesUpdatedBound =\n this.#handleSnapBalancesUpdated.bind(this);\n this.#handlePermissionStateChangeBound =\n this.#discoverKeyringSnaps.bind(this);\n\n this.#subscribeToEvents();\n\n // Discover keyring-capable snaps and populate activeChains dynamically\n this.#discoverKeyringSnaps();\n }\n\n /**\n * Subscribe to all events needed by SnapDataSource.\n * Groups snap keyring events and permission change events.\n */\n #subscribeToEvents(): void {\n // Subscribe to snap keyring events and permission changes (not in AssetsControllerEvents).\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n messenger.subscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n messenger.subscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n // Rediscover keyring snaps when any snap gets installed\n messenger.subscribe('SnapController:snapInstalled', () => {\n this.#discoverKeyringSnaps();\n });\n }\n\n /**\n * Handle snap balance updates from the keyring.\n * Transforms the payload and publishes to AssetsController.\n *\n * @param payload - The balance update payload from AccountsController.\n */\n #handleSnapBalancesUpdated(\n payload: AccountBalancesUpdatedEventPayload,\n ): void {\n // Transform the snap keyring payload to DataResponse format\n let assetsBalance: NonNullable<DataResponse['assetsBalance']> | undefined;\n\n for (const [accountId, assets] of Object.entries(payload.balances)) {\n let accountAssets: Record<Caip19AssetId, AssetBalance> | undefined;\n\n for (const [assetId, balance] of Object.entries(assets)) {\n let chainId: ChainId;\n try {\n chainId = extractChainFromAssetId(assetId);\n } catch (error) {\n log('Skipping snap balance for malformed asset ID', {\n assetId,\n error,\n });\n continue;\n }\n if (this.#isChainSupportedBySnap(chainId)) {\n accountAssets ??= {};\n accountAssets[assetId as Caip19AssetId] = {\n amount: balance.amount,\n ...(balance.metadata ? { metadata: balance.metadata } : {}),\n };\n }\n }\n\n if (accountAssets) {\n assetsBalance ??= {};\n assetsBalance[accountId] = accountAssets;\n }\n }\n\n // Only report if we have snap-related updates\n if (assetsBalance) {\n const response: DataResponse = { assetsBalance, updateMode: 'merge' };\n Promise.resolve(this.#onAssetsUpdate(response)).catch(console.error);\n }\n }\n\n /**\n * Check if a chain ID is supported by any discovered snap.\n *\n * @param chainId - The CAIP-2 chain ID to check.\n * @returns True if we have a snap that supports this chain.\n */\n #isChainSupportedBySnap(chainId: ChainId): boolean {\n return this.state.activeChains.includes(chainId);\n }\n\n // ============================================================================\n // SNAP DISCOVERY (Dynamic via PermissionController)\n // ============================================================================\n\n /**\n * Get all runnable snaps from SnapController.\n * Runnable snaps are enabled and not blocked.\n *\n * @returns Array of runnable snaps.\n */\n #getRunnableSnaps(): Snap[] {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'SnapController:getRunnableSnaps',\n ) as Snap[];\n } catch (error) {\n log('Failed to get runnable snaps', error);\n return [];\n }\n }\n\n /**\n * Get permissions for a snap from PermissionController.\n *\n * @param snapId - The snap ID to get permissions for.\n * @returns The snap's permissions, or undefined if none.\n */\n #getSnapPermissions(\n snapId: string,\n ): SubjectPermissions<PermissionConstraint> | undefined {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (this.#messenger as any).call(\n 'PermissionController:getPermissions',\n snapId,\n ) as SubjectPermissions<PermissionConstraint>;\n } catch (error) {\n log('Failed to get permissions for snap', { snapId, error });\n return undefined;\n }\n }\n\n /**\n * Discover all snaps with keyring capabilities and their supported chains.\n * Uses PermissionController to find snaps with endowment:keyring permission.\n * Updates chainToSnap mapping and activeChains.\n *\n * Called on initialization and whenever PermissionController state changes\n * (e.g., new snaps installed, permissions granted/revoked).\n *\n * @remarks\n * **Known limitation:** If discovery fails (e.g., SnapController not ready),\n * the data source continues with empty chainToSnap. This means no snap\n * chains will be supported until a re-discovery is triggered by a permission\n * change. Callers should be aware that initialization may complete with no\n * active chains.\n */\n #discoverKeyringSnaps(): void {\n try {\n const runnableSnaps = this.#getRunnableSnaps();\n const chainToSnap: Record<ChainId, string> = {};\n const supportedChains: ChainId[] = [];\n\n for (const snap of runnableSnaps) {\n const permissions = this.#getSnapPermissions(snap.id);\n // Must have endowment:keyring permission to be a keyring snap\n if (!permissions?.[KEYRING_PERMISSION]) {\n continue;\n }\n\n // Get chainIds caveat from the assets permission (not keyring permission)\n // The chainIds are stored in endowment:assets\n const assetsPermission = permissions[ASSETS_PERMISSION];\n const chainIds = getChainIdsCaveat(assetsPermission);\n\n // Map each chain to this snap (first snap wins if multiple support same chain)\n if (chainIds) {\n for (const chainId of chainIds) {\n if (!(chainId in chainToSnap)) {\n chainToSnap[chainId] = snap.id;\n supportedChains.push(chainId);\n }\n }\n }\n }\n\n // Update chainToSnap mapping\n this.state.chainToSnap = chainToSnap;\n\n // Notify if chains changed\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains(supportedChains, (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n } catch (error) {\n log('Keyring snap discovery failed', { error });\n this.state.chainToSnap = {};\n try {\n const previous = [...this.state.activeChains];\n this.updateActiveChains([], (updatedChains) => {\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous);\n });\n } catch {\n // AssetsController not ready yet - expected during initialization\n }\n }\n }\n\n // ============================================================================\n // FETCH\n // ============================================================================\n\n async fetch(request: DataRequest): Promise<DataResponse> {\n // Guard against undefined request\n // Note: chainIds filtering is done by middleware/subscribe before calling fetch\n if (!request?.chainIds?.length) {\n return {};\n }\n\n if (this.#isBalanceV6Enabled()) {\n return this.#fetchV6(request);\n }\n\n return this.#fetchV5(request);\n }\n\n /**\n * v5 fetch. Unchanged from the pre-v6 handler; delete the v6 sibling first\n * if `assetsAccountsApiV6` is rolled back.\n *\n * @param request - The data request.\n * @returns Overlay (`merge`) balances from the snap keyring.\n */\n async #fetchV5(request: DataRequest): Promise<DataResponse> {\n if (!request?.accountsWithSupportedChains?.length) {\n return { assetsBalance: {}, assetsInfo: {}, updateMode: 'merge' };\n }\n\n const results: DataResponse = {\n assetsBalance: {},\n assetsInfo: {},\n updateMode: 'merge',\n };\n\n // Fetch balances for each account using its snap ID from metadata\n for (const { account } of request.accountsWithSupportedChains) {\n // Skip accounts without snap metadata (non-snap accounts)\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n continue;\n }\n\n // Skip accounts whose snap doesn't support any of the requested chains\n const snapSupportsRequestedChains = request.chainIds.some(\n (chainId) => this.state.chainToSnap[chainId] === snapId,\n );\n if (!snapSupportsRequestedChains) {\n continue;\n }\n\n const accountId = account.id;\n try {\n const client = this.#getKeyringClient(snapId);\n\n // Step 1: Get the list of assets for this account\n const accountAssets = await client.listAccountAssets(accountId);\n\n // If no assets, skip to next account\n if (!accountAssets || accountAssets.length === 0) {\n continue;\n }\n\n // Step 2: Get balances for those specific assets\n const balances: Record<CaipAssetType, Balance> =\n await client.getAccountBalances(accountId, accountAssets);\n\n // Transform keyring response to DataResponse format\n if (balances && typeof balances === 'object' && results.assetsBalance) {\n for (const [assetId, balance] of Object.entries(balances)) {\n results.assetsBalance[accountId] ??= {};\n const accountBalances = results.assetsBalance[accountId];\n if (accountBalances) {\n (accountBalances as Record<string, unknown>)[assetId] = {\n amount: balance.amount,\n ...(balance.metadata ? { metadata: balance.metadata } : {}),\n };\n }\n }\n }\n } catch {\n // Expected when account doesn't belong to this snap\n }\n }\n\n return results;\n }\n\n /**\n * v6 fetch: a complete snapshot of the requested account-chain slices.\n * Listed holdings and expected visible assets (native, pin, default\n * tracked) are requested together. Hidden assets are left out entirely.\n * Delete with the rest of the v6 path if `assetsAccountsApiV6` is rolled\n * back.\n *\n * @param request - The data request.\n * @returns Authoritative (`full`) balances for the requested slices.\n */\n async #fetchV6(request: DataRequest): Promise<DataResponse> {\n if (!request?.accountsWithSupportedChains?.length) {\n return { assetsBalance: {}, assetsInfo: {}, updateMode: 'full' };\n }\n\n const results: DataResponse = {\n assetsBalance: {},\n assetsInfo: {},\n updateMode: 'full',\n };\n\n // Fetch balances for each account using its snap ID from metadata\n for (const { account } of request.accountsWithSupportedChains) {\n // Skip accounts without snap metadata (non-snap accounts)\n const snapId = account.metadata.snap?.id;\n if (!snapId) {\n continue;\n }\n\n // Skip accounts whose snap doesn't support any of the requested chains\n const supportedChainIds = request.chainIds.filter(\n (chainId) => this.state.chainToSnap[chainId] === snapId,\n );\n if (supportedChainIds.length === 0) {\n continue;\n }\n\n const accountId = account.id;\n try {\n const client = this.#getKeyringClient(snapId);\n const { visibleAssetIds, hiddenAssetIds } = this.#getAssetVisibility(\n [accountId],\n supportedChainIds,\n );\n\n // Step 1: Get the list of assets for this account\n const accountAssets = await client.listAccountAssets(accountId);\n const assetsToFetch = this.#selectAssetsToFetchV6(\n accountAssets ?? [],\n visibleAssetIds,\n supportedChainIds,\n hiddenAssetIds,\n );\n // TEMPORARY: delete this call with `#includeSnapRollbackBalanceStateTokens` after Snaps Migration.\n this.#includeSnapRollbackBalanceStateTokens(\n accountId,\n assetsToFetch,\n supportedChainIds,\n hiddenAssetIds,\n );\n\n // Step 2: Get balances for those specific assets. An empty map is a\n // failed fetch (or nothing to ask for), not a zero snapshot. Leave\n // this account out so `full` cannot replace last-known amounts with 0.\n const balances: Record<CaipAssetType, Balance> = assetsToFetch.length\n ? await client.getAccountBalances(accountId, assetsToFetch)\n : {};\n if (\n !balances ||\n typeof balances !== 'object' ||\n Object.keys(balances).length === 0\n ) {\n continue;\n }\n\n // Transform keyring response to DataResponse format\n const accountBalances: Record<string, AssetBalance> = {};\n for (const [assetId, balance] of Object.entries(balances)) {\n accountBalances[assetId] = {\n amount: balance.amount,\n ...(balance.metadata ? { metadata: balance.metadata } : {}),\n };\n }\n\n // Step 3: Guard against an incomplete snap response. A `full` replace\n // would drop any expected visible asset that was requested but omitted.\n // Keep the last-known amount when we have one; otherwise seed 0.\n this.#fillOmittedVisibleAssets(\n accountId,\n visibleAssetIds,\n accountBalances,\n );\n\n if (results.assetsBalance) {\n results.assetsBalance[accountId] = accountBalances;\n }\n } catch {\n // Snap failed or the account does not belong to this snap. Contribute\n // nothing so previous balances stay in state.\n }\n }\n\n return results;\n }\n\n /**\n * Put every omitted visible asset on the snapshot so `full` cannot drop it.\n * Reuse the amount already in state when one exists; otherwise seed `0`.\n *\n * @param accountId - Account whose balances were fetched.\n * @param visibleAssetIds - Native, pin, and default tracked IDs for this scope.\n * @param accountBalances - Snapshot being built, mutated in place.\n */\n #fillOmittedVisibleAssets(\n accountId: string,\n visibleAssetIds: Caip19AssetId[],\n accountBalances: Record<string, AssetBalance>,\n ): void {\n const previousByKey = new Map(\n Object.entries(this.#getAssetsState().assetsBalance[accountId] ?? {}).map(\n ([assetId, balance]) => [assetId.toLowerCase(), balance],\n ),\n );\n const presentKeys = new Set(\n Object.keys(accountBalances).map((assetId) => assetId.toLowerCase()),\n );\n\n for (const assetId of visibleAssetIds) {\n if (presentKeys.has(assetId.toLowerCase())) {\n continue;\n }\n\n const previous = previousByKey.get(assetId.toLowerCase());\n if (previous) {\n accountBalances[assetId] = { ...previous };\n continue;\n }\n\n accountBalances[assetId] = getZeroAssetBalance(assetId);\n }\n }\n\n /**\n * Union the snap's listed holdings with expected visible assets (native,\n * pin, default tracked), limited to the requested chains. Hidden assets\n * are dropped so they are neither fetched nor written back to state.\n *\n * @param accountAssets - Asset IDs the snap listed for the account.\n * @param visibleAssetIds - Native, pin, and default tracked IDs for this scope.\n * @param supportedChainIds - Chains this snap was asked about.\n * @param hiddenAssetIds - Asset IDs the user hid in this scope.\n * @returns Asset IDs to request balances for.\n */\n #selectAssetsToFetchV6(\n accountAssets: string[],\n visibleAssetIds: Caip19AssetId[],\n supportedChainIds: ChainId[],\n hiddenAssetIds: Caip19AssetId[],\n ): CaipAssetType[] {\n const supportedChains = new Set(supportedChainIds);\n const hidden = new Set(\n hiddenAssetIds.map((assetId) => assetId.toLowerCase()),\n );\n const assetsToFetch = new Map<string, CaipAssetType>();\n\n for (const assetId of [...accountAssets, ...visibleAssetIds]) {\n const normalizedAssetId = assetId.toLowerCase();\n if (\n assetsToFetch.has(normalizedAssetId) ||\n hidden.has(normalizedAssetId)\n ) {\n continue;\n }\n\n try {\n if (!supportedChains.has(extractChainFromAssetId(assetId))) {\n continue;\n }\n } catch {\n // Skip unparseable asset IDs\n continue;\n }\n\n assetsToFetch.set(normalizedAssetId, assetId as CaipAssetType);\n }\n\n return Array.from(assetsToFetch.values());\n }\n\n // ============================================================================\n // TEMPORARY: balance-state tokens while a chain can roll back to Snaps\n //\n // Delete this whole section, and the call marked TEMPORARY in `#fetchV6`,\n // once balance reads fully move to Accounts API.\n //\n // The v6 request is the union of the snap's listed holdings, visible assets,\n // and every token already in balance state for the chain. Accounts API and\n // the websocket already return more tokens than the snap lists, so a rollback\n // to the snap still refreshes that wider set. This section adds the\n // balance-state part. Hidden assets stay out. Visible assets stay in the\n // request even when they have no balance entry yet.\n // ============================================================================\n\n /**\n * Append balance-state tokens for these chains onto the v6 request.\n * Tokens already selected, hidden, or on another chain are left out.\n *\n * @param accountId - Account whose balances are being fetched.\n * @param assetsToFetch - Asset IDs already chosen, mutated in place.\n * @param supportedChainIds - Chains this snap was asked about.\n * @param hiddenAssetIds - Asset IDs the user hid in this scope.\n */\n #includeSnapRollbackBalanceStateTokens(\n accountId: string,\n assetsToFetch: CaipAssetType[],\n supportedChainIds: ChainId[],\n hiddenAssetIds: Caip19AssetId[],\n ): void {\n const supportedChains = new Set(supportedChainIds);\n const hidden = new Set(\n hiddenAssetIds.map((assetId) => assetId.toLowerCase()),\n );\n const present = new Set(\n assetsToFetch.map((assetId) => assetId.toLowerCase()),\n );\n const balanceAssetIds = Object.keys(\n this.#getAssetsState().assetsBalance[accountId] ?? {},\n );\n\n for (const assetId of balanceAssetIds) {\n const normalizedAssetId = assetId.toLowerCase();\n if (present.has(normalizedAssetId) || hidden.has(normalizedAssetId)) {\n continue;\n }\n\n if (!this.#isSnapRollbackAssetOnChains(assetId, supportedChains)) {\n continue;\n }\n\n present.add(normalizedAssetId);\n assetsToFetch.push(assetId as CaipAssetType);\n }\n }\n\n /**\n * Whether an asset ID belongs to one of the chains in this request.\n * Unparseable IDs are treated as out of scope.\n *\n * @param assetId - CAIP-19 asset ID.\n * @param supportedChains - Chains this snap was asked about.\n * @returns True when the asset's chain is in scope.\n */\n #isSnapRollbackAssetOnChains(\n assetId: string,\n supportedChains: Set<ChainId>,\n ): boolean {\n try {\n return supportedChains.has(extractChainFromAssetId(assetId));\n } catch {\n return false;\n }\n }\n\n // ============================================================================\n // MIDDLEWARE\n // ============================================================================\n\n /**\n * Get the middleware for fetching balances via Snaps.\n * This middleware:\n * - Supports multiple accounts in a single request\n * - Filters request to only chains this data source supports\n * - Fetches balances for those chains for all accounts\n * - Merges response into context\n * - Removes handled chains from request for next middleware\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n const { request } = context;\n\n // Filter to chains this data source supports\n const supportedChains = request.chainIds.filter((chainId) =>\n this.state.activeChains.includes(chainId),\n );\n\n // If no supported chains, skip and pass to next middleware\n if (supportedChains.length === 0) {\n return next(context);\n }\n\n let successfullyHandledChains: ChainId[] = [];\n\n try {\n // Fetch for supported chains\n const response = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n // Merge response into context\n if (response.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n response.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n if (response.assetsInfo) {\n context.response.assetsInfo = {\n ...context.response.assetsInfo,\n ...response.assetsInfo,\n };\n }\n if (response.assetsPrice) {\n context.response.assetsPrice = {\n ...context.response.assetsPrice,\n ...response.assetsPrice,\n };\n }\n if (response.updateMode) {\n context.response = {\n ...context.response,\n updateMode: response.updateMode,\n };\n }\n\n // Determine successfully handled chains (exclude errors)\n const failedChains = new Set(Object.keys(response.errors ?? {}));\n successfullyHandledChains = supportedChains.filter(\n (chainId) => !failedChains.has(chainId),\n );\n } catch (error) {\n log('Middleware fetch failed', { error });\n successfullyHandledChains = [];\n }\n\n // Prepare context for next middleware\n let nextContext = context;\n if (successfullyHandledChains.length > 0) {\n const remainingChains = request.chainIds.filter(\n (chainId) => !successfullyHandledChains.includes(chainId),\n );\n nextContext = {\n ...context,\n request: {\n ...request,\n chainIds: remainingChains,\n },\n };\n }\n\n // Call next middleware\n return next(nextContext);\n };\n }\n\n // ============================================================================\n // SUBSCRIBE - Routes to appropriate snap(s)\n // ============================================================================\n\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId } = subscriptionRequest;\n\n // Guard against undefined request or chainIds\n if (!request?.chainIds) {\n return;\n }\n\n // Filter to chains we have a snap for\n const supportedChains = request.chainIds.filter((chainId) =>\n this.#isChainSupportedBySnap(chainId),\n );\n\n if (supportedChains.length === 0) {\n return;\n }\n\n try {\n const fetchResponse = await this.fetch({\n ...request,\n chainIds: supportedChains,\n });\n\n if (Object.keys(fetchResponse.assetsBalance ?? {}).length > 0) {\n await this.#onAssetsUpdate(fetchResponse);\n }\n } catch (error) {\n log('Initial fetch failed', { subscriptionId, error });\n }\n }\n\n // ============================================================================\n // KEYRING CLIENT\n // ============================================================================\n\n /**\n * Gets a `KeyringClient` for a Snap.\n * Caches clients per snap ID to avoid re-instantiation across multiple calls.\n *\n * @param snapId - ID of the Snap to get the client for.\n * @returns A `KeyringClient` for the Snap.\n */\n #getKeyringClient(snapId: string): KeyringClient {\n const cachedClient = this.#keyringClientCache.get(snapId);\n if (cachedClient) {\n return cachedClient;\n }\n\n const client = new KeyringClient({\n send: async (request: JsonRpcRequest): Promise<Json> =>\n await (\n this.#messenger as unknown as {\n call: (action: string, ...args: unknown[]) => Promise<Json> | Json;\n }\n ).call('SnapController:handleRequest', {\n snapId: snapId as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnKeyringRequest,\n request,\n }),\n });\n\n this.#keyringClientCache.set(snapId, client);\n return client;\n }\n\n // ============================================================================\n // CLEANUP\n // ============================================================================\n\n destroy(): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const messenger = this.#messenger as any;\n\n // Unsubscribe from snap keyring events\n try {\n messenger.unsubscribe(\n 'AccountsController:accountBalancesUpdated',\n this.#handleSnapBalancesUpdatedBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from snap keyring events', { error });\n }\n\n // Unsubscribe from permission changes\n try {\n messenger.unsubscribe(\n 'PermissionController:stateChange',\n this.#handlePermissionStateChangeBound,\n );\n } catch (error) {\n log('Failed to unsubscribe from permission changes', { error });\n }\n\n // Clear keyring client cache\n this.#keyringClientCache.clear();\n }\n}\n\n// ============================================================================\n// FACTORY\n// ============================================================================\n\nexport function createSnapDataSource(\n options: SnapDataSourceOptions,\n): SnapDataSource {\n return new SnapDataSource(options);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask-previews/assets-controller",
|
|
3
|
-
"version": "19.0.0-preview-
|
|
3
|
+
"version": "19.0.0-preview-c18f4a64e",
|
|
4
4
|
"description": "Tracks assets balances/prices and handles token detection across all digital assets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ethereum",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"@metamask/account-tree-controller": "^11.0.1",
|
|
59
59
|
"@metamask/accounts-controller": "^40.1.0",
|
|
60
60
|
"@metamask/assets-controllers": "^112.1.2",
|
|
61
|
-
"@metamask/base-controller": "^10.
|
|
61
|
+
"@metamask/base-controller": "^10.1.0",
|
|
62
62
|
"@metamask/client-controller": "^2.0.0",
|
|
63
63
|
"@metamask/config-registry-controller": "^5.0.0",
|
|
64
64
|
"@metamask/controller-utils": "^13.0.0",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"@metamask/keyring-snap-client": "^10.0.1",
|
|
70
70
|
"@metamask/messenger": "^3.0.0",
|
|
71
71
|
"@metamask/multichain-transactions-controller": "^8.0.0",
|
|
72
|
-
"@metamask/network-controller": "^37.0
|
|
72
|
+
"@metamask/network-controller": "^37.1.0",
|
|
73
73
|
"@metamask/network-enablement-controller": "^7.0.2",
|
|
74
74
|
"@metamask/permission-controller": "^14.0.0",
|
|
75
75
|
"@metamask/phishing-controller": "^18.2.1",
|