@metamask/assets-controller 2.0.2 → 2.1.0

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/dist/AssetsController-method-action-types.cjs.map +1 -1
  3. package/dist/AssetsController-method-action-types.d.cts +5 -0
  4. package/dist/AssetsController-method-action-types.d.cts.map +1 -1
  5. package/dist/AssetsController-method-action-types.d.mts +5 -0
  6. package/dist/AssetsController-method-action-types.d.mts.map +1 -1
  7. package/dist/AssetsController-method-action-types.mjs.map +1 -1
  8. package/dist/AssetsController.cjs +259 -88
  9. package/dist/AssetsController.cjs.map +1 -1
  10. package/dist/AssetsController.d.cts +44 -17
  11. package/dist/AssetsController.d.cts.map +1 -1
  12. package/dist/AssetsController.d.mts +44 -17
  13. package/dist/AssetsController.d.mts.map +1 -1
  14. package/dist/AssetsController.mjs +259 -88
  15. package/dist/AssetsController.mjs.map +1 -1
  16. package/dist/data-sources/AbstractDataSource.cjs.map +1 -1
  17. package/dist/data-sources/AbstractDataSource.d.cts +3 -3
  18. package/dist/data-sources/AbstractDataSource.d.cts.map +1 -1
  19. package/dist/data-sources/AbstractDataSource.d.mts +3 -3
  20. package/dist/data-sources/AbstractDataSource.d.mts.map +1 -1
  21. package/dist/data-sources/AbstractDataSource.mjs.map +1 -1
  22. package/dist/data-sources/AccountsApiDataSource.cjs +1 -0
  23. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  24. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  25. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  26. package/dist/data-sources/AccountsApiDataSource.mjs +1 -0
  27. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  28. package/dist/data-sources/BackendWebsocketDataSource.cjs +18 -6
  29. package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
  30. package/dist/data-sources/BackendWebsocketDataSource.d.cts +2 -2
  31. package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
  32. package/dist/data-sources/BackendWebsocketDataSource.d.mts +2 -2
  33. package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
  34. package/dist/data-sources/BackendWebsocketDataSource.mjs +15 -6
  35. package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
  36. package/dist/data-sources/PriceDataSource.cjs +20 -14
  37. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  38. package/dist/data-sources/PriceDataSource.d.cts +2 -2
  39. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  40. package/dist/data-sources/PriceDataSource.d.mts +2 -2
  41. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  42. package/dist/data-sources/PriceDataSource.mjs +20 -14
  43. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  44. package/dist/data-sources/RpcDataSource.cjs +23 -4
  45. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  46. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  47. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  48. package/dist/data-sources/RpcDataSource.mjs +23 -4
  49. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  50. package/dist/data-sources/SnapDataSource.cjs +3 -2
  51. package/dist/data-sources/SnapDataSource.cjs.map +1 -1
  52. package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
  53. package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
  54. package/dist/data-sources/SnapDataSource.mjs +3 -2
  55. package/dist/data-sources/SnapDataSource.mjs.map +1 -1
  56. package/dist/data-sources/StakedBalanceDataSource.cjs +41 -3
  57. package/dist/data-sources/StakedBalanceDataSource.cjs.map +1 -1
  58. package/dist/data-sources/StakedBalanceDataSource.d.cts.map +1 -1
  59. package/dist/data-sources/StakedBalanceDataSource.d.mts.map +1 -1
  60. package/dist/data-sources/StakedBalanceDataSource.mjs +41 -3
  61. package/dist/data-sources/StakedBalanceDataSource.mjs.map +1 -1
  62. package/dist/data-sources/TokenDataSource.cjs +1 -0
  63. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  64. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  65. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  66. package/dist/data-sources/TokenDataSource.mjs +1 -0
  67. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  68. package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs.map +1 -1
  69. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts.map +1 -1
  70. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts.map +1 -1
  71. package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs.map +1 -1
  72. package/dist/index.cjs.map +1 -1
  73. package/dist/index.d.cts +2 -1
  74. package/dist/index.d.cts.map +1 -1
  75. package/dist/index.d.mts +2 -1
  76. package/dist/index.d.mts.map +1 -1
  77. package/dist/index.mjs.map +1 -1
  78. package/dist/middlewares/DetectionMiddleware.cjs +44 -27
  79. package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
  80. package/dist/middlewares/DetectionMiddleware.d.cts +15 -9
  81. package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
  82. package/dist/middlewares/DetectionMiddleware.d.mts +15 -9
  83. package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
  84. package/dist/middlewares/DetectionMiddleware.mjs +44 -27
  85. package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
  86. package/dist/middlewares/ParallelMiddleware.cjs +216 -0
  87. package/dist/middlewares/ParallelMiddleware.cjs.map +1 -0
  88. package/dist/middlewares/ParallelMiddleware.d.cts +45 -0
  89. package/dist/middlewares/ParallelMiddleware.d.cts.map +1 -0
  90. package/dist/middlewares/ParallelMiddleware.d.mts +45 -0
  91. package/dist/middlewares/ParallelMiddleware.d.mts.map +1 -0
  92. package/dist/middlewares/ParallelMiddleware.mjs +214 -0
  93. package/dist/middlewares/ParallelMiddleware.mjs.map +1 -0
  94. package/dist/middlewares/index.cjs +5 -1
  95. package/dist/middlewares/index.cjs.map +1 -1
  96. package/dist/middlewares/index.d.cts +2 -0
  97. package/dist/middlewares/index.d.cts.map +1 -1
  98. package/dist/middlewares/index.d.mts +2 -0
  99. package/dist/middlewares/index.d.mts.map +1 -1
  100. package/dist/middlewares/index.mjs +1 -0
  101. package/dist/middlewares/index.mjs.map +1 -1
  102. package/dist/types.cjs.map +1 -1
  103. package/dist/types.d.cts +16 -0
  104. package/dist/types.d.cts.map +1 -1
  105. package/dist/types.d.mts +16 -0
  106. package/dist/types.d.mts.map +1 -1
  107. package/dist/types.mjs.map +1 -1
  108. package/package.json +6 -5
