@metamask-previews/assets-controller 2.0.2-preview-4c504af → 2.0.2-preview-702bd3940

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
24
24
 
25
25
  ### Fixed
26
26
 
27
+ - Default `assetsBalance` to `0` for native tokens of each account's supported chains using `NetworkEnablementController.nativeAssetIdentifiers`, so native entries are always present in state even before data sources respond ([#8036](https://github.com/MetaMask/core/pull/8036))
28
+ - Auto-select `'merge'` update mode in `getAssets` when `chainIds` is a subset of enabled chains, preventing partial-chain fetches (e.g. after a swap, adding a custom asset, or data-source chain changes) from wiping balances of other chains ([#8036](https://github.com/MetaMask/core/pull/8036))
27
29
  - Convert WebSocket balance updates in `BackendWebsocketDataSource` from raw smallest-units to human-readable amounts using asset decimals (same behavior as RPC/Accounts API), so `assetsBalance` remains consistent across data sources ([#8032](https://github.com/MetaMask/core/pull/8032))
28
30
  - Include all assets from balance and each account's custom assets from state in `detectedAssets`, so prices and metadata are fetched for existing assets and custom tokens (previously only assets without metadata were included, so existing assets did not get prices) ([#8021](https://github.com/MetaMask/core/pull/8021))
29
31
  - Request `includeAggregators: true` when fetching token metadata from the v3 assets API so aggregator data is returned and stored in `assetsInfo` ([#8021](https://github.com/MetaMask/core/pull/8021))
@@ -13,7 +13,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_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_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_updateActive, _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_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_updateActive, _AssetsController_registerActionHandlers, _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");
@@ -343,6 +343,7 @@ class AssetsController extends base_controller_1.BaseController {
343
343
  this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
344
344
  chainIds: addedEnabledChains,
345
345
  forceUpdate: true,
346
+ updateMode: 'merge',
346
347
  }).catch((error) => {
347
348
  log('Failed to fetch balance for added chains', { error });
348
349
  });
@@ -394,7 +395,12 @@ class AssetsController extends base_controller_1.BaseController {
394
395
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
395
396
  ];
396
397
  const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
397
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode: 'full' });
398
+ // Default to 'merge' when fetching a subset of chains so we don't wipe
399
+ // balances from chains that weren't included in this fetch.
400
+ const isPartialChainFetch = options?.chainIds !== undefined &&
401
+ options.chainIds.length < __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size;
402
+ const updateMode = options?.updateMode ?? (isPartialChainFetch ? 'merge' : 'full');
403
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode });
398
404
  if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
399
405
  __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
400
406
  const durationMs = Date.now() - startTime;
@@ -508,13 +514,14 @@ class AssetsController extends base_controller_1.BaseController {
508
514
  assetMetadata;
509
515
  }
510
516
  });
511
- // Fetch data for the newly added custom asset
517
+ // Fetch data for the newly added custom asset (merge to preserve other chains)
512
518
  const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
513
519
  if (account) {
514
520
  const chainId = extractChainId(normalizedAssetId);
515
521
  await this.getAssets([account], {
516
522
  chainIds: [chainId],
517
523
  forceUpdate: true,
524
+ updateMode: 'merge',
518
525
  });
519
526
  }
520
527
  }
@@ -861,11 +868,44 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
861
868
  }
862
869
  }
863
870
  return { response: result.response, durationByDataSource };
