@metamask-previews/assets-controller 13.1.4-preview-22007ec → 13.1.4-preview-57cd9b4fb

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,8 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
- - **BREAKING:** Subscribe to `AccountTreeController:initialized` (typed as `AccountTreeControllerInitializedEvent`) so asset tracking starts only after the account tree is fully built, instead of on intermediate `AccountTreeController:stateChange` events during `init()` ([#9892](https://github.com/MetaMask/core/pull/9892))
13
- - Hosts that restrict which events flow through the `AssetsController` messenger must now also delegate `AccountTreeController:initialized`
12
+ - **BREAKING:** Subscribe to `AccountTreeController:initialized` / `:uninitialized` (typed as `AccountTreeControllerInitializedEvent` / `AccountTreeControllerUninitializedEvent`) so asset tracking starts only after the account tree is fully built, instead of on intermediate `AccountTreeController:stateChange` events during `init()` or on unlock before the tree is ready ([#9892](https://github.com/MetaMask/core/pull/9892))
13
+ - Hosts that restrict which events flow through the `AssetsController` messenger must now also delegate `AccountTreeController:initialized` and `AccountTreeController:uninitialized`
14
+ - Reduce Accounts API calls on startup and refresh:
15
+ - Skip `AccountsApiDataSource` subscribe-time initial poll after a forced `getAssets` balance fetch
16
+ - Ignore init-time `AccountTreeController:selectedAccountGroupChange` (including same-group re-emits and events before tracking starts) so `:initialized` owns first start; only refresh on real group switches while tracking
17
+ - Skip Accounts API middleware when `dataTypes` does not include `balance` (e.g. price-only refreshes)
14
18
 
15
19
  ## [13.1.4]
16
20
 
@@ -13,7 +13,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trace, _AssetsController_captureException, _AssetsController_firstInitFetchReported, _AssetsController_stateSizeReported, _AssetsController_emitStateSizeTrace, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_controllerMutex, _AssetsController_accountRefreshMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_lastKnownAccountIds, _AssetsController_getSelectedAccounts, _AssetsController_accountActivityDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_customAssetGraduationMiddleware, _AssetsController_rpcFallbackMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_queryApiClient, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeNativeAssetsMap, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_onUnapprovedTransactionAdded, _AssetsController_onTransactionConfirmed, _AssetsController_updateActive, _AssetsController_handleAccountTreeInitialized, _AssetsController_handleAccountTreeStateChange, _AssetsController_runAccountTreeRefresh, _AssetsController_runStartupRefresh, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_assertNonEmptyAccountId, _AssetsController_normalizeAssetIdOrThrow, _AssetsController_fetchMissingPricesWithoutCache, _AssetsController_getNativeAssetMap, _AssetsController_isNativeAsset, _AssetsController_getAssetType, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_getSlowPipelineChainIds, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_ensureDefaultTrackedAssetsSeeded, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_getAssetFromState, _AssetsController_shouldHideNativeToken, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeRpcCustomAssetsSupplement, _AssetsController_unsubscribeBySubscriptionKey, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleNetworkAdded, _AssetsController_refreshActiveChainsOnNetworkSwitch, _AssetsController_getSelectedEvmChainIdFromNetworkState, _AssetsController_handleNetworkDidChange, _AssetsController_refreshAssetsAfterNetworkChange, _AssetsController_refreshAssetsAfterNetworkAdded;
16
+ var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trace, _AssetsController_captureException, _AssetsController_firstInitFetchReported, _AssetsController_stateSizeReported, _AssetsController_emitStateSizeTrace, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_accountTreeInitialized, _AssetsController_controllerMutex, _AssetsController_accountRefreshMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_lastKnownAccountIds, _AssetsController_getSelectedAccounts, _AssetsController_accountActivityDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_customAssetGraduationMiddleware, _AssetsController_rpcFallbackMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_queryApiClient, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeNativeAssetsMap, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_onUnapprovedTransactionAdded, _AssetsController_onTransactionConfirmed, _AssetsController_updateActive, _AssetsController_handleAccountTreeStateChange, _AssetsController_runAccountTreeRefresh, _AssetsController_runStartupRefresh, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_assertNonEmptyAccountId, _AssetsController_normalizeAssetIdOrThrow, _AssetsController_fetchMissingPricesWithoutCache, _AssetsController_getNativeAssetMap, _AssetsController_isNativeAsset, _AssetsController_getAssetType, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_getSlowPipelineChainIds, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_ensureDefaultTrackedAssetsSeeded, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_getAssetFromState, _AssetsController_shouldHideNativeToken, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeRpcCustomAssetsSupplement, _AssetsController_unsubscribeBySubscriptionKey, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleNetworkAdded, _AssetsController_refreshActiveChainsOnNetworkSwitch, _AssetsController_getSelectedEvmChainIdFromNetworkState, _AssetsController_handleNetworkDidChange, _AssetsController_refreshAssetsAfterNetworkChange, _AssetsController_refreshAssetsAfterNetworkAdded;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.AssetsController = exports.getDefaultAssetsControllerState = void 0;
19
19
  const base_controller_1 = require("@metamask/base-controller");
@@ -309,6 +309,11 @@ class AssetsController extends base_controller_1.BaseController {
309
309
  _AssetsController_uiOpen.set(this, false);
310
310
  /** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
311
311
  _AssetsController_keyringUnlocked.set(this, false);
312
+ /**
313
+ * Whether `AccountTreeController` has finished `init()`. Unlock / UI-open
314
+ * alone must not start fetches — the tree can still be mid-build.
315
+ */
316
+ _AssetsController_accountTreeInitialized.set(this, false);
312
317
  _AssetsController_controllerMutex.set(this, new async_mutex_1.Mutex());
313
318
  /** Serializes account-switch fetch + subscribe to prevent overlapping races. */
314
319
  _AssetsController_accountRefreshMutex.set(this, new async_mutex_1.Mutex());
@@ -1180,7 +1185,7 @@ class AssetsController extends base_controller_1.BaseController {
1180
1185
  }
1181
1186
  }
1182
1187
  exports.AssetsController = AssetsController;
1183
- _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trace = new WeakMap(), _AssetsController_captureException = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_stateSizeReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_accountRefreshMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_lastKnownAccountIds = new WeakMap(), _AssetsController_accountActivityDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_stakedBalanceDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_customAssetGraduationMiddleware = new WeakMap(), _AssetsController_rpcFallbackMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_queryApiClient = new WeakMap(), _AssetsController_onActiveChainsUpdated = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_emitStateSizeTrace = function _AssetsController_emitStateSizeTrace() {
1188
+ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trace = new WeakMap(), _AssetsController_captureException = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_stateSizeReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_accountTreeInitialized = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_accountRefreshMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_lastKnownAccountIds = new WeakMap(), _AssetsController_accountActivityDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_stakedBalanceDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_customAssetGraduationMiddleware = new WeakMap(), _AssetsController_rpcFallbackMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_queryApiClient = new WeakMap(), _AssetsController_onActiveChainsUpdated = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_emitStateSizeTrace = function _AssetsController_emitStateSizeTrace() {
1184
1189
  if (!__classPrivateFieldGet(this, _AssetsController_trace, "f") || __classPrivateFieldGet(this, _AssetsController_stateSizeReported, "f")) {
1185
1190
  return;
1186
1191
  }
@@ -1293,8 +1298,8 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1293
1298
  return reference;
1294
1299
  }, _AssetsController_subscribeToEvents = function _AssetsController_subscribeToEvents() {
1295
1300
  // Subscribe to account group changes (when user switches between account groups like Account 1 -> Account 2)
1296
- this.messenger.subscribe('AccountTreeController:selectedAccountGroupChange', (groupId) => {
1297
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleAccountGroupChanged).call(this, groupId).catch(console.error);
1301
+ this.messenger.subscribe('AccountTreeController:selectedAccountGroupChange', (groupId, previousGroupId) => {
1302
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleAccountGroupChanged).call(this, groupId, previousGroupId).catch(console.error);
1298
1303
  });
1299
1304
  // Catch post-init tree mutations that change the selected account set
1300
1305
  // (e.g. a snap account added to the current group) without changing
@@ -1355,7 +1360,12 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1355
1360
  // happen before `AccountTreeController.init()`, and `:stateChange` fires
1356
1361
  // for intermediate mutations during that build.
1357
1362
  this.messenger.subscribe('AccountTreeController:initialized', () => {
1358
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleAccountTreeInitialized).call(this);
1363
+ __classPrivateFieldSet(this, _AssetsController_accountTreeInitialized, true, "f");
1364
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1365
+ });
1366
+ this.messenger.subscribe('AccountTreeController:uninitialized', () => {
1367
+ __classPrivateFieldSet(this, _AssetsController_accountTreeInitialized, false, "f");
1368
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1359
1369
  });
1360
1370
  }, _AssetsController_onUnapprovedTransactionAdded = function _AssetsController_onUnapprovedTransactionAdded(transactionMeta) {
1361
1371
  const hexChainId = transactionMeta.chainId;
@@ -1400,22 +1410,19 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1400
1410
  log('Failed to refresh assets after transaction confirmed', { error });
1401
1411
  });
1402
1412
  }, _AssetsController_updateActive = function _AssetsController_updateActive() {
1403
- const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
1413
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") && __classPrivateFieldGet(this, _AssetsController_accountTreeInitialized, "f");
1404
1414
  if (shouldRun) {
1405
1415
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
1406
1416
  }
1407
1417
  else {
1408
1418
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
1409
1419
  }
1410
- }, _AssetsController_handleAccountTreeInitialized = function _AssetsController_handleAccountTreeInitialized() {
1411
- const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
1412
- if (!shouldRun) {
1413
- return;
1414
- }
1415
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
1416
1420
  }, _AssetsController_handleAccountTreeStateChange = function _AssetsController_handleAccountTreeStateChange() {
1417
- const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
1418
- if (!shouldRun || __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size === 0) {
1421
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") &&
1422
+ __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") &&
1423
+ __classPrivateFieldGet(this, _AssetsController_accountTreeInitialized, "f") &&
1424
+ __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size > 0;
1425
+ if (!shouldRun) {
1419
1426
  return;
1420
1427
  }
1421
1428
  const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this);
@@ -1447,7 +1454,7 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1447
1454
  chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
1448
1455
  forceUpdate: true,
1449
1456
  });
1450
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1457
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
1451
1458
  if (newAccounts.length > 0) {
1452
1459
  await this.getAssets(newAccounts, {
1453
1460
  chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
@@ -1458,7 +1465,7 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1458
1465
  }
1459
1466
  catch (error) {
1460
1467
  log('Failed to fetch assets after tree change', error);
1461
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1468
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
1462
1469
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
1463
1470
  }
1464
1471
  finally {
@@ -1481,14 +1488,15 @@ async function _AssetsController_runStartupRefresh(accounts) {
1481
1488
  // and default tracked assets that were never returned by balance APIs.
1482
1489
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1483
1490
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureDefaultTrackedAssetsSeeded).call(this);
1484
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1491
+ // Balances were just force-fetched — skip AccountsApi's subscribe-time poll.
1492
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
1485
1493
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
1486
1494
  }
1487
1495
  catch (error) {
1488
1496
  log('Failed to fetch assets on startup', error);
1489
1497
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1490
1498
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureDefaultTrackedAssetsSeeded).call(this);
1491
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1499
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
1492
1500
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
1493
1501
  }
1494
1502
  finally {
@@ -2111,19 +2119,19 @@ async function _AssetsController_executeMiddlewares(params) {
2111
2119
  }
2112
2120
  }
2113
2121
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
2114
- }, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
2122
+ }, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets(options) {
2115
2123
  const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this);
