@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
@@ -9,8 +9,9 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
10
10
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
11
11
  };
12
- 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;
12
+ 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;
13
13
  import { BaseController } from "@metamask/base-controller";
14
+ import { clientControllerSelectors } from "@metamask/client-controller";
14
15
  import { isCaipChainId, isStrictHexString, parseCaipAssetType, parseCaipChainId } from "@metamask/utils";
15
16
  import { Mutex } from "async-mutex";
16
17
  import BigNumberJS from "bignumber.js";
@@ -25,6 +26,7 @@ import { StakedBalanceDataSource } from "./data-sources/StakedBalanceDataSource.
25
26
  import { TokenDataSource } from "./data-sources/TokenDataSource.mjs";
26
27
  import { projectLogger, createModuleLogger } from "./logger.mjs";
27
28
  import { DetectionMiddleware } from "./middlewares/DetectionMiddleware.mjs";
29
+ import { createParallelBalanceMiddleware, createParallelMiddleware } from "./middlewares/ParallelMiddleware.mjs";
28
30
  import { normalizeAssetId } from "./utils.mjs";
29
31
  // ============================================================================
30
32
  // CONTROLLER CONSTANTS
@@ -57,6 +59,7 @@ export function getDefaultAssetsControllerState() {
57
59
  assetsPrice: {},
58
60
  customAssets: {},
59
61
  assetPreferences: {},
62
+ selectedCurrency: 'usd',
60
63
  };
61
64
  }
62
65
  // ============================================================================
@@ -93,6 +96,12 @@ const stateMetadata = {
93
96
  includeInDebugSnapshot: false,
94
97
  usedInUi: true,
95
98
  },
99
+ selectedCurrency: {
100
+ persist: true,
101
+ includeInStateLogs: false,
102
+ includeInDebugSnapshot: false,
103
+ usedInUi: true,
104
+ },
96
105
  };
97
106
  // ============================================================================
98
107
  // HELPER FUNCTIONS
@@ -146,6 +155,9 @@ function normalizeResponse(response) {
146
155
  if (response.errors) {
147
156
  normalized.errors = { ...response.errors };
148
157
  }
158
+ if (response.updateMode) {
159
+ normalized.updateMode = response.updateMode;
160
+ }
149
161
  return normalized;
150
162
  }
151
163
  // ============================================================================