864
- }, _AssetsController_updateState =
865
- // ============================================================================
866
- // STATE MANAGEMENT
867
- // ============================================================================
868
- async function _AssetsController_updateState(response) {
871
+ }, _AssetsController_resolveNativeAssetIds = function _AssetsController_resolveNativeAssetIds(chains) {
872
+ const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
873
+ const ids = [];
874
+ for (const chainId of chains) {
875
+ const nativeId = nativeAssetIdentifiers?.[chainId];
876
+ if (nativeId) {
877
+ ids.push(nativeId);
878
+ }
879
+ }
880
+ return ids;
881
+ }, _AssetsController_getNativeAssetIdsForEnabledChains = function _AssetsController_getNativeAssetIdsForEnabledChains() {
882
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
883
+ }, _AssetsController_getNativeAssetIdsForAccount = function _AssetsController_getNativeAssetIdsForAccount(account) {
884
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_resolveNativeAssetIds).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account));
885
+ }, _AssetsController_ensureNativeBalancesDefaultZero = function _AssetsController_ensureNativeBalancesDefaultZero() {
886
+ const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get);
887
+ if (accounts.length === 0) {
888
+ return;
889
+ }
890
+ this.update((state) => {
891
+ const balances = state.assetsBalance;
892
+ for (const account of accounts) {
893
+ const accountId = account.id;
894
+ const nativeAssetIds = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account);
895
+ if (nativeAssetIds.length === 0) {
896
+ continue;
897
+ }
898
+ if (!balances[accountId]) {
899
+ balances[accountId] = {};
900
+ }
901
+ for (const nativeAssetId of nativeAssetIds) {
902
+ if (!(nativeAssetId in balances[accountId])) {
903
+ balances[accountId][nativeAssetId] = { amount: '0' };
904
+ }
905
+ }
906
+ }
907
+ });
908
+ }, _AssetsController_updateState = async function _AssetsController_updateState(response) {
869
909
  const normalizedResponse = normalizeResponse(response);
870
910
  const mode = normalizedResponse.updateMode ?? 'merge';
871
911
  const releaseLock = await __classPrivateFieldGet(this, _AssetsController_controllerMutex, "f").acquire();
@@ -894,9 +934,12 @@ async function _AssetsController_updateState(response) {
894
934
  for (const [accountId, accountBalances] of Object.entries(normalizedResponse.assetsBalance)) {
895
935
  const previousBalances = previousState.assetsBalance[accountId] ?? {};
896
936
  const customAssetIds = state.customAssets[accountId] ?? [];
897
- // Full: response is authoritative; preserve custom assets not in response. Merge: response overlays previous.
898
- const effective = mode === 'full'
899
- ? (() => {
937
+ // Full: response is authoritative; preserve custom assets not in response.
938
+ // Merge: response overlays previous balances.
939
+ // Callers that fetch partial data (e.g. newly added chains) must set updateMode: 'merge'.
940
+ const effective = mode === 'merge'
941
+ ? { ...previousBalances, ...accountBalances }
942
+ : (() => {
900
943
  const next = {
901
944
  ...accountBalances,
902
945
  };
@@ -908,13 +951,25 @@ async function _AssetsController_updateState(response) {
908
951
  }
909
952
  }
910
953
  return next;
911
- })()
912
- : { ...previousBalances, ...accountBalances };
954
+ })();
955
+ // Ensure native tokens have an entry (0 if missing) for chains this account supports
956
+ const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
957
+ const nativeAssetIdsForAccount = account
958
+ ? __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForAccount).call(this, account)
959
+ : __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForEnabledChains).call(this);
960
+ for (const nativeAssetId of nativeAssetIdsForAccount) {
961
+ if (!(nativeAssetId in effective)) {
962
+ effective[nativeAssetId] = { amount: '0' };
963
+ }
964
+ }
913
965
  for (const [assetId, balance] of Object.entries(effective)) {
914
966
  const previousBalance = previousBalances[assetId];
915
967
  const newAmount = balance.amount;
916
968
  const oldAmount = previousBalance?.amount;
917
- if (oldAmount !== newAmount) {
969
+ const isNewDefaultNativeZero = oldAmount === undefined &&
970
+ newAmount === '0' &&
971
+ nativeAssetIdsForAccount.includes(assetId);
972
+ if (oldAmount !== newAmount && !isNewDefaultNativeZero) {
918
973
  changedBalances.push({
919
974
  accountId,
920
975
  assetId,
@@ -1067,6 +1122,7 @@ async function _AssetsController_updateState(response) {
1067
1122
  enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
1068
1123
  });
1069
1124
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1125
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1070
1126
  this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
1071
1127
  chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
1072
1128
  forceUpdate: true,
@@ -1274,6 +1330,7 @@ async function _AssetsController_handleAccountGroupChanged() {
1274
1330
  forceUpdate: true,
1275
1331
  });
1276
1332
  }
1333
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1277
1334
  }, _AssetsController_handleEnabledNetworksChanged = async function _AssetsController_handleEnabledNetworksChanged(enabledNetworkMap) {
1278
1335
  const previousChains = __classPrivateFieldGet(this, _AssetsController_enabledChains, "f");
1279
1336
  __classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
@@ -1302,12 +1359,14 @@ async function _AssetsController_handleAccountGroupChanged() {
1302
1359
  // The data will simply not be updated until the network is re-enabled.
1303
1360
  // Refresh subscriptions for new chain set
1304
1361
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1305
- // Do one-time fetch for newly enabled chains
1362
+ // Do one-time fetch for newly enabled chains; merge so we keep existing chain balances
1306
1363
  if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
1307
1364
  await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
1308
1365
  chainIds: addedChains,
1309
1366
  forceUpdate: true,
1367
+ updateMode: 'merge',
1310
1368
  });
1311
1369
  }
1370
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_ensureNativeBalancesDefaultZero).call(this);
1312
1371
  };
1313
1372
  //# sourceMappingURL=AssetsController.cjs.map