@metamask-previews/assets-controller 14.0.3-preview-a38f058 → 14.0.3-preview-1cf7cc7b3

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,10 +9,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Changed
11
11
 
12
- - **BREAKING:** `AssetsControllerMessenger` now requires `AccountTreeController:isInitialized`, `ClientController:getState`, and `KeyringController:isUnlocked` so lifecycle checks read controller state on demand instead of mirroring it from events ([#10059](https://github.com/MetaMask/core/pull/10059))
13
- - Hosts that restrict which actions flow through the `AssetsController` messenger must delegate these three actions
14
- - `AccountTreeController:stateChange` is no longer subscribed to; remove it from allowed events if your messenger wiring lists events explicitly
15
- - Revert to `selectedAccountGroupChange` for account-group switches; snap accounts added mid-session are picked up on restart ([#10059](https://github.com/MetaMask/core/pull/10059))
16
12
  - Bump `@metamask/transaction-controller` from `^69.6.1` to `^69.7.0` ([#10046](https://github.com/MetaMask/core/pull/10046))
17
13
 
18
14
  ## [14.0.3]
@@ -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_controllerMutex, _AssetsController_accountRefreshMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_getSelectedAccounts, _AssetsController_isAccountTreeInitialized, _AssetsController_isUiOpen, _AssetsController_isKeyringUnlocked, _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_refreshAssetsForTransaction, _AssetsController_runSpamCleanup, _AssetsController_updateActive, _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_refreshAssetsForTransaction, _AssetsController_runSpamCleanup, _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");
@@ -305,6 +305,15 @@ class AssetsController extends base_controller_1.BaseController {
305
305
  _AssetsController_firstInitFetchReported.set(this, false);
306
306
  /** Whether we have already reported state size for this session (reset on #stop). */
307
307
  _AssetsController_stateSizeReported.set(this, false);
308
+ /** Whether the client (UI) is open. Combined with #keyringUnlocked for #updateActive. */
309
+ _AssetsController_uiOpen.set(this, false);
310
+ /** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
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);
308
317
  _AssetsController_controllerMutex.set(this, new async_mutex_1.Mutex());
309
318
  /** Serializes account-switch fetch + subscribe to prevent overlapping races. */
310
319
  _AssetsController_accountRefreshMutex.set(this, new async_mutex_1.Mutex());
@@ -317,6 +326,12 @@ class AssetsController extends base_controller_1.BaseController {
317
326
  _AssetsController_activeSubscriptions.set(this, new Map());
318
327
  /** Currently enabled chains from NetworkEnablementController */
319
328
  _AssetsController_enabledChains.set(this, new Set());
329
+ /**
330
+ * Snapshot of account IDs that were active when the last subscription/fetch
331
+ * cycle ran. Used by #handleAccountTreeStateChange to skip redundant
332
+ * re-subscriptions when the account set hasn't actually changed.
333
+ */
334
+ _AssetsController_lastKnownAccountIds.set(this, new Set());
320
335
  _AssetsController_accountActivityDataSource.set(this, void 0);
321
336
  _AssetsController_accountsApiDataSource.set(this, void 0);
322
337
  _AssetsController_snapDataSource.set(this, void 0);
@@ -1170,7 +1185,7 @@ class AssetsController extends base_controller_1.BaseController {
1170
1185
  }
1171
1186
  }
1172
1187
  exports.AssetsController = AssetsController;
1173
- _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_controllerMutex = new WeakMap(), _AssetsController_accountRefreshMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = 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() {
1174
1189
  if (!__classPrivateFieldGet(this, _AssetsController_trace, "f") || __classPrivateFieldGet(this, _AssetsController_stateSizeReported, "f")) {
1175
1190
  return;
1176
1191
  }
@@ -1223,12 +1238,6 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1223
1238
  return [selectedAccount];
1224
1239
  }
1225
1240
  return [];
1226
- }, _AssetsController_isAccountTreeInitialized = function _AssetsController_isAccountTreeInitialized() {
1227
- return this.messenger.call('AccountTreeController:isInitialized');
1228
- }, _AssetsController_isUiOpen = function _AssetsController_isUiOpen() {
1229
- return client_controller_1.clientControllerSelectors.selectIsUiOpen(this.messenger.call('ClientController:getState'));
1230
- }, _AssetsController_isKeyringUnlocked = function _AssetsController_isKeyringUnlocked() {
1231
- return this.messenger.call('KeyringController:isUnlocked');
1232
1241
  }, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
1233
1242
  return [
1234
1243
  __classPrivateFieldGet(this, _AssetsController_accountActivityDataSource, "f"),
@@ -1288,14 +1297,16 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1288
1297
  }
1289
1298
  return reference;
1290
1299
  }, _AssetsController_subscribeToEvents = function _AssetsController_subscribeToEvents() {
1300
+ // Subscribe to account group changes (when user switches between account groups like Account 1 -> Account 2)
1291
1301
  this.messenger.subscribe('AccountTreeController:selectedAccountGroupChange', (groupId, previousGroupId) => {
1292
1302
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleAccountGroupChanged).call(this, groupId, previousGroupId).catch(console.error);
1293
1303
  });
1294
- this.messenger.subscribe('AccountTreeController:initialized', () => {
1295
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1296
- });
1297
- this.messenger.subscribe('AccountTreeController:uninitialized', () => {
1298
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1304
+ // Catch post-init tree mutations that change the selected account set
1305
+ // (e.g. a snap account added to the current group) without changing
1306
+ // the selected group id. Intermediate `:stateChange` events during
1307
+ // `AccountTreeController.init()` are ignored until `:initialized`.
1308
+ this.messenger.subscribe('AccountTreeController:stateChange', () => {
1309
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleAccountTreeStateChange).call(this);
1299
1310
  });
1300
1311
  // Subscribe to network enablement changes (only enabledNetworkMap)
1301
1312
  this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
@@ -1322,17 +1333,20 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1322
1333
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleNetworkDidChange).call(this, networkState).catch(console.error);
1323
1334
  });
1324
1335
  // Client + Keyring lifecycle: only run when UI is open AND keyring is unlocked
1325
- this.messenger.subscribe('ClientController:stateChange', () => {
1336
+ this.messenger.subscribe('ClientController:stateChange', (isUiOpen) => {
1337
+ __classPrivateFieldSet(this, _AssetsController_uiOpen, isUiOpen, "f");
1326
1338
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1327
1339
  }, client_controller_1.clientControllerSelectors.selectIsUiOpen);
1328
1340
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
1329
1341
  this.messenger.subscribe('KeyringController:unlock', async () => {
1342
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, true, "f");
1330
1343
  await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_runSpamCleanup).call(this).catch(() => {
1331
1344
  /* Do nothing */
1332
1345
  });
1333
1346
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1334
1347
  });
1335
1348
  this.messenger.subscribe('KeyringController:lock', () => {
1349
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
1336
1350
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1337
1351
  });
1338
1352
  // Subscribe to unapproved transactions - TXs that need confirmation.
@@ -1348,6 +1362,17 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1348
1362
  this.messenger.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
1349
1363
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_refreshAssetsForTransaction).call(this, transactionMeta);
1350
1364
  });