@@ -167,8 +179,10 @@ function normalizeResponse(response) {
167
179
  * based on which chains they support. When active chains change, the controller
168
180
  * dynamically adjusts subscriptions.
169
181
  *
170
- * 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
171
- * start/stop subscriptions when the wallet is unlocked or locked.
182
+ * 4. **Client + Keyring Lifecycle**: Starts subscriptions only when both the UI is
183
+ * open (ClientController) and the wallet is unlocked (KeyringController).
184
+ * Stops when either the UI closes or the keyring locks. See client-controller
185
+ * README for the combined pattern.
172
186
  *
173
187
  * ## Architecture
174
188
  *
@@ -198,6 +212,10 @@ export class AssetsController extends BaseController {
198
212
  _AssetsController_trackMetaMetricsEvent.set(this, void 0);
199
213
  /** Whether we have already reported first init fetch for this session (reset on #stop). */
200
214
  _AssetsController_firstInitFetchReported.set(this, false);
215
+ /** Whether the client (UI) is open. Combined with #keyringUnlocked for #updateActive. */
216
+ _AssetsController_uiOpen.set(this, false);
217
+ /** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
218
+ _AssetsController_keyringUnlocked.set(this, false);
201
219
  _AssetsController_controllerMutex.set(this, new Mutex());
202
220
  /**
203
221
  * Active balance subscriptions keyed by account ID.
@@ -217,36 +235,37 @@ export class AssetsController extends BaseController {
217
235
  _AssetsController_detectionMiddleware.set(this, void 0);
218
236
  _AssetsController_tokenDataSource.set(this, void 0);
219
237
  _AssetsController_unsubscribeBasicFunctionality.set(this, null);
238
+ _AssetsController_onActiveChainsUpdated.set(this, void 0);
220
239
  __classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
221
240
  __classPrivateFieldSet(this, _AssetsController_isBasicFunctionality, isBasicFunctionality ?? (() => true), "f");
222
241
  __classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
223
242
  __classPrivateFieldSet(this, _AssetsController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
224
243
  const rpcConfig = rpcDataSourceConfig ?? {};
225
- const onActiveChainsUpdated = (dataSourceName, chains, previousChains) => {
226
- this.handleActiveChainsUpdate(dataSourceName, chains, previousChains);
227
- };
244
+ __classPrivateFieldSet(this, _AssetsController_onActiveChainsUpdated, (dataSourceName, chains, previousChains) => {
245
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleActiveChainsUpdate).call(this, dataSourceName, chains, previousChains);
246
+ }, "f");
228
247
  __classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource({
229
248
  messenger: this.messenger,
230
249
  queryApiClient,
231
- onActiveChainsUpdated,
250
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
232
251
  }), "f");
233
252
  __classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource({
234
253
  queryApiClient,
235
- onActiveChainsUpdated,
254
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
236
255
  ...accountsApiDataSourceConfig,
237
256
  }), "f");
238
257
  __classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource({
239
258
  messenger: this.messenger,
240
- onActiveChainsUpdated,
259
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
241
260
  }), "f");
242
261
  __classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource({
243
262
  messenger: this.messenger,
244
- onActiveChainsUpdated,
263
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
245
264
  ...rpcConfig,
246
265
  }), "f");
247
266
  __classPrivateFieldSet(this, _AssetsController_stakedBalanceDataSource, new StakedBalanceDataSource({
248
267
  messenger: this.messenger,
249
- onActiveChainsUpdated,
268
+ onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
250
269
  ...stakedBalanceDataSourceConfig,
251
270
  }), "f");
252
271
  __classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource({
@@ -254,6 +273,7 @@ export class AssetsController extends BaseController {
254
273
  }), "f");
255
274
  __classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource({
256
275
  queryApiClient,
276
+ getSelectedCurrency: () => this.state.selectedCurrency,
257
277
  ...priceDataSourceConfig,
258
278
  }), "f");
259
279
  __classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware(), "f");
@@ -267,7 +287,7 @@ export class AssetsController extends BaseController {
267
287
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
268
288
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
269
289
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
270
- // Subscriptions start only on KeyringController:unlock -> #start(), not here.
290
+ // Subscriptions start only when both UI is open and keyring unlocked -> #updateActive().
271
291
  // Subscribe to basic-functionality changes after construction so a synchronous
272
292
  // onChange during subscribe cannot run before data sources are initialized.
273
293
  if (subscribeToBasicFunctionalityChange) {
@@ -277,52 +297,14 @@ export class AssetsController extends BaseController {
277
297
  }
278
298
  }
279
299
  }
280
- // ============================================================================
281
- // DATA SOURCE CHAIN MANAGEMENT
282
- // ============================================================================
283
300
  /**
284
- * Handle when a data source's supported chains change.
285
- * Used to refresh balance subscriptions and run a one-time fetch when a new chain is supported.
301
+ * Returns the callback passed to data sources for reporting active chain updates.
302
+ * Used by tests to simulate a data source reporting chain changes.
286
303
  *
287
- * - On any add/remove: re-subscribes to data sources so chain assignment stays correct.
288
- * - When chains are added: fetches balances for the new chains (for selected accounts on enabled networks).
289
- *
290
- * Controller does not store chains; sources report via this callback. previousChains is required for diff.
291
- *
292
- * @param dataSourceId - The identifier of the data source reporting the change.
293
- * @param activeChains - Currently active (supported and available) chain IDs for this source.
294
- * @param previousChains - Previous chains; used to compute added/removed.
304
+ * @returns The onActiveChainsUpdated callback.
295
305
  */
296
- handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
297
- if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
298
- return;
299
- }
300
- log('Data source active chains changed', {
301
- dataSourceId,
302
- chainCount: activeChains.length,
303
- chains: activeChains,
304
- });
305
- const previous = previousChains;
306
- const previousSet = new Set(previous);
307
- const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
308
- const removedChains = previous.filter((ch) => !activeChains.includes(ch));
309
- if (addedChains.length > 0 || removedChains.length > 0) {
310
- // Refresh subscriptions to use updated data source availability
311
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
312
- }
313
- // If chains were added and we have selected accounts, do one-time fetch
314
- if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
315
- const addedEnabledChains = addedChains.filter((chain) => __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").has(chain));
316
- if (addedEnabledChains.length > 0) {
317
- log('Fetching balances for newly added chains', { addedEnabledChains });
318
- this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
319
- chainIds: addedEnabledChains,
320
- forceUpdate: true,
321
- }).catch((error) => {
322
- log('Failed to fetch balance for added chains', { error });
323
- });
324
- }
325
- }
306
+ getOnActiveChainsUpdated() {
307
+ return __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f");
326
308
  }
