@metamask-previews/assets-controller 0.1.0-preview-8f3469e9c → 0.1.0-preview-ce3ee897a

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 (36) hide show
  1. package/CHANGELOG.md +11 -2
  2. package/dist/AssetsController.cjs +74 -12
  3. package/dist/AssetsController.cjs.map +1 -1
  4. package/dist/AssetsController.d.cts +36 -11
  5. package/dist/AssetsController.d.cts.map +1 -1
  6. package/dist/AssetsController.d.mts +36 -11
  7. package/dist/AssetsController.d.mts.map +1 -1
  8. package/dist/AssetsController.mjs +74 -12
  9. package/dist/AssetsController.mjs.map +1 -1
  10. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  11. package/dist/data-sources/RpcDataSource.d.cts +0 -7
  12. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  13. package/dist/data-sources/RpcDataSource.d.mts +0 -7
  14. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  15. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  16. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs +192 -95
  17. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs.map +1 -1
  18. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts +22 -1
  19. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts.map +1 -1
  20. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts +22 -1
  21. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts.map +1 -1
  22. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs +192 -95
  23. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs.map +1 -1
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +1 -1
  26. package/dist/index.d.cts.map +1 -1
  27. package/dist/index.d.mts +1 -1
  28. package/dist/index.d.mts.map +1 -1
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/types.cjs.map +1 -1
  31. package/dist/types.d.cts +10 -0
  32. package/dist/types.d.cts.map +1 -1
  33. package/dist/types.d.mts +10 -0
  34. package/dist/types.d.mts.map +1 -1
  35. package/dist/types.mjs.map +1 -1
  36. package/package.json +2 -3