2116
2124
  const enabledChains = [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")];
2117
2125
  if (accounts.length === 0 || enabledChains.length === 0) {
2118
2126
  return;
2119
2127
  }
2120
2128
  // Subscribe to balance updates (batched by data source)
2121
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this, accounts, enabledChains);
2129
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this, accounts, enabledChains, options);
2122
2130
  // Subscribe to staked balance updates (separate from regular balance chain-claiming)
2123
2131
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeStakedBalance).call(this, accounts, enabledChains);
2124
2132
  // Subscribe to price updates for all assets held by selected accounts
2125
2133
  this.subscribeAssetsPrice(accounts, enabledChains);
2126
- }, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance(accounts, chainIds) {
2134
+ }, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance(accounts, chainIds, options) {
2127
2135
  const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, accounts, new Set(chainIds));
2128
2136
  const remainingChains = new Set(chainToAccounts.keys());
2129
2137
  // When basic functionality is on, use all balance data sources; when off,
@@ -2160,7 +2168,12 @@ async function _AssetsController_executeMiddlewares(params) {
2160
2168
  return true;
2161
2169
  });
2162
2170
  if (accountsForSource.length > 0) {
2163
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accountsForSource, assignedChains);
2171
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accountsForSource, assignedChains, {
2172
+ ...(options?.skipInitialFetch &&
2173
+ source === __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f")
2174
+ ? { skipInitialFetch: true }
2175
+ : {}),
2176
+ });
2164
2177
  }