327
309
  // ============================================================================
328
310
  // PUBLIC API: QUERY METHODS
@@ -331,6 +313,9 @@ export class AssetsController extends BaseController {
331
313
  const chainIds = options?.chainIds ?? [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")];
332
314
  const assetTypes = options?.assetTypes ?? ['fungible'];
333
315
  const dataTypes = options?.dataTypes ?? ['balance', 'metadata', 'price'];
316
+ if (accounts.length === 0 || chainIds.length === 0) {
317
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
318
+ }
334
319
  // Collect custom assets for all requested accounts
335
320
  const customAssets = [];
336
321
  for (const account of accounts) {
@@ -344,16 +329,21 @@ export class AssetsController extends BaseController {
344
329
  dataTypes,
345
330
  customAssets: customAssets.length > 0 ? customAssets : undefined,
346
331
  forceUpdate: true,
332
+ assetsForPriceUpdate: options?.assetsForPriceUpdate,
347
333
  });
348
334
  const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
349
335
  ? [
350
- __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
351
- __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
352
- __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
353
- __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
336
+ createParallelBalanceMiddleware([
337
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
338
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
339
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
340
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
341
+ ]),
354
342
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
355
- __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
356
- __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
343
+ createParallelMiddleware([
344
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
345
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
346
+ ]),
357
347
  ]
358
348
  : [
359
349
  __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
@@ -361,7 +351,12 @@ export class AssetsController extends BaseController {
361
351
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
362
352
  ];
363
353
  const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
364
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
354
+ // Default to 'merge' when fetching a subset of chains so we don't wipe
355
+ // balances from chains that weren't included in this fetch.
356
+ const isPartialChainFetch = options?.chainIds !== undefined &&
357
+ options.chainIds.length < __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size;
358
+ const updateMode = options?.updateMode ?? (isPartialChainFetch ? 'merge' : 'full');
359
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode });
365
360
  if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
366
361
  __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
367
362
  const durationMs = Date.now() - startTime;
@@ -372,7 +367,8 @@ export class AssetsController extends BaseController {
372
367
  });
373
368
  }
374
369
  }
375
- return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
370
+ const result = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
371
+ return result;
376
372
  }
377
373
  async getAssetsBalance(accounts, options) {
378
374
  // Reuse getAssets with dataTypes: ['balance'] only
@@ -423,10 +419,15 @@ export class AssetsController extends BaseController {
423
419
  * Custom assets are included in subscription and fetch operations.
424
420
  * Adding a custom asset also unhides it if it was previously hidden.
425
421
  *
422
+ * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
423
+ * flow), the token metadata is persisted immediately into `assetsInfo` so the
424
+ * UI can render it without waiting for the next pipeline fetch.
425
+ *
426
426
  * @param accountId - The account ID to add the custom asset for.
427
427
  * @param assetId - The CAIP-19 asset ID to add.
428
+ * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
428
429
  */
429
- async addCustomAsset(accountId, assetId) {
430
+ async addCustomAsset(accountId, assetId, pendingMetadata) {
430
431
  const normalizedAssetId = normalizeAssetId(assetId);
431
432
  log('Adding custom asset', { accountId, assetId: normalizedAssetId });
432
433
  this.update((state) => {
@@ -446,14 +447,37 @@ export class AssetsController extends BaseController {
446
447
  delete state.assetPreferences[normalizedAssetId];
447
448
  }
448
449
  }
450
+ // Persist metadata from the UI so the token is immediately renderable
451
+ if (pendingMetadata) {
452
+ const parsed = parseCaipAssetType(normalizedAssetId);
453
+ let tokenType = 'erc20';
454
+ if (parsed.assetNamespace === 'slip44') {
455
+ tokenType = 'native';
456
+ }
457
+ else if (parsed.assetNamespace === 'spl') {
458
+ tokenType = 'spl';
459
+ }
460
+ const assetMetadata = {
461
+ type: tokenType,
462
+ symbol: pendingMetadata.symbol,
463
+ name: pendingMetadata.name,
464
+ decimals: pendingMetadata.decimals,
465
+ image: pendingMetadata.iconUrl,
466
+ aggregators: pendingMetadata.aggregators,
467
+ occurrences: pendingMetadata.occurrences,
468
+ };
469
+ state.assetsInfo[normalizedAssetId] =
470
+ assetMetadata;
471
+ }
449
472
  });
450
- // Fetch data for the newly added custom asset
473
+ // Fetch data for the newly added custom asset (merge to preserve other chains)
451
474
  const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
452
475
  if (account) {
453
476
  const chainId = extractChainId(normalizedAssetId);
454
477
  await this.getAssets([account], {
455
478
  chainIds: [chainId],
456
479
  forceUpdate: true,
480
+ updateMode: 'merge',
457
481
  });
458
482
  }
459
483
  }
@@ -524,6 +548,34 @@ export class AssetsController extends BaseController {
524
548
  });