@@ -13,10 +13,11 @@ 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_trackMetaMetricsEvent, _AssetsController_firstInitFetchReported, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
16
+ var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trackMetaMetricsEvent, _AssetsController_firstInitFetchReported, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_updateActive, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
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");
20
+ const client_controller_1 = require("@metamask/client-controller");
20
21
  const utils_1 = require("@metamask/utils");
21
22
  const async_mutex_1 = require("async-mutex");
22
23
  const bignumber_js_1 = __importDefault(require("bignumber.js"));
@@ -30,6 +31,7 @@ const StakedBalanceDataSource_1 = require("./data-sources/StakedBalanceDataSourc
30
31
  const TokenDataSource_1 = require("./data-sources/TokenDataSource.cjs");
31
32
  const logger_1 = require("./logger.cjs");
32
33
  const DetectionMiddleware_1 = require("./middlewares/DetectionMiddleware.cjs");
34
+ const ParallelMiddleware_1 = require("./middlewares/ParallelMiddleware.cjs");
33
35
  const utils_2 = require("./utils.cjs");
34
36
  // ============================================================================
35
37
  // CONTROLLER CONSTANTS
@@ -62,6 +64,7 @@ function getDefaultAssetsControllerState() {
62
64
  assetsPrice: {},
63
65
  customAssets: {},
64
66
  assetPreferences: {},
67
+ selectedCurrency: 'usd',
65
68
  };
66
69
  }
67
70
  exports.getDefaultAssetsControllerState = getDefaultAssetsControllerState;
@@ -99,6 +102,12 @@ const stateMetadata = {
99
102
  includeInDebugSnapshot: false,
100
103
  usedInUi: true,
101
104
  },
105
+ selectedCurrency: {
106
+ persist: true,
107
+ includeInStateLogs: false,
108
+ includeInDebugSnapshot: false,
109
+ usedInUi: true,
110
+ },
102
111
  };
103
112
  // ============================================================================
104
113
  // HELPER FUNCTIONS
