@metamask-previews/assets-controller 4.0.0-preview-3f6f27f → 4.0.0-preview-b6a517f5e

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,15 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
- - Split `getAssets` fetch pipeline into a fast awaited path and a parallel fire-and-forget background path to reduce perceived latency on unlock and onboarding ([#8383](https://github.com/MetaMask/core/pull/8383))
13
- - Fast pipeline: AccountsApi + StakedBalance → Detection → Token + Price (awaited, committed to state immediately)
14
- - Background pipeline: Snap + RPC run in parallel → Detection → Token + Price when basic functionality is enabled; when disabled (RPC-only mode), Token + Price are omitted (fire-and-forget merge)
15
- - `handleAssetsUpdate` skips token/price enrichment and strips `metadata` / `price` from the effective request when basic functionality is disabled (RPC-only mode)
16
- - `setSelectedCurrency` no longer triggers a price refresh via `getAssets` when basic functionality is disabled
17
- - `PriceDataSource` now batches spot-price API requests in chunks of 50 using `reduceInBatchesSerially` to avoid DynamoDB batch-limit errors ([#8383](https://github.com/MetaMask/core/pull/8383))
18
- - `TokenDataSource` now batches token metadata API requests in chunks of 50 using `reduceInBatchesSerially` to avoid DynamoDB batch-limit errors ([#8383](https://github.com/MetaMask/core/pull/8383))
19
- - `PriceDataSource` filters out all synthetic `slip44:NUMBER-*` staking-position asset IDs before calling the Price API ([#8383](https://github.com/MetaMask/core/pull/8383))
20
- - `TokenDataSource` filters EVM ERC-20 tokens by `occurrences >= 3` and treats missing occurrences as 0 ([#8383](https://github.com/MetaMask/core/pull/8383))
21
12
  - Bump `@metamask/keyring-controller` from `^25.1.1` to `^25.2.0` ([#8363](https://github.com/MetaMask/core/pull/8363))
22
13
  - Bump `@metamask/messenger` from `^1.0.0` to `^1.1.1` ([#8364](https://github.com/MetaMask/core/pull/8364), [#8373](https://github.com/MetaMask/core/pull/8373))
23
14
 
@@ -356,18 +356,12 @@ class AssetsController extends base_controller_1.BaseController {
356
356
  forceUpdate: true,
357
357
  assetsForPriceUpdate: options?.assetsForPriceUpdate,
358
358
  });
359
- // Fast pipeline: accountsApi + stakedBalance → detection → token + price.
360
- // Snap and RPC are excluded here due to their latency (snap triggers account
361
- // creation, RPC is slow on many chains). Results are committed to state
362
- // immediately so the UI can display balances without waiting for them.
363
- //
364
- // Both the fast and background pipelines use 'merge' mode because neither
365
- // alone represents the full set of data sources. Using 'full' in either
366
- // would wipe balances from the sources handled by the other pipeline.
367
- const fastSources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
359
+ const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
368
360
  ? [
369
361
  (0, ParallelMiddleware_1.createParallelBalanceMiddleware)([
370
362
  __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
363
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
364
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
371
365
  __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
372
366
  ]),
373
367
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
@@ -376,33 +370,18 @@ class AssetsController extends base_controller_1.BaseController {
376
370
  __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
377
371
  ]),
378
372
  ]
379
- : [__classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"), __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f")];
380
- const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, fastSources, request);
381
- // The fast pipeline only contains a subset of data sources (AccountsApi +
382
- // StakedBalance), so it must always merge to avoid wiping Snap/RPC
383
- // balances that the background pipeline hasn't yet replaced.
384
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode: 'merge' });
385
- // Background pipeline: snap and RPC run in parallel after the fast path
386
- // commits to state. Their balances are merged together before detection.
387
- // Token + price enrichment matches the pre-split behavior: only when basic
388
- // functionality is on (RPC-only mode must not call token/price APIs).
389
- const slowSources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
390
- ? [__classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"), __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")]
391
- : [__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")];
392
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
393
- (0, ParallelMiddleware_1.createParallelBalanceMiddleware)(slowSources),
394
- __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
395
- ...(__classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
396
- ? [
397
- (0, ParallelMiddleware_1.createParallelMiddleware)([
398
- __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
399
- __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
400
- ]),
401
- ]
402
- : []),
403
- ], request)
404
- .then(({ response: slowResponse }) => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...slowResponse, updateMode: 'merge' }))
405
- .catch((error) => log('Background pipeline failed', { error }));
373
+ : [
374
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
375
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
376
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
377
+ ];
378
+ const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
379
+ // Default to 'merge' when fetching a subset of chains so we don't wipe
380
+ // balances from chains that weren't included in this fetch.
381
+ const isPartialChainFetch = options?.chainIds !== undefined &&
382
+ options.chainIds.length < __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size;
383
+ const updateMode = options?.updateMode ?? (isPartialChainFetch ? 'merge' : 'full');
384
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode });
406
385
  const durationMs = performance.now() - startTime;
407
386
  // Emit trace for every full fetch (Assets Health dashboard)
408
387
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_emitTrace).call(this, TRACE_FULL_FETCH, {
@@ -669,9 +648,6 @@ class AssetsController extends base_controller_1.BaseController {
669
648
  previousCurrency,
670
649
  selectedCurrency,
671
650
  });
672
- if (!__classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)) {
673
- return;
674
- }
675
651
  this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
676
652
  forceUpdate: true,
677
653
  dataTypes: ['price'],
@@ -746,8 +722,7 @@ class AssetsController extends base_controller_1.BaseController {
746
722
  /**
747
723
  * Handle assets updated from a data source.
748
724
  * Called via the onAssetsUpdate callback passed in SubscriptionRequest when the controller subscribes to a data source.
749
- * Runs detection, then (when basic functionality is enabled) token metadata and price enrichment before updating state.
750
- * When basic functionality is disabled (RPC-only mode), only detection runs; token and price APIs are not used.
725
+ * Enriches the response with token metadata (via middlewares) before updating state.
751
726
  *
752
727
  * @param response - The data response with updated assets
753
728
  * @param sourceId - The data source ID reporting the update
@@ -760,27 +735,19 @@ class AssetsController extends base_controller_1.BaseController {
760
735
  hasBalance: Boolean(response.assetsBalance),
761
736
  hasPrice: Boolean(response.assetsPrice),
762
737
  });
763
- const resolvedRequest = request ?? {
738
+ // Run through enrichment middlewares (Detection, then Token + Price in parallel)
739
+ // Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
740
+ const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
741
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
742
+ (0, ParallelMiddleware_1.createParallelMiddleware)([
743
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
744
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
745
+ ]),
746
+ ], request ?? {
764
747
  accountsWithSupportedChains: [],
765
748
  chainIds: [],
766
749
  dataTypes: ['balance', 'metadata', 'price'],
767
- };
768
- // RPC-only mode (basic functionality off): never run token/price APIs. Strip
769
- // those data types so downstream middleware cannot treat them as requested.
770
- const pipelineRequest = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
771
- ? resolvedRequest
772
- : {
773
- ...resolvedRequest,
774
- dataTypes: resolvedRequest.dataTypes.filter((dt) => dt !== 'metadata' && dt !== 'price'),
775
- };
776
- const enrichmentSources = [__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f")];
777
- if (__classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)) {
778
- enrichmentSources.push((0, ParallelMiddleware_1.createParallelMiddleware)([
779
- __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
780
- __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
781
- ]));
782
- }
783
- const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, enrichmentSources, pipelineRequest, response);
750
+ }, response);
784
751
  await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
785
752
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_emitTrace).call(this, TRACE_UPDATE_PIPELINE, {
786
753
  source: sourceId,