1365
+ // Start tracking only after the account tree is fully built. Unlock can
1366
+ // happen before `AccountTreeController.init()`, and `:stateChange` fires
1367
+ // for intermediate mutations during that build.
1368
+ this.messenger.subscribe('AccountTreeController:initialized', () => {
1369
+ __classPrivateFieldSet(this, _AssetsController_accountTreeInitialized, true, "f");
1370
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1371
+ });
1372
+ this.messenger.subscribe('AccountTreeController:uninitialized', () => {
1373
+ __classPrivateFieldSet(this, _AssetsController_accountTreeInitialized, false, "f");
1374
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
1375
+ });
1351
1376
  }, _AssetsController_refreshAssetsForTransaction = function _AssetsController_refreshAssetsForTransaction(transactionMeta) {
1352
1377
  const hexChainId = transactionMeta.chainId;
1353
1378
  if (!hexChainId) {
@@ -1377,7 +1402,7 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1377
1402
  });
1378
1403
  }, _AssetsController_runSpamCleanup = async function _AssetsController_runSpamCleanup() {
1379
1404
  try {
1380
- const shouldRun = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isKeyringUnlocked).call(this) &&
1405
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") &&
1381
1406
  __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this) &&
1382
1407
  (0, healAssetsInfoMetadata_js_1.isUnlockCleanupEnabled)(this.messenger.call('RemoteFeatureFlagController:getState')
1383
1408
  ?.remoteFeatureFlags);