@@ -152,6 +161,9 @@ function normalizeResponse(response) {
152
161
  if (response.errors) {
153
162
  normalized.errors = { ...response.errors };
154
163
  }
164
+ if (response.updateMode) {
165
+ normalized.updateMode = response.updateMode;
166
+ }
155
167
  return normalized;
156
168
  }
157
169
  // ============================================================================
@@ -173,8 +185,10 @@ function normalizeResponse(response) {
173
185
  * based on which chains they support. When active chains change, the controller
174
186
  * dynamically adjusts subscriptions.
175
187
  *
176
- * 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
177
- * start/stop subscriptions when the wallet is unlocked or locked.
188
+ * 4. **Client + Keyring Lifecycle**: Starts subscriptions only when both the UI is
189
+ * open (ClientController) and the wallet is unlocked (KeyringController).
190
+ * Stops when either the UI closes or the keyring locks. See client-controller
191
+ * README for the combined pattern.
178
192
  *
179
193
  * ## Architecture
180
194
  *
@@ -204,6 +218,10 @@ class AssetsController extends base_controller_1.BaseController {
204
218
  _AssetsController_trackMetaMetricsEvent.set(this, void 0);
205
219
  /** Whether we have already reported first init fetch for this session (reset on #stop). */
206
220
  _AssetsController_firstInitFetchReported.set(this, false);
221
+ /** Whether the client (UI) is open. Combined with #keyringUnlocked for #updateActive. */
222
+ _AssetsController_uiOpen.set(this, false);
223
+ /** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
224
+ _AssetsController_keyringUnlocked.set(this, false);
207
225
  _AssetsController_controllerMutex.set(this, new async_mutex_1.Mutex());
208
226
  /**
209
227
  * Active balance subscriptions keyed by account ID.
@@ -223,36 +241,37 @@ class AssetsController extends base_controller_1.BaseController {
223
241
  _AssetsController_detectionMiddleware.set(this, void 0);
224
242
  _AssetsController_tokenDataSource.set(this, void 0);
225
243
  _AssetsController_unsubscribeBasicFunctionality.set(this, null);
244
+ _AssetsController_onActiveChainsUpdated.set(this, void 0);
226
245
  __classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
227
246
  __classPrivateFieldSet(this, _AssetsController_isBasicFunctionality, isBasicFunctionality ?? (() => true), "f");
228
247
  __classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
229
248
  __classPrivateFieldSet(this, _AssetsController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
230
249
  const rpcConfig = rpcDataSourceConfig ?? {};
231
- const onActiveChainsUpdated = (dataSourceName, chains, previousChains) => {
232
- this.handleActiveChainsUpdate(dataSourceName, chains, previousChains);
233
- };
250
+ __classPrivateFieldSet(this, _AssetsController_onActiveChainsUpdated, (dataSourceName, chains, previousChains) => {
251
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleActiveChainsUpdate).call(this, dataSourceName, chains, previousChains);
252
+ }, "f");
234
253
  __classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource_1.BackendWebsocketDataSource({
235
254
  messenger: this.messenger,
236
255
  queryApiClient,
237
- onActiveChainsUpdated,
256
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
238
257
  }), "f");
239
258
  __classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource_1.AccountsApiDataSource({
240
259
  queryApiClient,
241
- onActiveChainsUpdated,
260
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
242
261
  ...accountsApiDataSourceConfig,
243
262
  }), "f");
244
263
  __classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource_1.SnapDataSource({
245
264
  messenger: this.messenger,
246
- onActiveChainsUpdated,
265
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
247
266
  }), "f");
248
267
  __classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource_1.RpcDataSource({
249
268
  messenger: this.messenger,
250
- onActiveChainsUpdated,
269
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
251
270
  ...rpcConfig,
252
271
  }), "f");
253
272
  __classPrivateFieldSet(this, _AssetsController_stakedBalanceDataSource, new StakedBalanceDataSource_1.StakedBalanceDataSource({
254
273
  messenger: this.messenger,
255
- onActiveChainsUpdated,
274
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
256
275
  ...stakedBalanceDataSourceConfig,
257
276
  }), "f");
258
277
  __classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource_1.TokenDataSource({
@@ -260,6 +279,7 @@ class AssetsController extends base_controller_1.BaseController {
260
279
  }), "f");
261
280
  __classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource_1.PriceDataSource({
262
281
  queryApiClient,
282
+ getSelectedCurrency: () => this.state.selectedCurrency,
263
283
  ...priceDataSourceConfig,
264
284
  }), "f");
265
285
  __classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware_1.DetectionMiddleware(), "f");
@@ -273,7 +293,7 @@ class AssetsController extends base_controller_1.BaseController {
273
293
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
274
294
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
275
295
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
276
- // Subscriptions start only on KeyringController:unlock -> #start(), not here.
296
+ // Subscriptions start only when both UI is open and keyring unlocked -> #updateActive().
277
297
  // Subscribe to basic-functionality changes after construction so a synchronous
278
298
  // onChange during subscribe cannot run before data sources are initialized.
279
299
  if (subscribeToBasicFunctionalityChange) {
@@ -283,52 +303,14 @@ class AssetsController extends base_controller_1.BaseController {
283
303
  }
284
304
  }
285
305
  }
286
- // ============================================================================
287
- // DATA SOURCE CHAIN MANAGEMENT
288
- // ============================================================================
289
306
  /**
290
- * Handle when a data source's supported chains change.
291
- * Used to refresh balance subscriptions and run a one-time fetch when a new chain is supported.
307
+ * Returns the callback passed to data sources for reporting active chain updates.
308
+ * Used by tests to simulate a data source reporting chain changes.
292
309
  *
293
- * - On any add/remove: re-subscribes to data sources so chain assignment stays correct.
294
- * - When chains are added: fetches balances for the new chains (for selected accounts on enabled networks).
295
- *
296
- * Controller does not store chains; sources report via this callback. previousChains is required for diff.
297
- *
298
- * @param dataSourceId - The identifier of the data source reporting the change.
299
- * @param activeChains - Currently active (supported and available) chain IDs for this source.
300
- * @param previousChains - Previous chains; used to compute added/removed.
310
+ * @returns The onActiveChainsUpdated callback.
301
311
  */
302
- handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
303
- if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
304
- return;
305
- }
306
- log('Data source active chains changed', {
307
- dataSourceId,
308
- chainCount: activeChains.length,
309
- chains: activeChains,
310
- });
311
- const previous = previousChains;
312
- const previousSet = new Set(previous);
313
- const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
314
- const removedChains = previous.filter((ch) => !activeChains.includes(ch));
315
- if (addedChains.length > 0 || removedChains.length > 0) {
316
- // Refresh subscriptions to use updated data source availability
317
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
318
- }
319
- // If chains were added and we have selected accounts, do one-time fetch
320
- if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
321
- const addedEnabledChains = addedChains.filter((chain) => __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").has(chain));
322
- if (addedEnabledChains.length > 0) {
323
- log('Fetching balances for newly added chains', { addedEnabledChains });
324
- this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
325
- chainIds: addedEnabledChains,
326
- forceUpdate: true,
327
- }).catch((error) => {
328
- log('Failed to fetch balance for added chains', { error });
329
- });
330
- }
331
- }
312
+ getOnActiveChainsUpdated() {
313
+ return __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f");
332
314
  }