525
549
  }
526
550
  // ============================================================================
551
+ // CURRENT CURRENCY MANAGEMENT
552
+ // ============================================================================
553
+ /**
554
+ * Set the current currency.
555
+ *
556
+ * @param selectedCurrency - The ISO 4217 currency code to set.
557
+ */
558
+ setSelectedCurrency(selectedCurrency) {
559
+ const previousCurrency = this.state.selectedCurrency;
560
+ if (previousCurrency === selectedCurrency) {
561
+ return;
562
+ }
563
+ this.update((state) => {
564
+ state.selectedCurrency = selectedCurrency;
565
+ });
566
+ log('Current currency changed', {
567
+ previousCurrency,
568
+ selectedCurrency,
569
+ });
570
+ this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
571
+ forceUpdate: true,
572
+ dataTypes: ['price'],
573
+ assetsForPriceUpdate: Object.values(this.state.assetsBalance).flatMap((balances) => Object.keys(balances)),
574
+ }).catch((error) => {
575
+ log('Failed to fetch asset prices after current currency change', error);
576
+ });
577
+ }
578
+ // ============================================================================
527
579
  // SUBSCRIPTIONS
528
580
  // ============================================================================
529
581
  /**
@@ -601,9 +653,15 @@ export class AssetsController extends BaseController {
601
653
  hasBalance: Boolean(response.assetsBalance),
602
654
  hasPrice: Boolean(response.assetsPrice),
603
655
  });
604
- // Run through enrichment middlewares (Event Stack: Detection Token Price)
656
+ // Run through enrichment middlewares (Detection, then Token + Price in parallel)
605
657
  // Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
606
- 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 ?? {
658
+ const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
659
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
660
+ createParallelMiddleware([
661
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
662
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
663
+ ]),
664
+ ], request ?? {
607
665
  accountsWithSupportedChains: [],
608
666
  chainIds: [],
609
667
  dataTypes: ['balance', 'metadata', 'price'],
@@ -642,7 +700,7 @@ export class AssetsController extends BaseController {
642
700
  this.messenger.unregisterActionHandler('AssetsController:unhideAsset');
643
701
  }
644
702
  }
645
- _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() {
703
+ _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() {
646
704
  return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
647
705
  }, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
648
706
  return [
@@ -692,11 +750,60 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
692
750
  this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
693
751
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
694
752
  });
695
- // Keyring lifecycle: start when unlocked, stop when locked
696
- this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
697
- this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
753
+ // Client + Keyring lifecycle: only run when UI is open AND keyring is unlocked
754
+ this.messenger.subscribe('ClientController:stateChange', (isUiOpen) => {
755
+ __classPrivateFieldSet(this, _AssetsController_uiOpen, isUiOpen, "f");
756
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
757
+ }, clientControllerSelectors.selectIsUiOpen);
758
+ this.messenger.subscribe('KeyringController:unlock', () => {
759
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, true, "f");
760
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
761
+ });
762
+ this.messenger.subscribe('KeyringController:lock', () => {
763
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
764
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
765
+ });
766
+ }, _AssetsController_updateActive = function _AssetsController_updateActive() {
767
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
768
+ if (shouldRun) {
769
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
770
+ }
771
+ else {
772
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
773
+ }
698
774
  }, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
699
775
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
776
+ }, _AssetsController_handleActiveChainsUpdate = function _AssetsController_handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
777
+ if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
778
+ return;
779
+ }
780
+ log('Data source active chains changed', {
781
+ dataSourceId,
782
+ chainCount: activeChains.length,
783
+ chains: activeChains,
784
+ });
785
+ const previous = previousChains;
786
+ const previousSet = new Set(previous);
787
+ const addedChains = activeChains.filter((ch) => !previousSet.has(ch));
788
+ const removedChains = previous.filter((ch) => !activeChains.includes(ch));
789
+ if (addedChains.length > 0 || removedChains.length > 0) {
790
+ // Refresh subscriptions to use updated data source availability
791
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
792
+ }
793
+ // If chains were added and we have selected accounts, do one-time fetch
794
+ if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
795
+ const addedEnabledChains = addedChains.filter((chain) => __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").has(chain));
796
+ if (addedEnabledChains.length > 0) {
797
+ log('Fetching balances for newly added chains', { addedEnabledChains });
798
+ this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
799
+ chainIds: addedEnabledChains,
800
+ forceUpdate: true,
801
+ updateMode: 'merge',
802
+ }).catch((error) => {
803
+ log('Failed to fetch balance for added chains', { error });
804
+ });
805
+ }
806
+ }
700
807
  }, _AssetsController_executeMiddlewares =
701
808
  // ============================================================================
702
809
  // MIDDLEWARE EXECUTION
@@ -747,13 +854,46 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
747
854
  }
748
855
  }
749
856
  return { response: result.response, durationByDataSource };
750
- }, _AssetsController_updateState =
751
- // ============================================================================
752
- // STATE MANAGEMENT
753
- // ============================================================================
754
- async function _AssetsController_updateState(response) {
755
- // Normalize asset IDs (checksum EVM addresses) before storing in state
857
+ }, _AssetsController_resolveNativeAssetIds = function _AssetsController_resolveNativeAssetIds(chains) {
858
+ const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
859
+ const ids = [];
860
+ for (const chainId of chains) {
861
+ const nativeId = nativeAssetIdentifiers?.[chainId];
862
+ if (nativeId) {
863
+ ids.push(nativeId);
864
+ }
865
+ }
866
+ return ids;
867
+ }, _AssetsController_getNativeAssetIdsForEnabledChains = function _AssetsController_getNativeAssetIdsForEnabledChains() {
868
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
869
+ }, _AssetsController_getNativeAssetIdsForAccount = function _AssetsController_getNativeAssetIdsForAccount(account) {
870
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account));
871
+ }, _AssetsController_ensureNativeBalancesDefaultZero = function _AssetsController_ensureNativeBalancesDefaultZero() {
872
+ const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get);
873
+ if (accounts.length === 0) {
874
+ return;
875
+ }
876
+ this.update((state) => {
877
+ const balances = state.assetsBalance;
878
+ for (const account of accounts) {
879
+ const accountId = account.id;
880
+ const nativeAssetIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account);
881
+ if (nativeAssetIds.length === 0) {
882
+ continue;
883
+ }
884
+ if (!balances[accountId]) {
885
+ balances[accountId] = {};
886
+ }
887
+ for (const nativeAssetId of nativeAssetIds) {
888
+ if (!(nativeAssetId in balances[accountId])) {
889
+ balances[accountId][nativeAssetId] = { amount: '0' };
890
+ }
891
+ }
892
+ }
893
+ });
894
+ }, _AssetsController_updateState = async function _AssetsController_updateState(response) {
756
895
  const normalizedResponse = normalizeResponse(response);
896
+ const mode = normalizedResponse.updateMode ?? 'merge';
757
897
  const releaseLock = await __classPrivateFieldGet(this, _AssetsController_controllerMutex, "f").acquire();
758
898
  try {
759
899
  const previousState = this.state;
@@ -779,16 +919,43 @@ async function _AssetsController_updateState(response) {
779
919
  if (normalizedResponse.assetsBalance) {
780
920
  for (const [accountId, accountBalances] of Object.entries(normalizedResponse.assetsBalance)) {
781
921
  const previousBalances = previousState.assetsBalance[accountId] ?? {};
782
- if (!balances[accountId]) {
783
- balances[accountId] = {};
922
+ const customAssetIds = state.customAssets[accountId] ?? [];
923
+ // Full: response is authoritative; preserve custom assets not in response.
924
+ // Merge: response overlays previous balances.
925
+ // Callers that fetch partial data (e.g. newly added chains) must set updateMode: 'merge'.
926
+ const effective = mode === 'merge'
927
+ ? { ...previousBalances, ...accountBalances }
928
+ : (() => {
929
+ const next = {
930
+ ...accountBalances,
931
+ };
932
+ for (const customId of customAssetIds) {
933
+ if (!(customId in next)) {
934
+ const prev = previousBalances[customId];
935
+ next[customId] =
936
+ prev ?? { amount: '0' };
937
+ }
938
+ }
939
+ return next;
940
+ })();
941
+ // Ensure native tokens have an entry (0 if missing) for chains this account supports
942
+ const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
943
+ const nativeAssetIdsForAccount = account
944
+ ? __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account)
945
+ : __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForEnabledChains).call(this);
946
+ for (const nativeAssetId of nativeAssetIdsForAccount) {
947
+ if (!(nativeAssetId in effective)) {
948
+ effective[nativeAssetId] = { amount: '0' };
949
+ }
784
950
  }
785
- for (const [assetId, balance] of Object.entries(accountBalances)) {
951
+ for (const [assetId, balance] of Object.entries(effective)) {
786
952
  const previousBalance = previousBalances[assetId];
787
- const balanceData = balance;
788
- const newAmount = balanceData.amount;
953
+ const newAmount = balance.amount;
789
954
  const oldAmount = previousBalance?.amount;
790
- // Track if balance actually changed
791
- if (oldAmount !== newAmount) {
955
+ const isNewDefaultNativeZero = oldAmount === undefined &&
956
+ newAmount === '0' &&
957
+ nativeAssetIdsForAccount.includes(assetId);
958
+ if (oldAmount !== newAmount && !isNewDefaultNativeZero) {
792
959
  changedBalances.push({
793
960
  accountId,
794
961
  assetId,
@@ -797,7 +964,7 @@ async function _AssetsController_updateState(response) {
797
964
  });
798
965
  }
799
966
  }
800
- Object.assign(balances[accountId], accountBalances);
967
+ balances[accountId] = effective;
801
968
  }
802
969
  }
803
970
  // Update prices in state
@@ -941,6 +1108,7 @@ async function _AssetsController_updateState(response) {
941
1108
  enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
942
1109
  });
943
1110
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1111
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
944
1112
  this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
945
1113
  chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
946
1114
  forceUpdate: true,
@@ -975,7 +1143,7 @@ async function _AssetsController_updateState(response) {
975
1143
  }
976
1144
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
977
1145
  }, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
978
- if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
1146
+ if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0 || __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size === 0) {
979
1147
  return;
980
1148
  }
981
1149
  // Subscribe to balance updates (batched by data source)
@@ -1064,7 +1232,7 @@ async function _AssetsController_updateState(response) {
1064
1232
  }),
1065
1233
  subscriptionId: subscriptionKey,
1066
1234
  isUpdate,
1067
- onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
1235
+ onAssetsUpdate: (response, request) => this.handleAssetsUpdate(response, sourceId, request),
1068
1236
  getAssetsState: () => this.state,
1069
1237
  };
1070
1238
  source.subscribe(subscribeReq).catch((error) => {
@@ -1148,6 +1316,7 @@ async function _AssetsController_handleAccountGroupChanged() {
1148
1316
  forceUpdate: true,
1149
1317
  });
1150
1318
  }
1319
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1151
1320
  }, _AssetsController_handleEnabledNetworksChanged = async function _AssetsController_handleEnabledNetworksChanged(enabledNetworkMap) {
1152
1321
  const previousChains = __classPrivateFieldGet(this, _AssetsController_enabledChains, "f");
1153
1322
  __classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
@@ -1176,12 +1345,14 @@ async function _AssetsController_handleAccountGroupChanged() {
1176
1345
  // The data will simply not be updated until the network is re-enabled.
1177
1346
  // Refresh subscriptions for new chain set
1178
1347
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1179
- // Do one-time fetch for newly enabled chains
1348
+ // Do one-time fetch for newly enabled chains; merge so we keep existing chain balances
1180
1349
  if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
1181
1350
  await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
1182
1351
  chainIds: addedChains,
1183
1352
  forceUpdate: true,
1353
+ updateMode: 'merge',
1184
1354
  });
1185
1355
  }
1356
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1186
1357
  };
1187
1358
  //# sourceMappingURL=AssetsController.mjs.map