@@ -1409,15 +1434,67 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
1409
1434
  log('Failed to run spam cleanup', { error });
1410
1435
  }
1411
1436
  }, _AssetsController_updateActive = function _AssetsController_updateActive() {
1412
- const shouldRun = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isUiOpen).call(this) &&
1413
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isKeyringUnlocked).call(this) &&
1414
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isAccountTreeInitialized).call(this);
1437
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") && __classPrivateFieldGet(this, _AssetsController_accountTreeInitialized, "f");
1415
1438
  if (shouldRun) {
1416
1439
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
1417
1440
  }
1418
1441
  else {
1419
1442
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
1420
1443
  }
1444
+ }, _AssetsController_handleAccountTreeStateChange = function _AssetsController_handleAccountTreeStateChange() {
1445
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") &&
1446
+ __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") &&
1447
+ __classPrivateFieldGet(this, _AssetsController_accountTreeInitialized, "f") &&
1448
+ __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size > 0;
1449
+ if (!shouldRun) {
1450
+ return;
1451
+ }
1452
+ const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this);
1453
+ const currentIds = new Set(accounts.map((a) => a.id));
1454
+ const accountsChanged = currentIds.size !== __classPrivateFieldGet(this, _AssetsController_lastKnownAccountIds, "f").size ||
1455
+ [...currentIds].some((id) => !__classPrivateFieldGet(this, _AssetsController_lastKnownAccountIds, "f").has(id));
1456
+ if (!accountsChanged) {
1457
+ return;
1458
+ }
1459
+ const hasOverlap = [...currentIds].some((id) => __classPrivateFieldGet(this, _AssetsController_lastKnownAccountIds, "f").has(id));
1460
+ if (!hasOverlap && __classPrivateFieldGet(this, _AssetsController_lastKnownAccountIds, "f").size > 0) {
1461
+ return;
1462
+ }
1463
+ log('Account tree changed with new accounts, re-subscribing', {
1464
+ previousCount: __classPrivateFieldGet(this, _AssetsController_lastKnownAccountIds, "f").size,
1465
+ currentCount: currentIds.size,
1466
+ });
1467
+ const newAccounts = accounts.filter((account) => !__classPrivateFieldGet(this, _AssetsController_lastKnownAccountIds, "f").has(account.id));
1468
+ __classPrivateFieldSet(this, _AssetsController_lastKnownAccountIds, currentIds, "f");
1469
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1470
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureDefaultTrackedAssetsSeeded).call(this);
1471
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_runAccountTreeRefresh).call(this, accounts, newAccounts).catch((error) => {
1472
+ log('Failed to refresh assets after tree change', error);
1473
+ });
1474
+ }, _AssetsController_runAccountTreeRefresh = async function _AssetsController_runAccountTreeRefresh(accounts, newAccounts = []) {
1475
+ const releaseLock = await __classPrivateFieldGet(this, _AssetsController_accountRefreshMutex, "f").acquire();
1476
+ try {
1477
+ await this.getAssets(accounts, {
1478
+ chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
1479
+ forceUpdate: true,
1480
+ });
1481
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
1482
+ if (newAccounts.length > 0) {
1483
+ await this.getAssets(newAccounts, {
1484
+ chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
1485
+ forceUpdate: true,
1486
+ });
1487
+ }
1488
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
1489
+ }
1490
+ catch (error) {
1491
+ log('Failed to fetch assets after tree change', error);
1492
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
1493
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
1494
+ }
1495
+ finally {
1496
+ releaseLock();
1497
+ }
1421
1498
  }, _AssetsController_runStartupRefresh =