333
315
  // ============================================================================
334
316
  // PUBLIC API: QUERY METHODS
@@ -337,6 +319,9 @@ class AssetsController extends base_controller_1.BaseController {
337
319
  const chainIds = options?.chainIds ?? [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")];
338
320
  const assetTypes = options?.assetTypes ?? ['fungible'];
339
321
  const dataTypes = options?.dataTypes ?? ['balance', 'metadata', 'price'];
322
+ if (accounts.length === 0 || chainIds.length === 0) {
323
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
324
+ }
340
325
  // Collect custom assets for all requested accounts
341
326
  const customAssets = [];
342
327
  for (const account of accounts) {
@@ -350,16 +335,21 @@ class AssetsController extends base_controller_1.BaseController {
350
335
  dataTypes,
351
336
  customAssets: customAssets.length > 0 ? customAssets : undefined,
352
337
  forceUpdate: true,
338
+ assetsForPriceUpdate: options?.assetsForPriceUpdate,
353
339
  });
354
340
  const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
355
341
  ? [
356
- __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
357
- __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
358
- __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
359
- __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
342
+ (0, ParallelMiddleware_1.createParallelBalanceMiddleware)([
343
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
344
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
345
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
346
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
347
+ ]),
360
348
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
361
- __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
362
- __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
349
+ (0, ParallelMiddleware_1.createParallelMiddleware)([
350
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
351
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
352
+ ]),
363
353
  ]
364
354
  : [
365
355
  __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
@@ -367,7 +357,12 @@ class AssetsController extends base_controller_1.BaseController {
367
357
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
368
358
  ];
369
359
  const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
370
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
360
+ // Default to 'merge' when fetching a subset of chains so we don't wipe
361
+ // balances from chains that weren't included in this fetch.
362
+ const isPartialChainFetch = options?.chainIds !== undefined &&
363
+ options.chainIds.length < __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size;
364
+ const updateMode = options?.updateMode ?? (isPartialChainFetch ? 'merge' : 'full');
365
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode });
371
366
  if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
372
367
  __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
373
368
  const durationMs = Date.now() - startTime;
@@ -378,7 +373,8 @@ class AssetsController extends base_controller_1.BaseController {
378
373
  });