package/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add `assetPreferences` state and `AssetPreferences` type for per-asset UI preferences (e.g. `hidden`), separate from `assetsMetadata` ([#7777](https://github.com/MetaMask/core/pull/7777))
13
+ - Add `hideAsset(assetId)`, `unhideAsset(assetId)` for managing hidden assets globally; hidden assets are excluded from `getAssets` but balance updates continue to be tracked ([#7777](https://github.com/MetaMask/core/pull/7777))
14
+
15
+ ### Changed
16
+
17
+ - Narrow `AssetsControllerState` types from `Json` to semantic types: `assetsMetadata` → `AssetMetadata`, `assetsBalance` → `AssetBalance`, `assetsPrice` → `AssetPrice`, `assetPreferences` → `AssetPreferences`, `customAssets` → `Caip19AssetId[]` ([#7777](https://github.com/MetaMask/core/pull/7777))
18
+
19
+ - Replace `viem` dependency with manual ABI encoding/decoding in `MulticallClient` ([#7839](https://github.com/MetaMask/core/pull/7839))
20
+
10
21
  ## [0.1.0]
11
22
 
12
23
  ### Added
@@ -18,7 +29,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
18
29
  - Add batch utilities (`divideIntoBatches`, `reduceInBatchesSerially`) for processing arrays in batches ([#7677](https://github.com/MetaMask/core/pull/7677))
19
30
  - Add `TokenDetector` service for detecting ERC-20 tokens with non-zero balances on a chain ([#7683](https://github.com/MetaMask/core/pull/7683))
20
31
  - Add `BalanceFetcher` service for fetching token balances for user's imported/detected tokens ([#7684](https://github.com/MetaMask/core/pull/7684))
21
- - Add `viem` dependency for ABI encoding/decoding in MulticallClient
22
32
  - Add configurable polling intervals for `RpcDataSource` via `RpcDataSourceConfig` in `initDataSources` ([#7709](https://github.com/MetaMask/core/pull/7709))
23
33
  - Add comprehensive unit tests for data sources (`AccountsApiDataSource`, `BackendWebsocketDataSource`, `PriceDataSource`, `TokenDataSource`, `SnapDataSource`), `DetectionMiddleware`, and `AssetsController` ([#7714](https://github.com/MetaMask/core/pull/7714))
24
34
 
@@ -29,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
29
39
  - Store native token metadata (type, symbol, name, decimals) in `assetsMetadata` derived from `NetworkController` chain status ([#7752](https://github.com/MetaMask/core/pull/7752))
30
40
  - `AccountsApiDataSource` now includes `assetsMetadata` in response with token info from V5 API ([#7752](https://github.com/MetaMask/core/pull/7752))
31
41
  - Bump `@metamask/keyring-controller` from `^25.0.0` to `^25.1.0` ([#7713](https://github.com/MetaMask/core/pull/7713))
32
- - Refactor `MulticallClient` to use viem for ABI encoding/decoding instead of manual implementation
33
42
  - Refactor `RpcDataSource` to delegate polling to `BalanceFetcher` and `TokenDetector` services ([#7709](https://github.com/MetaMask/core/pull/7709))
34
43
  - Refactor `BalanceFetcher` and `TokenDetector` to extend `StaticIntervalPollingControllerOnly` for independent polling management ([#7709](https://github.com/MetaMask/core/pull/7709))
35
44
 
@@ -33,7 +33,7 @@ const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_
33
33
  /**
34
34
  * Returns the default state for AssetsController.
35
35
  *
36
- * @returns The default AssetsController state with empty metadata, balance, price, and customAssets maps.
36
+ * @returns The default AssetsController state with empty maps.
37
37
  */
38
38
  function getDefaultAssetsControllerState() {
39
39
  return {
@@ -41,6 +41,7 @@ function getDefaultAssetsControllerState() {
41
41
  assetsBalance: {},
42
42
  assetsPrice: {},
43
43
  customAssets: {},
44
+ assetPreferences: {},
44
45
  };
45
46
  }
46
47
  exports.getDefaultAssetsControllerState = getDefaultAssetsControllerState;
@@ -72,6 +73,12 @@ const stateMetadata = {
72
73
  includeInDebugSnapshot: false,
73
74
  usedInUi: true,
74
75
  },
76
+ assetPreferences: {
77
+ persist: true,
78
+ includeInStateLogs: false,
79
+ includeInDebugSnapshot: false,
80
+ usedInUi: true,
81
+ },
75
82
  };
76
83
  // ============================================================================
77
84
  // HELPER FUNCTIONS
@@ -354,6 +361,7 @@ class AssetsController extends base_controller_1.BaseController {
354
361
  /**
355
362
  * Add a custom asset for an account.
356
363
  * Custom assets are included in subscription and fetch operations.
364
+ * Adding a custom asset also unhides it if it was previously hidden.
357
365
  *
358
366
  * @param accountId - The account ID to add the custom asset for.
359
367
  * @param assetId - The CAIP-19 asset ID to add.
@@ -370,6 +378,14 @@ class AssetsController extends base_controller_1.BaseController {
370
378
  if (!customAssets[accountId].includes(normalizedAssetId)) {
371
379
  customAssets[accountId].push(normalizedAssetId);
372
380
  }
381
+ // Unhide the asset if it was hidden (via assetPreferences)
382
+ const prefs = state.assetPreferences[normalizedAssetId];
383
+ if (prefs?.hidden) {
384
+ delete prefs.hidden;
385
+ if (Object.keys(prefs).length === 0) {
386
+ delete state.assetPreferences[normalizedAssetId];
387
+ }
388
+ }
373
389
  });
374
390
  // Fetch data for the newly added custom asset
375
391
  const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
@@ -391,12 +407,11 @@ class AssetsController extends base_controller_1.BaseController {
391
407
  const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
392
408
  log('Removing custom asset', { accountId, assetId: normalizedAssetId });
393
409
  this.update((state) => {
394
- const customAssets = state.customAssets;
395
- if (customAssets[accountId]) {
396
- customAssets[accountId] = customAssets[accountId].filter((id) => id !== normalizedAssetId);
410
+ if (state.customAssets[accountId]) {
411
+ state.customAssets[accountId] = state.customAssets[accountId].filter((id) => id !== normalizedAssetId);
397
412
  // Clean up empty arrays
398
- if (customAssets[accountId].length === 0) {
399
- delete customAssets[accountId];
413
+ if (state.customAssets[accountId].length === 0) {
414
+ delete state.customAssets[accountId];
400
415
  }
401
416
  }
402
417
  });
@@ -408,7 +423,45 @@ class AssetsController extends base_controller_1.BaseController {
408
423
  * @returns Array of CAIP-19 asset IDs for the account's custom assets.
409
424
  */
410
425
  getCustomAssets(accountId) {
411
- return (this.state.customAssets[accountId] ?? []);
426
+ return this.state.customAssets[accountId] ?? [];
427
+ }
428
+ // ============================================================================
429
+ // HIDDEN ASSETS MANAGEMENT
430
+ // ============================================================================
431
+ /**
432
+ * Hide an asset globally.
433
+ * Hidden assets are excluded from the asset list returned by getAssets.
434
+ * The hidden state is stored in assetPreferences.
435
+ *
436
+ * @param assetId - The CAIP-19 asset ID to hide.
437
+ */
438
+ hideAsset(assetId) {
439
+ const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
440
+ log('Hiding asset', { assetId: normalizedAssetId });
441
+ this.update((state) => {
442
+ if (!state.assetPreferences[normalizedAssetId]) {
443
+ state.assetPreferences[normalizedAssetId] = {};
444
+ }
445
+ state.assetPreferences[normalizedAssetId].hidden = true;
446
+ });
447
+ }
448
+ /**
449
+ * Unhide an asset globally.
450
+ *
451
+ * @param assetId - The CAIP-19 asset ID to unhide.
452
+ */
453
+ unhideAsset(assetId) {
454
+ const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
455
+ log('Unhiding asset', { assetId: normalizedAssetId });
456
+ this.update((state) => {
457
+ const prefs = state.assetPreferences[normalizedAssetId];
458
+ if (prefs) {
459
+ delete prefs.hidden;
460
+ if (Object.keys(prefs).length === 0) {
461
+ delete state.assetPreferences[normalizedAssetId];
462
+ }
463
+ }
464
+ });
412
465
  }
413
466
  /**
414
467
  * Subscribe to price updates for all assets held by the given accounts.
@@ -501,6 +554,8 @@ class AssetsController extends base_controller_1.BaseController {
501
554
  this.messenger.unregisterActionHandler('AssetsController:addCustomAsset');
502
555
  this.messenger.unregisterActionHandler('AssetsController:removeCustomAsset');
503
556
  this.messenger.unregisterActionHandler('AssetsController:getCustomAssets');
557
+ this.messenger.unregisterActionHandler('AssetsController:hideAsset');
558
+ this.messenger.unregisterActionHandler('AssetsController:unhideAsset');
504
559
  }
505
560
  }
506
561
  exports.AssetsController = AssetsController;
@@ -563,6 +618,8 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInte
563
618
  this.messenger.registerActionHandler('AssetsController:addCustomAsset', this.addCustomAsset.bind(this));
564
619
  this.messenger.registerActionHandler('AssetsController:removeCustomAsset', this.removeCustomAsset.bind(this));
565
620
  this.messenger.registerActionHandler('AssetsController:getCustomAssets', this.getCustomAssets.bind(this));
621
+ this.messenger.registerActionHandler('AssetsController:hideAsset', this.hideAsset.bind(this));
622
+ this.messenger.registerActionHandler('AssetsController:unhideAsset', this.unhideAsset.bind(this));
566
623
  }, _AssetsController_executeMiddlewares =
567
624
  // ============================================================================
568
625
  // MIDDLEWARE EXECUTION
@@ -634,7 +691,7 @@ async function _AssetsController_updateState(response) {
634
691
  const changedBalances = [];
635
692
  const changedMetadata = [];
636
693
  this.update((state) => {
637
- // Use type assertions to avoid deep type instantiation issues with Draft<Json>
694
+ // Use type assertions to avoid deep type instantiation issues with Immer Draft types
638
695
  const metadata = state.assetsMetadata;
639
696
  const balances = state.assetsBalance;
640
697
  const prices = state.assetsPrice;
@@ -745,16 +802,21 @@ async function _AssetsController_updateState(response) {
745
802
  const accountBalances = this.state.assetsBalance[account.id] ?? {};
746
803
  for (const [assetId, balance] of Object.entries(accountBalances)) {
747
804
  const typedAssetId = assetId;
748
- const assetChainId = extractChainId(typedAssetId);
749
- if (!chainIdSet.has(assetChainId)) {
750
- continue;
751
- }
752
805
  const metadataRaw = this.state.assetsMetadata[typedAssetId];
753
806
  // Skip assets without metadata
754
807
  if (!metadataRaw) {
755
808
  continue;
756
809
  }
757
810
  const metadata = metadataRaw;
811
+ // Skip hidden assets (assetPreferences)
812
+ const prefs = this.state.assetPreferences[typedAssetId];
813
+ if (prefs?.hidden) {
814
+ continue;
815
+ }
816
+ const assetChainId = extractChainId(typedAssetId);
817
+ if (!chainIdSet.has(assetChainId)) {
818
+ continue;
819
+ }
758
820
  // Filter by asset type
759
821
  const tokenAssetType = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_tokenStandardToAssetType).call(this, metadata.type);
760
822
  if (!assetTypeSet.has(tokenAssetType)) {