2165
2178
  }
2166
2179
  // Supplemental RPC subscription for customAssets on chains another data
@@ -2239,6 +2252,7 @@ async function _AssetsController_executeMiddlewares(params) {
2239
2252
  accountCount: accounts.length,
2240
2253
  chainCount: chains.length,
2241
2254
  customAssetsOnly: options.customAssetsOnly === true,
2255
+ skipInitialFetch: options.skipInitialFetch === true,
2242
2256
  });
2243
2257
  const subscribeReq = {
2244
2258
  request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chains, {
@@ -2253,6 +2267,7 @@ async function _AssetsController_executeMiddlewares(params) {
2253
2267
  isUpdate,
2254
2268
  onAssetsUpdate: (response, request) => this.handleAssetsUpdate(response, sourceId, request),
2255
2269
  getAssetsState: () => this.state,
2270
+ ...(options.skipInitialFetch === true ? { skipInitialFetch: true } : {}),
2256
2271
  };
2257
2272
  source.subscribe(subscribeReq).catch((error) => {
2258
2273
  console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
@@ -2342,15 +2357,27 @@ async function _AssetsController_executeMiddlewares(params) {
2342
2357
  // ============================================================================
2343
2358
  // EVENT HANDLERS
2344
2359
  // ============================================================================
2345
- async function _AssetsController_handleAccountGroupChanged(groupId) {
2360
+ async function _AssetsController_handleAccountGroupChanged(groupId, previousGroupId = '') {
2346
2361
  // The selected account group can be empty during onboarding or wallet reset.
2347
2362
  if (!groupId) {
2348
2363
  return;
2349
2364
  }
2365
+ // First start is owned by `AccountTreeController:initialized` / `#start`.
2366
+ // ATC also re-publishes `selectedAccountGroupChange` on every `init()`
2367
+ // (including when the group did not change) so late subscribers can catch
2368
+ // up — ignore those until we are already tracking.
2369
+ if (__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size === 0) {
2370
+ return;
2371
+ }
2372
+ if (groupId === previousGroupId) {
2373
+ return;
2374
+ }
2350
2375
  const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this);
2351
2376
  log('Account group changed', {
2352
2377
  accountCount: accounts.length,
2353
2378
  accountIds: accounts.map((a) => a.id),
2379
+ groupId,
2380
+ previousGroupId,
2354
2381
  });
2355
2382
  __classPrivateFieldSet(this, _AssetsController_lastKnownAccountIds, new Set(accounts.map((a) => a.id)), "f");
2356
2383
  const releaseLock = await __classPrivateFieldGet(this, _AssetsController_accountRefreshMutex, "f").acquire();
@@ -2364,7 +2391,8 @@ async function _AssetsController_handleAccountGroupChanged(groupId) {
2364
2391
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
2365
2392
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureDefaultTrackedAssetsSeeded).call(this);
2366
2393
  // Subscribe after seed so the price poll sees natives / defaults.
2367
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
2394
+ // Balances were just force-fetched — skip AccountsApi's subscribe-time poll.
2395
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
2368
2396
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
2369
2397
  }
2370
2398
  finally {