379
374
  }
380
375
  }
381
- return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
376
+ const result = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
377
+ return result;
382
378
  }
383
379
  async getAssetsBalance(accounts, options) {
384
380
  // Reuse getAssets with dataTypes: ['balance'] only
@@ -429,10 +425,15 @@ class AssetsController extends base_controller_1.BaseController {
429
425
  * Custom assets are included in subscription and fetch operations.
430
426
  * Adding a custom asset also unhides it if it was previously hidden.
431
427
  *
428
+ * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
429
+ * flow), the token metadata is persisted immediately into `assetsInfo` so the
430
+ * UI can render it without waiting for the next pipeline fetch.
431
+ *
432
432
  * @param accountId - The account ID to add the custom asset for.
433
433
  * @param assetId - The CAIP-19 asset ID to add.
434
+ * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
434
435
  */
435
- async addCustomAsset(accountId, assetId) {
436
+ async addCustomAsset(accountId, assetId, pendingMetadata) {
436
437
  const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
437
438
  log('Adding custom asset', { accountId, assetId: normalizedAssetId });
438
439
  this.update((state) => {
@@ -452,14 +453,37 @@ class AssetsController extends base_controller_1.BaseController {
452
453
  delete state.assetPreferences[normalizedAssetId];
453
454
  }
454
455
  }
456
+ // Persist metadata from the UI so the token is immediately renderable
457
+ if (pendingMetadata) {
458
+ const parsed = (0, utils_1.parseCaipAssetType)(normalizedAssetId);
459
+ let tokenType = 'erc20';
460
+ if (parsed.assetNamespace === 'slip44') {
461
+ tokenType = 'native';
462
+ }
463
+ else if (parsed.assetNamespace === 'spl') {
464
+ tokenType = 'spl';
465
+ }
466
+ const assetMetadata = {
467
+ type: tokenType,
468
+ symbol: pendingMetadata.symbol,
469
+ name: pendingMetadata.name,
470
+ decimals: pendingMetadata.decimals,
471
+ image: pendingMetadata.iconUrl,
472
+ aggregators: pendingMetadata.aggregators,
473
+ occurrences: pendingMetadata.occurrences,
474
+ };
475
+ state.assetsInfo[normalizedAssetId] =
476
+ assetMetadata;
477
+ }
455
478
  });
456
- // Fetch data for the newly added custom asset
479
+ // Fetch data for the newly added custom asset (merge to preserve other chains)
457
480
  const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
458
481
  if (account) {
459
482
  const chainId = extractChainId(normalizedAssetId);
460
483
  await this.getAssets([account], {
461
484
  chainIds: [chainId],
462
485
  forceUpdate: true,
486
+ updateMode: 'merge',
463
487
  });
464
488
  }
465
489
  }
@@ -530,6 +554,34 @@ class AssetsController extends base_controller_1.BaseController {
530
554
  });