1422
1499
  /**
1423
1500
  * Force-fetch balances then subscribe. Used on unlock / first startup.
@@ -1452,7 +1529,7 @@ async function _AssetsController_runStartupRefresh(accounts) {
1452
1529
  }, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
1453
1530
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
1454
1531
  }, _AssetsController_handleActiveChainsUpdate = function _AssetsController_handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
1455
- if (!__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isUiOpen).call(this) || !__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isKeyringUnlocked).call(this) || !__classPrivateFieldGet(this, _AssetsController_isEnabled, "f").call(this)) {
1532
+ if (!__classPrivateFieldGet(this, _AssetsController_uiOpen, "f") || !__classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") || !__classPrivateFieldGet(this, _AssetsController_isEnabled, "f").call(this)) {
1456
1533
  return;
1457
1534
  }
1458
1535
  log('Data source active chains changed', {
@@ -2025,6 +2102,7 @@ async function _AssetsController_executeMiddlewares(params) {
2025
2102
  selectedAccountCount: accounts.length,
2026
2103
  enabledChainCount: chainIds.length,
2027
2104
  });
2105
+ __classPrivateFieldSet(this, _AssetsController_lastKnownAccountIds, new Set(accounts.map((a) => a.id)), "f");
2028
2106
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_runStartupRefresh).call(this, accounts).catch((error) => {
2029
2107
  log('Failed to start asset tracking', error);
2030
2108
  });
@@ -2035,6 +2113,7 @@ async function _AssetsController_executeMiddlewares(params) {
2035
2113
  });
2036
2114
  __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, false, "f");
2037
2115
  __classPrivateFieldSet(this, _AssetsController_stateSizeReported, false, "f");
2116
+ __classPrivateFieldSet(this, _AssetsController_lastKnownAccountIds, new Set(), "f");
2038
2117
  // Stop price subscription first (uses direct messenger call)
2039
2118
  this.unsubscribeAssetsPrice();
2040
2119
  // Stop balance subscriptions by properly notifying data sources via messenger
@@ -2303,6 +2382,7 @@ async function _AssetsController_executeMiddlewares(params) {
2303
2382
  // EVENT HANDLERS
2304
2383
  // ============================================================================
2305
2384
  async function _AssetsController_handleAccountGroupChanged(groupId, previousGroupId = '') {
2385
+ // The selected account group can be empty during onboarding or wallet reset.
2306
2386
  if (!groupId) {
2307
2387
  return;
2308
2388
  }
@@ -2323,6 +2403,7 @@ async function _AssetsController_handleAccountGroupChanged(groupId, previousGrou
2323
2403
  groupId,
2324
2404
  previousGroupId,
2325
2405
  });
2406
+ __classPrivateFieldSet(this, _AssetsController_lastKnownAccountIds, new Set(accounts.map((a) => a.id)), "f");
2326
2407
  const releaseLock = await __classPrivateFieldGet(this, _AssetsController_accountRefreshMutex, "f").acquire();
2327
2408
  try {
2328
2409
  if (accounts.length > 0) {
@@ -2333,6 +2414,8 @@ async function _AssetsController_handleAccountGroupChanged(groupId, previousGrou
2333
2414
  }
2334
2415
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
2335
2416
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureDefaultTrackedAssetsSeeded).call(this);
2417
+ // Subscribe after seed so the price poll sees natives / defaults.
2418
+ // Balances were just force-fetched — skip AccountsApi's subscribe-time poll.
2336
2419
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this, { skipInitialFetch: true });
2337
2420
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_fetchMissingPricesWithoutCache).call(this, accounts, [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
2338
2421
  }
@@ -2430,7 +2513,7 @@ async function _AssetsController_refreshActiveChainsOnNetworkSwitch() {
2430
2513
  * @param networkState - NetworkController state after the switch.
2431
2514
  */
2432
2515
  async function _AssetsController_handleNetworkDidChange(networkState) {
2433
- if (!__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isUiOpen).call(this) || !__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isKeyringUnlocked).call(this) || !__classPrivateFieldGet(this, _AssetsController_isEnabled, "f").call(this)) {
2516
+ if (!__classPrivateFieldGet(this, _AssetsController_uiOpen, "f") || !__classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f") || !__classPrivateFieldGet(this, _AssetsController_isEnabled, "f").call(this)) {
2434
2517
  return;
2435
2518
  }
2436
2519
  const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this);