531
555
  }
532
556
  // ============================================================================
557
+ // CURRENT CURRENCY MANAGEMENT
558
+ // ============================================================================
559
+ /**
560
+ * Set the current currency.
561
+ *
562
+ * @param selectedCurrency - The ISO 4217 currency code to set.
563
+ */
564
+ setSelectedCurrency(selectedCurrency) {
565
+ const previousCurrency = this.state.selectedCurrency;
566
+ if (previousCurrency === selectedCurrency) {
567
+ return;
568
+ }
569
+ this.update((state) => {
570
+ state.selectedCurrency = selectedCurrency;
571
+ });
572
+ log('Current currency changed', {
573
+ previousCurrency,
574
+ selectedCurrency,
575
+ });
576
+ this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
577
+ forceUpdate: true,
578
+ dataTypes: ['price'],
579
+ assetsForPriceUpdate: Object.values(this.state.assetsBalance).flatMap((balances) => Object.keys(balances)),
580
+ }).catch((error) => {
581
+ log('Failed to fetch asset prices after current currency change', error);
582
+ });
583
+ }
584
+ // ============================================================================
533
585
  // SUBSCRIPTIONS
534
586
  // ============================================================================
535
587
  /**
@@ -607,9 +659,15 @@ class AssetsController extends base_controller_1.BaseController {
607
659
  hasBalance: Boolean(response.assetsBalance),
608
660
  hasPrice: Boolean(response.assetsPrice),
609
661
  });
610
- // Run through enrichment middlewares (Event Stack: Detection Token Price)
662
+ // Run through enrichment middlewares (Detection, then Token + Price in parallel)
611
663
  // Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
612
- const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"), __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"), __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f")], request ?? {
664
+ const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
665
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
666
+ (0, ParallelMiddleware_1.createParallelMiddleware)([
667
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
668
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
669
+ ]),
670
+ ], request ?? {
613
671
  accountsWithSupportedChains: [],
614
672
  chainIds: [],
615
673
  dataTypes: ['balance', 'metadata', 'price'],
@@ -649,7 +707,7 @@ class AssetsController extends base_controller_1.BaseController {
649
707
  }
650
708
  }
651
709
  exports.AssetsController = AssetsController;
652
- _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trackMetaMetricsEvent = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_backendWebsocketDataSource = 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_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
710
+ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trackMetaMetricsEvent = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_backendWebsocketDataSource = 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_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_onActiveChainsUpdated = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
653
711
  return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
654
712
  }, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
655
713
  return [
@@ -699,11 +757,60 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
699
757
  this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
700
758
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
701
759
  });
702
- // Keyring lifecycle: start when unlocked, stop when locked
703
- this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
704
- this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
760
+ // Client + Keyring lifecycle: only run when UI is open AND keyring is unlocked
761
+ this.messenger.subscribe('ClientController:stateChange', (isUiOpen) => {
762
+ __classPrivateFieldSet(this, _AssetsController_uiOpen, isUiOpen, "f");
763
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
764
+ }, client_controller_1.clientControllerSelectors.selectIsUiOpen);
765
+ this.messenger.subscribe('KeyringController:unlock', () => {
766
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, true, "f");
767
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
768
+ });
769
+ this.messenger.subscribe('KeyringController:lock', () => {
770
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
771
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
772
+ });
773
+ }, _AssetsController_updateActive = function _AssetsController_updateActive() {
774
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
775
+ if (shouldRun) {
776
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
777
+ }
778
+ else {
779
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
780
+ }
705
781
  }, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
706
782
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
783
+ }, _AssetsController_handleActiveChainsUpdate = function _AssetsController_handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
784
+ if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
785
+ return;
786
+ }
787
+ log('Data source active chains changed', {
788
+ dataSourceId,
789
+ chainCount: activeChains.length,
790
+ chains: activeChains,
791
+ });
792
+ const previous = previousChains;
793
+ const previousSet = new Set(previous);
794
+ const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
795
+ const removedChains = previous.filter((ch) => !activeChains.includes(ch));
796
+ if (addedChains.length > 0 || removedChains.length > 0) {
797
+ // Refresh subscriptions to use updated data source availability
798
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
799
+ }
800
+ // If chains were added and we have selected accounts, do one-time fetch
801
+ if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
802
+ const addedEnabledChains = addedChains.filter((chain) => __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").has(chain));
803
+ if (addedEnabledChains.length > 0) {
804
+ log('Fetching balances for newly added chains', { addedEnabledChains });
805
+ this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
806
+ chainIds: addedEnabledChains,
807
+ forceUpdate: true,
808
+ updateMode: 'merge',
809
+ }).catch((error) => {
810
+ log('Failed to fetch balance for added chains', { error });
811
+ });
812
+ }
813
+ }
707
814
  }, _AssetsController_executeMiddlewares =
708
815
  // ============================================================================
709
816
  // MIDDLEWARE EXECUTION
@@ -754,13 +861,46 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
754
861
  }
755
862
  }
756
863
  return { response: result.response, durationByDataSource };
757
- }, _AssetsController_updateState =
758
- // ============================================================================
759
- // STATE MANAGEMENT
760
- // ============================================================================
761
- async function _AssetsController_updateState(response) {
762
- // Normalize asset IDs (checksum EVM addresses) before storing in state
864
+ }, _AssetsController_resolveNativeAssetIds = function _AssetsController_resolveNativeAssetIds(chains) {
865
+ const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
866
+ const ids = [];
867
+ for (const chainId of chains) {
868
+ const nativeId = nativeAssetIdentifiers?.[chainId];
869
+ if (nativeId) {
870
+ ids.push(nativeId);
871
+ }
872
+ }
873
+ return ids;
874
+ }, _AssetsController_getNativeAssetIdsForEnabledChains = function _AssetsController_getNativeAssetIdsForEnabledChains() {
875
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
876
+ }, _AssetsController_getNativeAssetIdsForAccount = function _AssetsController_getNativeAssetIdsForAccount(account) {
877
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account));
878
+ }, _AssetsController_ensureNativeBalancesDefaultZero = function _AssetsController_ensureNativeBalancesDefaultZero() {
879
+ const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get);
880
+ if (accounts.length === 0) {
881
+ return;
882
+ }
883
+ this.update((state) => {
884
+ const balances = state.assetsBalance;
885
+ for (const account of accounts) {
886
+ const accountId = account.id;
887
+ const nativeAssetIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account);
888
+ if (nativeAssetIds.length === 0) {
889
+ continue;
890
+ }
891
+ if (!balances[accountId]) {
892
+ balances[accountId] = {};
893
+ }
894
+ for (const nativeAssetId of nativeAssetIds) {
895
+ if (!(nativeAssetId in balances[accountId])) {
896
+ balances[accountId][nativeAssetId] = { amount: '0' };
897
+ }
898
+ }
899
+ }
900
+ });
901
+ }, _AssetsController_updateState = async function _AssetsController_updateState(response) {
763
902
  const normalizedResponse = normalizeResponse(response);
903
+ const mode = normalizedResponse.updateMode ?? 'merge';
764
904
  const releaseLock = await __classPrivateFieldGet(this, _AssetsController_controllerMutex, "f").acquire();
765
905
  try {
766
906
  const previousState = this.state;
@@ -786,16 +926,43 @@ async function _AssetsController_updateState(response) {
786
926
  if (normalizedResponse.assetsBalance) {
787
927
  for (const [accountId, accountBalances] of Object.entries(normalizedResponse.assetsBalance)) {
788
928
  const previousBalances = previousState.assetsBalance[accountId] ?? {};
789
- if (!balances[accountId]) {
790
- balances[accountId] = {};
929
+ const customAssetIds = state.customAssets[accountId] ?? [];
930
+ // Full: response is authoritative; preserve custom assets not in response.
931
+ // Merge: response overlays previous balances.
932
+ // Callers that fetch partial data (e.g. newly added chains) must set updateMode: 'merge'.
933
+ const effective = mode === 'merge'
934
+ ? { ...previousBalances, ...accountBalances }
935
+ : (() => {
936
+ const next = {
937
+ ...accountBalances,
938
+ };
939
+ for (const customId of customAssetIds) {
940
+ if (!(customId in next)) {
941
+ const prev = previousBalances[customId];
942
+ next[customId] =
943
+ prev ?? { amount: '0' };
944
+ }
945
+ }
946
+ return next;
947
+ })();
948
+ // Ensure native tokens have an entry (0 if missing) for chains this account supports
949
+ const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
950
+ const nativeAssetIdsForAccount = account
951
+ ? __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account)
952
+ : __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForEnabledChains).call(this);
953
+ for (const nativeAssetId of nativeAssetIdsForAccount) {
954
+ if (!(nativeAssetId in effective)) {
955
+ effective[nativeAssetId] = { amount: '0' };
956
+ }
791
957
  }
792
- for (const [assetId, balance] of Object.entries(accountBalances)) {
958
+ for (const [assetId, balance] of Object.entries(effective)) {
793
959
  const previousBalance = previousBalances[assetId];
794
- const balanceData = balance;
795
- const newAmount = balanceData.amount;
960
+ const newAmount = balance.amount;
796
961
  const oldAmount = previousBalance?.amount;
797
- // Track if balance actually changed
798
- if (oldAmount !== newAmount) {
962
+ const isNewDefaultNativeZero = oldAmount === undefined &&
963
+ newAmount === '0' &&
964
+ nativeAssetIdsForAccount.includes(assetId);
965
+ if (oldAmount !== newAmount && !isNewDefaultNativeZero) {
799
966
  changedBalances.push({
800
967
  accountId,
801
968
  assetId,
@@ -804,7 +971,7 @@ async function _AssetsController_updateState(response) {
804
971
  });
805
972
  }
806
973
  }
807
- Object.assign(balances[accountId], accountBalances);
974
+ balances[accountId] = effective;
808
975
  }
809
976
  }
810
977
  // Update prices in state
@@ -948,6 +1115,7 @@ async function _AssetsController_updateState(response) {
948
1115
  enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
949
1116
  });
950
1117
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1118
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
951
1119
  this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
952
1120
  chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
953
1121
  forceUpdate: true,
@@ -982,7 +1150,7 @@ async function _AssetsController_updateState(response) {
982
1150
  }
983
1151
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
984
1152
  }, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
985
- if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
1153
+ if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0 || __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size === 0) {
986
1154
  return;
987
1155
  }
988
1156
  // Subscribe to balance updates (batched by data source)
@@ -1071,7 +1239,7 @@ async function _AssetsController_updateState(response) {
1071
1239
  }),
1072
1240
  subscriptionId: subscriptionKey,
1073
1241
  isUpdate,
1074
- onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
1242
+ onAssetsUpdate: (response, request) => this.handleAssetsUpdate(response, sourceId, request),
1075
1243
  getAssetsState: () => this.state,
1076
1244
  };
1077
1245
  source.subscribe(subscribeReq).catch((error) => {
@@ -1155,6 +1323,7 @@ async function _AssetsController_handleAccountGroupChanged() {
1155
1323
  forceUpdate: true,
1156
1324
  });
1157
1325
  }
1326
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1158
1327
  }, _AssetsController_handleEnabledNetworksChanged = async function _AssetsController_handleEnabledNetworksChanged(enabledNetworkMap) {
1159
1328
  const previousChains = __classPrivateFieldGet(this, _AssetsController_enabledChains, "f");
1160
1329
  __classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
@@ -1183,12 +1352,14 @@ async function _AssetsController_handleAccountGroupChanged() {
1183
1352
  // The data will simply not be updated until the network is re-enabled.
1184
1353
  // Refresh subscriptions for new chain set
1185
1354
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1186
- // Do one-time fetch for newly enabled chains
1355
+ // Do one-time fetch for newly enabled chains; merge so we keep existing chain balances
1187
1356
  if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
1188
1357
  await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
1189
1358
  chainIds: addedChains,
1190
1359
  forceUpdate: true,
1360
+ updateMode: 'merge',
1191
1361
  });
1192
1362
  }
1363
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1193
1364
  };
1194
1365
  //# sourceMappingURL=AssetsController.cjs.map