@metamask/assets-controller 0.2.0 → 2.0.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 (202) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/dist/AssetsController-method-action-types.cjs +7 -0
  3. package/dist/AssetsController-method-action-types.cjs.map +1 -0
  4. package/dist/AssetsController-method-action-types.d.cts +78 -0
  5. package/dist/AssetsController-method-action-types.d.cts.map +1 -0
  6. package/dist/AssetsController-method-action-types.d.mts +78 -0
  7. package/dist/AssetsController-method-action-types.d.mts.map +1 -0
  8. package/dist/AssetsController-method-action-types.mjs +6 -0
  9. package/dist/AssetsController-method-action-types.mjs.map +1 -0
  10. package/dist/AssetsController.cjs +346 -271
  11. package/dist/AssetsController.cjs.map +1 -1
  12. package/dist/AssetsController.d.cts +92 -96
  13. package/dist/AssetsController.d.cts.map +1 -1
  14. package/dist/AssetsController.d.mts +92 -96
  15. package/dist/AssetsController.d.mts.map +1 -1
  16. package/dist/AssetsController.mjs +347 -272
  17. package/dist/AssetsController.mjs.map +1 -1
  18. package/dist/data-sources/AbstractDataSource.cjs +8 -0
  19. package/dist/data-sources/AbstractDataSource.cjs.map +1 -1
  20. package/dist/data-sources/AbstractDataSource.d.cts +16 -1
  21. package/dist/data-sources/AbstractDataSource.d.cts.map +1 -1
  22. package/dist/data-sources/AbstractDataSource.d.mts +16 -1
  23. package/dist/data-sources/AbstractDataSource.d.mts.map +1 -1
  24. package/dist/data-sources/AbstractDataSource.mjs +8 -0
  25. package/dist/data-sources/AbstractDataSource.mjs.map +1 -1
  26. package/dist/data-sources/AccountsApiDataSource.cjs +92 -111
  27. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  28. package/dist/data-sources/AccountsApiDataSource.d.cts +27 -70
  29. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  30. package/dist/data-sources/AccountsApiDataSource.d.mts +27 -70
  31. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  32. package/dist/data-sources/AccountsApiDataSource.mjs +88 -107
  33. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  34. package/dist/data-sources/BackendWebsocketDataSource.cjs +141 -46
  35. package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
  36. package/dist/data-sources/BackendWebsocketDataSource.d.cts +19 -66
  37. package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
  38. package/dist/data-sources/BackendWebsocketDataSource.d.mts +19 -66
  39. package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
  40. package/dist/data-sources/BackendWebsocketDataSource.mjs +141 -46
  41. package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
  42. package/dist/data-sources/PriceDataSource.cjs +39 -48
  43. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  44. package/dist/data-sources/PriceDataSource.d.cts +13 -92
  45. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  46. package/dist/data-sources/PriceDataSource.d.mts +13 -92
  47. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  48. package/dist/data-sources/PriceDataSource.mjs +39 -48
  49. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  50. package/dist/data-sources/RpcDataSource.cjs +184 -142
  51. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  52. package/dist/data-sources/RpcDataSource.d.cts +29 -114
  53. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  54. package/dist/data-sources/RpcDataSource.d.mts +29 -114
  55. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  56. package/dist/data-sources/RpcDataSource.mjs +185 -143
  57. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  58. package/dist/data-sources/SnapDataSource.cjs +53 -39
  59. package/dist/data-sources/SnapDataSource.cjs.map +1 -1
  60. package/dist/data-sources/SnapDataSource.d.cts +9 -45
  61. package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
  62. package/dist/data-sources/SnapDataSource.d.mts +9 -45
  63. package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
  64. package/dist/data-sources/SnapDataSource.mjs +53 -39
  65. package/dist/data-sources/SnapDataSource.mjs.map +1 -1
  66. package/dist/data-sources/StakedBalanceDataSource.cjs +609 -0
  67. package/dist/data-sources/StakedBalanceDataSource.cjs.map +1 -0
  68. package/dist/data-sources/StakedBalanceDataSource.d.cts +72 -0
  69. package/dist/data-sources/StakedBalanceDataSource.d.cts.map +1 -0
  70. package/dist/data-sources/StakedBalanceDataSource.d.mts +72 -0
  71. package/dist/data-sources/StakedBalanceDataSource.d.mts.map +1 -0
  72. package/dist/data-sources/StakedBalanceDataSource.mjs +605 -0
  73. package/dist/data-sources/StakedBalanceDataSource.mjs.map +1 -0
  74. package/dist/data-sources/TokenDataSource.cjs +15 -21
  75. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  76. package/dist/data-sources/TokenDataSource.d.cts +3 -25
  77. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  78. package/dist/data-sources/TokenDataSource.d.mts +3 -25
  79. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  80. package/dist/data-sources/TokenDataSource.mjs +15 -21
  81. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  82. package/dist/data-sources/evm-rpc-services/index.cjs +5 -1
  83. package/dist/data-sources/evm-rpc-services/index.cjs.map +1 -1
  84. package/dist/data-sources/evm-rpc-services/index.d.cts +1 -1
  85. package/dist/data-sources/evm-rpc-services/index.d.cts.map +1 -1
  86. package/dist/data-sources/evm-rpc-services/index.d.mts +1 -1
  87. package/dist/data-sources/evm-rpc-services/index.d.mts.map +1 -1
  88. package/dist/data-sources/evm-rpc-services/index.mjs +1 -1
  89. package/dist/data-sources/evm-rpc-services/index.mjs.map +1 -1
  90. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.cjs +132 -0
  91. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.cjs.map +1 -0
  92. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.cts +78 -0
  93. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.cts.map +1 -0
  94. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.mts +78 -0
  95. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.mts.map +1 -0
  96. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.mjs +126 -0
  97. package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.mjs.map +1 -0
  98. package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs +16 -0
  99. package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs.map +1 -1
  100. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts +5 -1
  101. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts.map +1 -1
  102. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts +5 -1
  103. package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts.map +1 -1
  104. package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs +16 -0
  105. package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs.map +1 -1
  106. package/dist/data-sources/evm-rpc-services/services/index.cjs +6 -1
  107. package/dist/data-sources/evm-rpc-services/services/index.cjs.map +1 -1
  108. package/dist/data-sources/evm-rpc-services/services/index.d.cts +1 -0
  109. package/dist/data-sources/evm-rpc-services/services/index.d.cts.map +1 -1
  110. package/dist/data-sources/evm-rpc-services/services/index.d.mts +1 -0
  111. package/dist/data-sources/evm-rpc-services/services/index.d.mts.map +1 -1
  112. package/dist/data-sources/evm-rpc-services/services/index.mjs +1 -0
  113. package/dist/data-sources/evm-rpc-services/services/index.mjs.map +1 -1
  114. package/dist/data-sources/evm-rpc-services/types/services.cjs.map +1 -1
  115. package/dist/data-sources/evm-rpc-services/types/services.d.cts +4 -0
  116. package/dist/data-sources/evm-rpc-services/types/services.d.cts.map +1 -1
  117. package/dist/data-sources/evm-rpc-services/types/services.d.mts +4 -0
  118. package/dist/data-sources/evm-rpc-services/types/services.d.mts.map +1 -1
  119. package/dist/data-sources/evm-rpc-services/types/services.mjs.map +1 -1
  120. package/dist/data-sources/evm-rpc-services/types/state.cjs.map +1 -1
  121. package/dist/data-sources/evm-rpc-services/types/state.d.cts +3 -3
  122. package/dist/data-sources/evm-rpc-services/types/state.d.cts.map +1 -1
  123. package/dist/data-sources/evm-rpc-services/types/state.d.mts +3 -3
  124. package/dist/data-sources/evm-rpc-services/types/state.d.mts.map +1 -1
  125. package/dist/data-sources/evm-rpc-services/types/state.mjs.map +1 -1
  126. package/dist/data-sources/evm-rpc-services/utils/index.cjs +9 -1
  127. package/dist/data-sources/evm-rpc-services/utils/index.cjs.map +1 -1
  128. package/dist/data-sources/evm-rpc-services/utils/index.d.cts +2 -0
  129. package/dist/data-sources/evm-rpc-services/utils/index.d.cts.map +1 -1
  130. package/dist/data-sources/evm-rpc-services/utils/index.d.mts +2 -0
  131. package/dist/data-sources/evm-rpc-services/utils/index.d.mts.map +1 -1
  132. package/dist/data-sources/evm-rpc-services/utils/index.mjs +2 -0
  133. package/dist/data-sources/evm-rpc-services/utils/index.mjs.map +1 -1
  134. package/dist/data-sources/evm-rpc-services/utils/parsing.cjs +47 -0
  135. package/dist/data-sources/evm-rpc-services/utils/parsing.cjs.map +1 -0
  136. package/dist/data-sources/evm-rpc-services/utils/parsing.d.cts +25 -0
  137. package/dist/data-sources/evm-rpc-services/utils/parsing.d.cts.map +1 -0
  138. package/dist/data-sources/evm-rpc-services/utils/parsing.d.mts +25 -0
  139. package/dist/data-sources/evm-rpc-services/utils/parsing.d.mts.map +1 -0
  140. package/dist/data-sources/evm-rpc-services/utils/parsing.mjs +39 -0
  141. package/dist/data-sources/evm-rpc-services/utils/parsing.mjs.map +1 -0
  142. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.cjs +68 -0
  143. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.cjs.map +1 -0
  144. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.cts +25 -0
  145. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.cts.map +1 -0
  146. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.mts +25 -0
  147. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.mts.map +1 -0
  148. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.mjs +62 -0
  149. package/dist/data-sources/evm-rpc-services/utils/staking-contracts.mjs.map +1 -0
  150. package/dist/data-sources/index.cjs +3 -6
  151. package/dist/data-sources/index.cjs.map +1 -1
  152. package/dist/data-sources/index.d.cts +7 -7
  153. package/dist/data-sources/index.d.cts.map +1 -1
  154. package/dist/data-sources/index.d.mts +7 -7
  155. package/dist/data-sources/index.d.mts.map +1 -1
  156. package/dist/data-sources/index.mjs +2 -3
  157. package/dist/data-sources/index.mjs.map +1 -1
  158. package/dist/index.cjs +6 -6
  159. package/dist/index.cjs.map +1 -1
  160. package/dist/index.d.cts +11 -11
  161. package/dist/index.d.cts.map +1 -1
  162. package/dist/index.d.mts +11 -11
  163. package/dist/index.d.mts.map +1 -1
  164. package/dist/index.mjs +3 -3
  165. package/dist/index.mjs.map +1 -1
  166. package/dist/middlewares/DetectionMiddleware.cjs +8 -28
  167. package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
  168. package/dist/middlewares/DetectionMiddleware.d.cts +4 -26
  169. package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
  170. package/dist/middlewares/DetectionMiddleware.d.mts +4 -26
  171. package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
  172. package/dist/middlewares/DetectionMiddleware.mjs +8 -28
  173. package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
  174. package/dist/middlewares/index.cjs.map +1 -1
  175. package/dist/middlewares/index.d.cts +1 -1
  176. package/dist/middlewares/index.d.cts.map +1 -1
  177. package/dist/middlewares/index.d.mts +1 -1
  178. package/dist/middlewares/index.d.mts.map +1 -1
  179. package/dist/middlewares/index.mjs.map +1 -1
  180. package/dist/selectors/balance.cjs +306 -0
  181. package/dist/selectors/balance.cjs.map +1 -0
  182. package/dist/selectors/balance.d.cts +22 -0
  183. package/dist/selectors/balance.d.cts.map +1 -0
  184. package/dist/selectors/balance.d.mts +22 -0
  185. package/dist/selectors/balance.d.mts.map +1 -0
  186. package/dist/selectors/balance.mjs +297 -0
  187. package/dist/selectors/balance.mjs.map +1 -0
  188. package/dist/types.cjs.map +1 -1
  189. package/dist/types.d.cts +56 -21
  190. package/dist/types.d.cts.map +1 -1
  191. package/dist/types.d.mts +56 -21
  192. package/dist/types.d.mts.map +1 -1
  193. package/dist/types.mjs.map +1 -1
  194. package/package.json +13 -10
  195. package/dist/data-sources/initDataSources.cjs +0 -215
  196. package/dist/data-sources/initDataSources.cjs.map +0 -1
  197. package/dist/data-sources/initDataSources.d.cts +0 -140
  198. package/dist/data-sources/initDataSources.d.cts.map +0 -1
  199. package/dist/data-sources/initDataSources.d.mts +0 -140
  200. package/dist/data-sources/initDataSources.d.mts.map +0 -1
  201. package/dist/data-sources/initDataSources.mjs +0 -210
  202. package/dist/data-sources/initDataSources.mjs.map +0 -1
@@ -1,19 +1,19 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
2
7
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
8
  if (kind === "m") throw new TypeError("Private method is not writable");
4
9
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
10
  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");
6
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
12
  };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
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_defaultUpdateInterval, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_dataSources, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_assignChainsToDataSources, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeToDataSources, _AssetsController_subscribeAssetsBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_getAccountsForChains, _AssetsController_subscribeToDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged, _AssetsController_handleSubscriptionUpdate;
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;
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");
@@ -21,12 +21,32 @@ const utils_1 = require("@metamask/utils");
21
21
  const async_mutex_1 = require("async-mutex");
22
22
  const bignumber_js_1 = __importDefault(require("bignumber.js"));
23
23
  const lodash_1 = require("lodash");
24
+ const AccountsApiDataSource_1 = require("./data-sources/AccountsApiDataSource.cjs");
25
+ const BackendWebsocketDataSource_1 = require("./data-sources/BackendWebsocketDataSource.cjs");
26
+ const PriceDataSource_1 = require("./data-sources/PriceDataSource.cjs");
27
+ const RpcDataSource_1 = require("./data-sources/RpcDataSource.cjs");
28
+ const SnapDataSource_1 = require("./data-sources/SnapDataSource.cjs");
29
+ const StakedBalanceDataSource_1 = require("./data-sources/StakedBalanceDataSource.cjs");
30
+ const TokenDataSource_1 = require("./data-sources/TokenDataSource.cjs");
24
31
  const logger_1 = require("./logger.cjs");
32
+ const DetectionMiddleware_1 = require("./middlewares/DetectionMiddleware.cjs");
25
33
  const utils_2 = require("./utils.cjs");
26
34
  // ============================================================================
27
35
  // CONTROLLER CONSTANTS
28
36
  // ============================================================================
29
37
  const CONTROLLER_NAME = 'AssetsController';
38
+ /** Method names exposed as messenger actions (AssetsController:getAssets, etc.) */
39
+ const MESSENGER_EXPOSED_METHODS = [
40
+ 'getAssets',
41
+ 'getAssetsBalance',
42
+ 'getAssetMetadata',
43
+ 'getAssetsPrice',
44
+ 'addCustomAsset',
45
+ 'removeCustomAsset',
46
+ 'getCustomAssets',
47
+ 'hideAsset',
48
+ 'unhideAsset',
49
+ ];
30
50
  /** Default polling interval hint for data sources (30 seconds) */
31
51
  const DEFAULT_POLLING_INTERVAL_MS = 30000;
32
52
  const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_NAME);
@@ -37,7 +57,7 @@ const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_
37
57
  */
38
58
  function getDefaultAssetsControllerState() {
39
59
  return {
40
- assetsMetadata: {},
60
+ assetsInfo: {},
41
61
  assetsBalance: {},
42
62
  assetsPrice: {},
43
63
  customAssets: {},
@@ -49,7 +69,7 @@ exports.getDefaultAssetsControllerState = getDefaultAssetsControllerState;
49
69
  // STATE METADATA
50
70
  // ============================================================================
51
71
  const stateMetadata = {
52
- assetsMetadata: {
72
+ assetsInfo: {
53
73
  persist: true,
54
74
  includeInStateLogs: false,
55
75
  includeInDebugSnapshot: false,
@@ -97,11 +117,11 @@ function extractChainId(assetId) {
97
117
  */
98
118
  function normalizeResponse(response) {
99
119
  const normalized = {};
100
- if (response.assetsMetadata) {
101
- normalized.assetsMetadata = {};
102
- for (const [assetId, metadata] of Object.entries(response.assetsMetadata)) {
120
+ if (response.assetsInfo) {
121
+ normalized.assetsInfo = {};
122
+ for (const [assetId, metadata] of Object.entries(response.assetsInfo)) {
103
123
  const normalizedId = (0, utils_2.normalizeAssetId)(assetId);
104
- normalized.assetsMetadata[normalizedId] = metadata;
124
+ normalized.assetsInfo[normalizedId] = metadata;
105
125
  }
106
126
  }
107
127
  if (response.assetsPrice) {
@@ -153,13 +173,8 @@ function normalizeResponse(response) {
153
173
  * based on which chains they support. When active chains change, the controller
154
174
  * dynamically adjusts subscriptions.
155
175
  *
156
- * 4. **App Lifecycle Management**: Listens to app open/close events via messenger
157
- * to start/stop subscriptions automatically, conserving resources when app is closed.
158
- *
159
- * ## App Lifecycle
160
- *
161
- * - **App Opened** (`AppStateController:appOpened`): Starts subscriptions, fetches initial data
162
- * - **App Closed** (`AppStateController:appClosed`): Stops all subscriptions to conserve resources
176
+ * 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
177
+ * start/stop subscriptions when the wallet is unlocked or locked.
163
178
  *
164
179
  * ## Architecture
165
180
  *
@@ -168,7 +183,7 @@ function normalizeResponse(response) {
168
183
  * - The controller does NOT manage polling - it simply receives pushed updates
169
184
  */
170
185
  class AssetsController extends base_controller_1.BaseController {
171
- constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, }) {
186
+ constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, isBasicFunctionality, subscribeToBasicFunctionalityChange, queryApiClient, rpcDataSourceConfig, trackMetaMetricsEvent, accountsApiDataSourceConfig, priceDataSourceConfig, stakedBalanceDataSourceConfig, }) {
172
187
  super({
173
188
  name: CONTROLLER_NAME,
174
189
  messenger,
@@ -181,8 +196,14 @@ class AssetsController extends base_controller_1.BaseController {
181
196
  _AssetsController_instances.add(this);
182
197
  /** Whether the controller is enabled */
183
198
  _AssetsController_isEnabled.set(this, void 0);
199
+ /** Getter for basic functionality (only balance fetch/subscribe use RPC; token/price API not used). No attribute stored. */
200
+ _AssetsController_isBasicFunctionality.set(this, void 0);
184
201
  /** Default update interval hint passed to data sources */
185
202
  _AssetsController_defaultUpdateInterval.set(this, void 0);
203
+ /** Optional callback for first init/fetch MetaMetrics (duration). */
204
+ _AssetsController_trackMetaMetricsEvent.set(this, void 0);
205
+ /** Whether we have already reported first init fetch for this session (reset on #stop). */
206
+ _AssetsController_firstInitFetchReported.set(this, false);
186
207
  _AssetsController_controllerMutex.set(this, new async_mutex_1.Mutex());
187
208
  /**
188
209
  * Active balance subscriptions keyed by account ID.
@@ -193,79 +214,107 @@ class AssetsController extends base_controller_1.BaseController {
193
214
  _AssetsController_activeSubscriptions.set(this, new Map());
194
215
  /** Currently enabled chains from NetworkEnablementController */
195
216
  _AssetsController_enabledChains.set(this, new Set());
196
- /**
197
- * Registered data sources with their available chains.
198
- * Updated continuously and independently from subscription flows.
199
- * Key: sourceId, Value: Set of currently available chainIds
200
- */
201
- _AssetsController_dataSources.set(this, new Map());
217
+ _AssetsController_backendWebsocketDataSource.set(this, void 0);
218
+ _AssetsController_accountsApiDataSource.set(this, void 0);
219
+ _AssetsController_snapDataSource.set(this, void 0);
220
+ _AssetsController_rpcDataSource.set(this, void 0);
221
+ _AssetsController_stakedBalanceDataSource.set(this, void 0);
222
+ _AssetsController_priceDataSource.set(this, void 0);
223
+ _AssetsController_detectionMiddleware.set(this, void 0);
224
+ _AssetsController_tokenDataSource.set(this, void 0);
225
+ _AssetsController_unsubscribeBasicFunctionality.set(this, null);
202
226
  __classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
227
+ __classPrivateFieldSet(this, _AssetsController_isBasicFunctionality, isBasicFunctionality ?? (() => true), "f");
203
228
  __classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
229
+ __classPrivateFieldSet(this, _AssetsController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
230
+ const rpcConfig = rpcDataSourceConfig ?? {};
231
+ const onActiveChainsUpdated = (dataSourceName, chains, previousChains) => {
232
+ this.handleActiveChainsUpdate(dataSourceName, chains, previousChains);
233
+ };
234
+ __classPrivateFieldSet(this, _AssetsController_backendWebsocketDataSource, new BackendWebsocketDataSource_1.BackendWebsocketDataSource({
235
+ messenger: this.messenger,
236
+ queryApiClient,
237
+ onActiveChainsUpdated,
238
+ }), "f");
239
+ __classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource_1.AccountsApiDataSource({
240
+ queryApiClient,
241
+ onActiveChainsUpdated,
242
+ ...accountsApiDataSourceConfig,
243
+ }), "f");
244
+ __classPrivateFieldSet(this, _AssetsController_snapDataSource, new SnapDataSource_1.SnapDataSource({
245
+ messenger: this.messenger,
246
+ onActiveChainsUpdated,
247
+ }), "f");
248
+ __classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource_1.RpcDataSource({
249
+ messenger: this.messenger,
250
+ onActiveChainsUpdated,
251
+ ...rpcConfig,
252
+ }), "f");
253
+ __classPrivateFieldSet(this, _AssetsController_stakedBalanceDataSource, new StakedBalanceDataSource_1.StakedBalanceDataSource({
254
+ messenger: this.messenger,
255
+ onActiveChainsUpdated,
256
+ ...stakedBalanceDataSourceConfig,
257
+ }), "f");
258
+ __classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource_1.TokenDataSource({
259
+ queryApiClient,
260
+ }), "f");
261
+ __classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource_1.PriceDataSource({
262
+ queryApiClient,
263
+ ...priceDataSourceConfig,
264
+ }), "f");
265
+ __classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware_1.DetectionMiddleware(), "f");
204
266
  if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
205
267
  log('AssetsController is disabled, skipping initialization');
206
268
  return;
207
269
  }
208
270
  log('Initializing AssetsController', {
209
- defaultUpdateInterval,
271
+ defaultUpdateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
210
272
  });
211
273
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
212
274
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
213
275
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
214
- // Register data sources (order = subscription priority)
215
- this.registerDataSources([
216
- 'BackendWebsocketDataSource', // Real-time push updates
217
- 'AccountsApiDataSource', // HTTP polling fallback
218
- 'SnapDataSource', // Solana/Bitcoin/Tron snaps
219
- 'RpcDataSource', // Direct blockchain queries
220
- ]);
221
- }
222
- // ============================================================================
223
- // DATA SOURCE MANAGEMENT
224
- // ============================================================================
225
- /**
226
- * Register data sources with the controller.
227
- * Order of the array determines subscription order.
228
- *
229
- * Data sources report chain changes by calling `AssetsController:activeChainsUpdate` action.
230
- *
231
- * @param dataSourceIds - Array of data source identifiers to register.
232
- */
233
- registerDataSources(dataSourceIds) {
234
- for (const id of dataSourceIds) {
235
- log('Registering data source', { id });
236
- // Initialize available chains tracking for this source
237
- __classPrivateFieldGet(this, _AssetsController_dataSources, "f").set(id, new Set());
276
+ // Subscriptions start only on KeyringController:unlock -> #start(), not here.
277
+ // Subscribe to basic-functionality changes after construction so a synchronous
278
+ // onChange during subscribe cannot run before data sources are initialized.
279
+ if (subscribeToBasicFunctionalityChange) {
280
+ const unsubscribe = subscribeToBasicFunctionalityChange((isBasic) => this.handleBasicFunctionalityChange(isBasic));
281
+ if (typeof unsubscribe === 'function') {
282
+ __classPrivateFieldSet(this, _AssetsController_unsubscribeBasicFunctionality, unsubscribe, "f");
283
+ }
238
284
  }
239
285
  }
240
286
  // ============================================================================
241
287
  // DATA SOURCE CHAIN MANAGEMENT
242
288
  // ============================================================================
243
289
  /**
244
- * Handle when a data source's active chains change.
245
- * Active chains are chains that are both supported AND available.
246
- * Updates centralized chain tracking and triggers re-selection if needed.
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.
292
+ *
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).
247
295
  *
248
- * Data sources should call this via `AssetsController:activeChainsUpdate` action.
296
+ * Controller does not store chains; sources report via this callback. previousChains is required for diff.
249
297
  *
250
298
  * @param dataSourceId - The identifier of the data source reporting the change.
251
- * @param activeChains - Array of currently active chain IDs for this source.
299
+ * @param activeChains - Currently active (supported and available) chain IDs for this source.
300
+ * @param previousChains - Previous chains; used to compute added/removed.
252
301
  */
253
- handleActiveChainsUpdate(dataSourceId, activeChains) {
302
+ handleActiveChainsUpdate(dataSourceId, activeChains, previousChains) {
303
+ if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
304
+ return;
305
+ }
254
306
  log('Data source active chains changed', {
255
307
  dataSourceId,
256
308
  chainCount: activeChains.length,
257
309
  chains: activeChains,
258
310
  });
259
- const previousChains = __classPrivateFieldGet(this, _AssetsController_dataSources, "f").get(dataSourceId) ?? new Set();
260
- const newChains = new Set(activeChains);
261
- // Update centralized available chains tracking
262
- __classPrivateFieldGet(this, _AssetsController_dataSources, "f").set(dataSourceId, newChains);
263
- // Check for changes
264
- const addedChains = activeChains.filter((chain) => !previousChains.has(chain));
265
- const removedChains = Array.from(previousChains).filter((chain) => !newChains.has(chain));
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));
266
315
  if (addedChains.length > 0 || removedChains.length > 0) {
267
316
  // Refresh subscriptions to use updated data source availability
268
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToDataSources).call(this);
317
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
269
318
  }
270
319
  // If chains were added and we have selected accounts, do one-time fetch
271
320
  if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
@@ -295,22 +344,39 @@ class AssetsController extends base_controller_1.BaseController {
295
344
  customAssets.push(...accountCustomAssets);
296
345
  }
297
346
  if (options?.forceUpdate) {
298
- const response = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
299
- this.messenger.call('AccountsApiDataSource:getAssetsMiddleware'),
300
- this.messenger.call('SnapDataSource:getAssetsMiddleware'),
301
- this.messenger.call('RpcDataSource:getAssetsMiddleware'),
302
- this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
303
- this.messenger.call('TokenDataSource:getAssetsMiddleware'),
304
- this.messenger.call('PriceDataSource:getAssetsMiddleware'),
305
- ], {
306
- accounts,
307
- chainIds,
347
+ const startTime = Date.now();
348
+ const request = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
308
349
  assetTypes,
309
350
  dataTypes,
310
351
  customAssets: customAssets.length > 0 ? customAssets : undefined,
311
352
  forceUpdate: true,
312
353
  });
354
+ const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
355
+ ? [
356
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
357
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
358
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
359
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
360
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
361
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
362
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
363
+ ]
364
+ : [
365
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
366
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
367
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
368
+ ];
369
+ const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
313
370
  await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
371
+ if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
372
+ __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
373
+ const durationMs = Date.now() - startTime;
374
+ __classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f").call(this, {
375
+ durationMs,
376
+ chainIds,
377
+ durationByDataSource,
378
+ });
379
+ }
314
380
  }
315
381
  return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
316
382
  }
@@ -335,7 +401,7 @@ class AssetsController extends base_controller_1.BaseController {
335
401
  return result;
336
402
  }
337
403
  getAssetMetadata(assetId) {
338
- return this.state.assetsMetadata[assetId];
404
+ return this.state.assetsInfo[assetId];
339
405
  }
340
406
  async getAssetsPrice(accounts, options) {
341
407
  const assets = await this.getAssets(accounts, {
@@ -463,33 +529,33 @@ class AssetsController extends base_controller_1.BaseController {
463
529
  }
464
530
  });
465
531
  }
532
+ // ============================================================================
533
+ // SUBSCRIPTIONS
534
+ // ============================================================================
466
535
  /**
467
536
  * Subscribe to price updates for all assets held by the given accounts.
468
537
  * Polls PriceDataSource which fetches prices from balance state.
469
538
  *
470
539
  * @param accounts - Accounts to subscribe price updates for.
471
540
  * @param chainIds - Chain IDs to filter prices for.
472
- * @param options - Subscription options.
473
- * @param options.updateInterval - Polling interval in ms.
474
541
  */
475
- subscribeAssetsPrice(accounts, chainIds, options = {}) {
476
- const { updateInterval = __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f") } = options;
542
+ subscribeAssetsPrice(accounts, chainIds) {
543
+ if (!__classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)) {
544
+ return;
545
+ }
477
546
  const subscriptionKey = 'ds:PriceDataSource';
478
547
  const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
479
548
  const isUpdate = existingSubscription !== undefined;
480
- // Fire-and-forget - errors are handled internally by PriceDataSource
481
- this.messenger
482
- .call('PriceDataSource:subscribe', {
483
- request: {
484
- accounts,
485
- chainIds,
549
+ const subscribeReq = {
550
+ request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chainIds, {
486
551
  dataTypes: ['price'],
487
- updateInterval,
488
- },
552
+ }),
489
553
  subscriptionId: subscriptionKey,
490
554
  isUpdate,
491
- })
492
- .catch(console.error);
555
+ onAssetsUpdate: (response) => this.handleAssetsUpdate(response, 'PriceDataSource'),
556
+ getAssetsState: () => this.state,
557
+ };
558
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").subscribe(subscribeReq).catch(console.error);
493
559
  // Track subscription
494
560
  const subscription = {
495
561
  chains: chainIds,
@@ -511,46 +577,70 @@ class AssetsController extends base_controller_1.BaseController {
511
577
  if (!existingSubscription) {
512
578
  return;
513
579
  }
514
- // Fire-and-forget - errors are handled internally by PriceDataSource
515
- this.messenger
516
- .call('PriceDataSource:unsubscribe', subscriptionKey)
517
- .catch(console.error);
580
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f").unsubscribe(subscriptionKey).catch(console.error);
518
581
  existingSubscription.unsubscribe();
519
582
  }
583
+ /**
584
+ * Handle basic functionality toggle change. Call this from the consumer (extension or mobile)
585
+ * when the user changes the "Basic functionality" setting. Refreshes subscriptions so the
586
+ * current {@link AssetsControllerOptions.isBasicFunctionality} getter is used (true = APIs on,
587
+ * false = RPC only).
588
+ *
589
+ * @param _isBasic - The new value (for call-site clarity; the getter is the source of truth).
590
+ */
591
+ handleBasicFunctionalityChange(_isBasic) {
592
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
593
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
594
+ }
520
595
  /**
521
596
  * Handle assets updated from a data source.
522
- * Called via `AssetsController:assetsUpdate` action by data sources.
597
+ * Called via the onAssetsUpdate callback passed in SubscriptionRequest when the controller subscribes to a data source.
598
+ * Enriches the response with token metadata (via middlewares) before updating state.
523
599
  *
524
600
  * @param response - The data response with updated assets
525
601
  * @param sourceId - The data source ID reporting the update
602
+ * @param request - Optional original request for context when enriching
526
603
  */
527
- async handleAssetsUpdate(response, sourceId) {
604
+ async handleAssetsUpdate(response, sourceId, request) {
528
605
  log('Assets updated from data source', {
529
606
  sourceId,
530
607
  hasBalance: Boolean(response.assetsBalance),
531
608
  hasPrice: Boolean(response.assetsPrice),
532
609
  });
533
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleSubscriptionUpdate).call(this, response, sourceId);
610
+ // Run through enrichment middlewares (Event Stack: Detection → Token → Price)
611
+ // 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 ?? {
613
+ accountsWithSupportedChains: [],
614
+ chainIds: [],
615
+ dataTypes: ['balance', 'metadata', 'price'],
616
+ }, response);
617
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
534
618
  }
535
619
  // ============================================================================
536
620
  // CLEANUP
537
621
  // ============================================================================
538
622
  destroy() {
539
623
  log('Destroying AssetsController', {
540
- dataSourceCount: __classPrivateFieldGet(this, _AssetsController_dataSources, "f").size,
624
+ dataSourceCount: __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_allBalanceDataSources_get).length,
541
625
  subscriptionCount: __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size,
542
626
  });
543
- // Clear data sources
544
- __classPrivateFieldGet(this, _AssetsController_dataSources, "f").clear();
627
+ // Destroy instantiated data sources
628
+ __classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f")?.destroy?.();
629
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f")?.destroy?.();
630
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f")?.destroy?.();
631
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")?.destroy?.();
632
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f")?.destroy?.();
545
633
  // Stop all active subscriptions
546
634
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
635
+ if (__classPrivateFieldGet(this, _AssetsController_unsubscribeBasicFunctionality, "f")) {
636
+ __classPrivateFieldGet(this, _AssetsController_unsubscribeBasicFunctionality, "f").call(this);
637
+ __classPrivateFieldSet(this, _AssetsController_unsubscribeBasicFunctionality, null, "f");
638
+ }
547
639
  // Unregister action handlers
548
640
  this.messenger.unregisterActionHandler('AssetsController:getAssets');
549
641
  this.messenger.unregisterActionHandler('AssetsController:getAssetsBalance');
550
642
  this.messenger.unregisterActionHandler('AssetsController:getAssetMetadata');
551
643
  this.messenger.unregisterActionHandler('AssetsController:getAssetsPrice');
552
- this.messenger.unregisterActionHandler('AssetsController:activeChainsUpdate');
553
- this.messenger.unregisterActionHandler('AssetsController:assetsUpdate');
554
644
  this.messenger.unregisterActionHandler('AssetsController:addCustomAsset');
555
645
  this.messenger.unregisterActionHandler('AssetsController:removeCustomAsset');
556
646
  this.messenger.unregisterActionHandler('AssetsController:getCustomAssets');
@@ -559,8 +649,15 @@ class AssetsController extends base_controller_1.BaseController {
559
649
  }
560
650
  }
561
651
  exports.AssetsController = AssetsController;
562
- _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_dataSources = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
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() {
563
653
  return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
654
+ }, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
655
+ return [
656
+ __classPrivateFieldGet(this, _AssetsController_backendWebsocketDataSource, "f"),
657
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
658
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
659
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
660
+ ];
564
661
  }, _AssetsController_initializeState = function _AssetsController_initializeState() {
565
662
  const { enabledNetworkMap } = this.messenger.call('NetworkEnablementController:getState');
566
663
  __classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
@@ -588,7 +685,7 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInte
588
685
  }
589
686
  return chains;
590
687
  }, _AssetsController_normalizeChainReference = function _AssetsController_normalizeChainReference(namespace, reference) {
591
- if (namespace === 'eip155' && reference.startsWith('0x')) {
688
+ if (namespace === 'eip155' && (0, utils_1.isStrictHexString)(reference)) {
592
689
  // Convert hex to decimal for EIP155 chains
593
690
  return parseInt(reference, 16).toString();
594
691
  }
@@ -602,38 +699,38 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_defaultUpdateInte
602
699
  this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
603
700
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
604
701
  });
605
- // App lifecycle: start when opened, stop when closed
606
- this.messenger.subscribe('AppStateController:appOpened', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
607
- this.messenger.subscribe('AppStateController:appClosed', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
608
702
  // Keyring lifecycle: start when unlocked, stop when locked
609
703
  this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
610
704
  this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
611
705
  }, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
612
- this.messenger.registerActionHandler('AssetsController:getAssets', this.getAssets.bind(this));
613
- this.messenger.registerActionHandler('AssetsController:getAssetsBalance', this.getAssetsBalance.bind(this));
614
- this.messenger.registerActionHandler('AssetsController:getAssetMetadata', this.getAssetMetadata.bind(this));
615
- this.messenger.registerActionHandler('AssetsController:getAssetsPrice', this.getAssetsPrice.bind(this));
616
- this.messenger.registerActionHandler('AssetsController:activeChainsUpdate', this.handleActiveChainsUpdate.bind(this));
617
- this.messenger.registerActionHandler('AssetsController:assetsUpdate', this.handleAssetsUpdate.bind(this));
618
- this.messenger.registerActionHandler('AssetsController:addCustomAsset', this.addCustomAsset.bind(this));
619
- this.messenger.registerActionHandler('AssetsController:removeCustomAsset', this.removeCustomAsset.bind(this));
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));
706
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
623
707
  }, _AssetsController_executeMiddlewares =
624
708
  // ============================================================================
625
709
  // MIDDLEWARE EXECUTION
626
710
  // ============================================================================
627
711
  /**
628
712
  * Execute middlewares with request/response context.
713
+ * Returns response and exclusive duration per source (sum ≈ wall time).
629
714
  *
630
- * @param middlewares - Middlewares to execute in order.
715
+ * @param sources - Data sources or middlewares with getName() and assetsMiddleware (executed in order).
631
716
  * @param request - The data request.
632
717
  * @param initialResponse - Optional initial response (for enriching existing data).
633
- * @returns The final DataResponse after all middlewares have processed.
718
+ * @returns Response and durationByDataSource (exclusive ms per source name).
634
719
  */
635
- async function _AssetsController_executeMiddlewares(middlewares, request, initialResponse = {}) {
636
- const chain = middlewares.reduceRight((next, middleware) => async (ctx) => {
720
+ async function _AssetsController_executeMiddlewares(sources, request, initialResponse = {}) {
721
+ const names = sources.map((source) => source.getName());
722
+ const middlewares = sources.map((source) => source.assetsMiddleware);
723
+ const inclusive = [];
724
+ const wrapped = middlewares.map((middleware, i) => (async (ctx, next) => {
725
+ const start = Date.now();
726
+ try {
727
+ return await middleware(ctx, next);
728
+ }
729
+ finally {
730
+ inclusive[i] = Date.now() - start;
731
+ }
732
+ }));
733
+ const chain = wrapped.reduceRight((next, middleware) => async (ctx) => {
637
734
  try {
638
735
  return await middleware(ctx, next);
639
736
  }
@@ -647,33 +744,16 @@ async function _AssetsController_executeMiddlewares(middlewares, request, initia
647
744
  response: initialResponse,
648
745
  getAssetsState: () => this.state,
649
746
  });
650
- return result.response;
651
- }, _AssetsController_assignChainsToDataSources = function _AssetsController_assignChainsToDataSources(requestedChains) {
652
- const assignment = new Map();
653
- const remainingChains = new Set(requestedChains);
654
- for (const sourceId of __classPrivateFieldGet(this, _AssetsController_dataSources, "f").keys()) {
655
- // Get available chains for this data source
656
- const availableChains = __classPrivateFieldGet(this, _AssetsController_dataSources, "f").get(sourceId);
657
- if (!availableChains || availableChains.size === 0) {
658
- continue;
659
- }
660
- const chainsForThisSource = [];
661
- for (const chainId of remainingChains) {
662
- // Check if this chain is available on this source
663
- if (availableChains.has(chainId)) {
664
- chainsForThisSource.push(chainId);
665
- remainingChains.delete(chainId);
666
- }
667
- }
668
- if (chainsForThisSource.length > 0) {
669
- assignment.set(sourceId, chainsForThisSource);
670
- log('Assigned chains to data source', {
671
- sourceId,
672
- chains: chainsForThisSource,
673
- });
747
+ const durationByDataSource = {};
748
+ for (let i = 0; i < inclusive.length; i++) {
749
+ const nextInc = i + 1 < inclusive.length ? (inclusive[i + 1] ?? 0) : 0;
750
+ const exclusive = Math.max(0, (inclusive[i] ?? 0) - nextInc);
751
+ const name = names[i];
752
+ if (name !== undefined) {
753
+ durationByDataSource[name] = exclusive;
674
754
  }
675
755
  }
676
- return assignment;
756
+ return { response: result.response, durationByDataSource };
677
757
  }, _AssetsController_updateState =
678
758
  // ============================================================================
679
759
  // STATE MANAGEMENT
@@ -692,12 +772,12 @@ async function _AssetsController_updateState(response) {
692
772
  const changedMetadata = [];
693
773
  this.update((state) => {
694
774
  // Use type assertions to avoid deep type instantiation issues with Immer Draft types
695
- const metadata = state.assetsMetadata;
775
+ const metadata = state.assetsInfo;
696
776
  const balances = state.assetsBalance;
697
777
  const prices = state.assetsPrice;
698
- if (normalizedResponse.assetsMetadata) {
699
- for (const [key, value] of Object.entries(normalizedResponse.assetsMetadata)) {
700
- if (!(0, lodash_1.isEqual)(previousState.assetsMetadata[key], value)) {
778
+ if (normalizedResponse.assetsInfo) {
779
+ for (const [key, value] of Object.entries(normalizedResponse.assetsInfo)) {
780
+ if (!(0, lodash_1.isEqual)(previousState.assetsInfo[key], value)) {
701
781
  changedMetadata.push(key);
702
782
  }
703
783
  metadata[key] = value;
@@ -802,7 +882,7 @@ async function _AssetsController_updateState(response) {
802
882
  const accountBalances = this.state.assetsBalance[account.id] ?? {};
803
883
  for (const [assetId, balance] of Object.entries(accountBalances)) {
804
884
  const typedAssetId = assetId;
805
- const metadataRaw = this.state.assetsMetadata[typedAssetId];
885
+ const metadataRaw = this.state.assetsInfo[typedAssetId];
806
886
  // Skip assets without metadata
807
887
  if (!metadataRaw) {
808
888
  continue;
@@ -867,98 +947,112 @@ async function _AssetsController_updateState(response) {
867
947
  selectedAccountCount: __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length,
868
948
  enabledChainCount: __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size,
869
949
  });
870
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToDataSources).call(this);
871
- if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
872
- this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
873
- chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
874
- forceUpdate: true,
875
- }).catch((error) => {
876
- log('Failed to fetch assets', error);
877
- });
878
- }
950
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
951
+ this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
952
+ chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
953
+ forceUpdate: true,
954
+ }).catch((error) => {
955
+ log('Failed to fetch assets', error);
956
+ });
879
957
  }, _AssetsController_stop = function _AssetsController_stop() {
880
958
  log('Stopping asset tracking', {
881
959
  activeSubscriptionCount: __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").size,
882
960
  hasPriceSubscription: __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").has('ds:PriceDataSource'),
883
961
  });
962
+ __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, false, "f");
884
963
  // Stop price subscription first (uses direct messenger call)
885
964
  this.unsubscribeAssetsPrice();
886
965
  // Stop balance subscriptions by properly notifying data sources via messenger
887
- // This ensures data sources stop their polling timers
888
- // Convert to array first to avoid modifying map during iteration
966
+ // This ensures data sources stop their polling timers.
967
+ // Use #allBalanceDataSources + staked balance source so we unsubscribe from
968
+ // every source that may have been subscribed.
969
+ const allSources = [
970
+ ...__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_allBalanceDataSources_get),
971
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
972
+ ];
889
973
  const subscriptionKeys = [...__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").keys()];
890
974
  for (const subscriptionKey of subscriptionKeys) {
891
- // Extract sourceId from subscription key (format: "ds:${sourceId}")
892
975
  if (subscriptionKey.startsWith('ds:')) {
893
976
  const sourceId = subscriptionKey.slice(3);
894
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, sourceId);
977
+ const source = allSources.find((ds) => ds.getName() === sourceId);
978
+ if (source) {
979
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
980
+ }
895
981
  }
896
982
  }
897
983
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
898
- }, _AssetsController_subscribeToDataSources = function _AssetsController_subscribeToDataSources() {
984
+ }, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
899
985
  if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
900
986
  return;
901
987
  }
902
988
  // Subscribe to balance updates (batched by data source)
903
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this);
989
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssetsBalance).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [
990
+ ...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f"),
991
+ ]);
992
+ // Subscribe to staked balance updates (separate from regular balance chain-claiming)
993
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeStakedBalance).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [
994
+ ...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f"),
995
+ ]);
904
996
  // Subscribe to price updates for all assets held by selected accounts
905
997
  this.subscribeAssetsPrice(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")]);
906
- }, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance() {
907
- // Step 1: Build chain -> accounts mapping based on account scopes and enabled networks
908
- const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), __classPrivateFieldGet(this, _AssetsController_enabledChains, "f"));
909
- // Step 2: Split by data source active chains (ordered by priority)
910
- // Get all chains that need to be subscribed
998
+ }, _AssetsController_subscribeAssetsBalance = function _AssetsController_subscribeAssetsBalance(accounts, chainIds) {
999
+ const chainToAccounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildChainToAccountsMap).call(this, accounts, new Set(chainIds));
911
1000
  const remainingChains = new Set(chainToAccounts.keys());
912
- // Assign chains to data sources based on availability (ordered by priority)
913
- const chainAssignment = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_assignChainsToDataSources).call(this, Array.from(remainingChains));
914
- log('Subscribe - chain assignment', {
915
- totalChains: remainingChains.size,
916
- dataSourceAssignments: Array.from(chainAssignment.entries()).map(([sourceId, chains]) => ({ sourceId, chainCount: chains.length })),
917
- });
918
- // Subscribe to each data source with its assigned chains and relevant accounts
919
- for (const sourceId of __classPrivateFieldGet(this, _AssetsController_dataSources, "f").keys()) {
920
- const assignedChains = chainAssignment.get(sourceId);
921
- if (!assignedChains || assignedChains.length === 0) {
922
- // Unsubscribe from data sources with no assigned chains
923
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, sourceId);
924
- continue;
1001
+ // When basic functionality is on (getter true), use all balance data sources; when off (getter false), RPC only.
1002
+ const balanceDataSources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
1003
+ ? __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_allBalanceDataSources_get)
1004
+ : [__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")];
1005
+ for (const source of balanceDataSources) {
1006
+ const availableChains = new Set(source.getActiveChainsSync());
1007
+ const assignedChains = [];
1008
+ for (const chainId of remainingChains) {
1009
+ if (availableChains.has(chainId)) {
1010
+ assignedChains.push(chainId);
1011
+ remainingChains.delete(chainId);
1012
+ }
925
1013
  }
926
- // Collect unique accounts that need any of the assigned chains
927
- const accountsForSource = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAccountsForChains).call(this, assignedChains, chainToAccounts);
928
- if (accountsForSource.length === 0) {
1014
+ if (assignedChains.length === 0) {
1015
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
929
1016
  continue;
930
1017
  }
931
- // Subscribe with ONE call per data source
932
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToDataSource).call(this, sourceId, accountsForSource, assignedChains);
1018
+ const seenIds = new Set();
1019
+ const accountsForSource = assignedChains
1020
+ .flatMap((chainId) => chainToAccounts.get(chainId) ?? [])
1021
+ .filter((account) => !seenIds.has(account.id) && (seenIds.add(account.id), true));
1022
+ if (accountsForSource.length > 0) {
1023
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accountsForSource, assignedChains);
1024
+ }
1025
+ }
1026
+ }, _AssetsController_subscribeStakedBalance = function _AssetsController_subscribeStakedBalance(accounts, chainIds) {
1027
+ const source = __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f");
1028
+ if (!source) {
1029
+ return;
933
1030
  }
1031
+ const availableChains = new Set(source.getActiveChainsSync());
1032
+ const assignedChains = chainIds.filter((chainId) => availableChains.has(chainId));
1033
+ if (assignedChains.length === 0) {
1034
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
1035
+ return;
1036
+ }
1037
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accounts, assignedChains);
934
1038
  }, _AssetsController_buildChainToAccountsMap = function _AssetsController_buildChainToAccountsMap(accounts, chainsToSubscribe) {
935
1039
  const chainToAccounts = new Map();
936
1040
  for (const account of accounts) {
937
- const accountChains = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account);
938
- for (const chainId of accountChains) {
1041
+ for (const chainId of __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account)) {
939
1042
  if (!chainsToSubscribe.has(chainId)) {
940
1043
  continue;
941
1044
  }
942
- const existingAccounts = chainToAccounts.get(chainId) ?? [];
943
- existingAccounts.push(account);
944
- chainToAccounts.set(chainId, existingAccounts);
945
- }
946
- }
947
- return chainToAccounts;
948
- }, _AssetsController_getAccountsForChains = function _AssetsController_getAccountsForChains(chains, chainToAccounts) {
949
- const accountIds = new Set();
950
- const accounts = [];
951
- for (const chainId of chains) {
952
- const chainAccounts = chainToAccounts.get(chainId) ?? [];
953
- for (const account of chainAccounts) {
954
- if (!accountIds.has(account.id)) {
955
- accountIds.add(account.id);
956
- accounts.push(account);
1045
+ let list = chainToAccounts.get(chainId);
1046
+ if (!list) {
1047
+ list = [];
1048
+ chainToAccounts.set(chainId, list);
957
1049
  }
1050
+ list.push(account);
958
1051
  }
959
1052
  }
960
- return accounts;
961
- }, _AssetsController_subscribeToDataSource = function _AssetsController_subscribeToDataSource(sourceId, accounts, chains) {
1053
+ return chainToAccounts;
1054
+ }, _AssetsController_subscribeDataSource = function _AssetsController_subscribeDataSource(source, accounts, chains) {
1055
+ const sourceId = source.getName();
962
1056
  const subscriptionKey = `ds:${sourceId}`;
963
1057
  const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
964
1058
  const isUpdate = existingSubscription !== undefined;
@@ -969,68 +1063,72 @@ async function _AssetsController_updateState(response) {
969
1063
  accountCount: accounts.length,
970
1064
  chainCount: chains.length,
971
1065
  });
972
- // Call data source subscribe action via Messenger (fire-and-forget)
973
- (async () => {
974
- try {
975
- await this.messenger.call(`${sourceId}:subscribe`, {
976
- request: {
977
- accounts,
978
- chainIds: chains,
979
- assetTypes: ['fungible'],
980
- dataTypes: ['balance'],
981
- updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
982
- },
983
- subscriptionId: subscriptionKey,
984
- isUpdate,
985
- });
986
- }
987
- catch (error) {
988
- console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
989
- }
990
- })().catch(console.error);
1066
+ const subscribeReq = {
1067
+ request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chains, {
1068
+ assetTypes: ['fungible'],
1069
+ dataTypes: ['balance'],
1070
+ updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
1071
+ }),
1072
+ subscriptionId: subscriptionKey,
1073
+ isUpdate,
1074
+ onAssetsUpdate: (response) => this.handleAssetsUpdate(response, sourceId),
1075
+ getAssetsState: () => this.state,
1076
+ };
1077
+ source.subscribe(subscribeReq).catch((error) => {
1078
+ console.error(`[AssetsController] Failed to subscribe to '${sourceId}':`, error);
1079
+ });
991
1080
  // Track subscription
992
1081
  const subscription = {
993
1082
  chains,
994
1083
  accountId: subscriptionKey,
995
1084
  assetTypes: ['fungible'],
996
- dataTypes: ['balance', 'price'],
1085
+ dataTypes: ['balance'],
997
1086
  unsubscribe: () => {
998
1087
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").delete(subscriptionKey);
999
1088
  },
1000
1089
  };
1001
1090
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").set(subscriptionKey, subscription);
1002
- }, _AssetsController_unsubscribeDataSource = function _AssetsController_unsubscribeDataSource(sourceId) {
1003
- const subscriptionKey = `ds:${sourceId}`;
1091
+ }, _AssetsController_unsubscribeDataSource = function _AssetsController_unsubscribeDataSource(source) {
1092
+ const subscriptionKey = `ds:${source.getName()}`;
1004
1093
  const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
1005
1094
  if (existingSubscription) {
1006
- // Fire-and-forget unsubscribe call
1007
- (async () => {
1008
- try {
1009
- await this.messenger.call(`${sourceId}:unsubscribe`, subscriptionKey);
1010
- }
1011
- catch {
1012
- // Ignore errors - source may not have been subscribed
1013
- }
1014
- })().catch(() => {
1015
- // Ignore errors - source may not have been subscribed
1016
- });
1095
+ source.unsubscribe(subscriptionKey).catch(() => undefined);
1017
1096
  existingSubscription.unsubscribe();
1018
1097
  }
1098
+ }, _AssetsController_buildDataRequest = function _AssetsController_buildDataRequest(accounts, chainIds, partial = {}) {
1099
+ const chainIdSet = new Set(chainIds);
1100
+ const accountsWithSupportedChains = accounts.map((account) => ({
1101
+ account,
1102
+ supportedChains: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getEnabledChainsForAccount).call(this, account).filter((chain) => chainIdSet.has(chain)),
1103
+ }));
1104
+ return {
1105
+ accountsWithSupportedChains,
1106
+ chainIds,
1107
+ ...partial,
1108
+ };
1019
1109
  }, _AssetsController_getEnabledChainsForAccount = function _AssetsController_getEnabledChainsForAccount(account) {
1020
1110
  // Account scopes are CAIP-2 chain IDs like "eip155:1", "solana:mainnet", "bip122:..."
1021
1111
  const scopes = account.scopes ?? [];
1022
1112
  const result = [];
1023
1113
  for (const scope of scopes) {
1024
- const [namespace, reference] = scope.split(':');
1114
+ const scopeStr = scope;
1115
+ if (!(0, utils_1.isCaipChainId)(scopeStr)) {
1116
+ result.push(scope);
1117
+ continue;
1118
+ }
1119
+ const { namespace, reference } = (0, utils_1.parseCaipChainId)(scopeStr);
1025
1120
  // Wildcard scope (e.g., "eip155:0" means all enabled chains in that namespace)
1026
1121
  if (reference === '0') {
1027
1122
  for (const chain of __classPrivateFieldGet(this, _AssetsController_enabledChains, "f")) {
1028
- if (chain.startsWith(`${namespace}:`)) {
1029
- result.push(chain);
1123
+ if ((0, utils_1.isCaipChainId)(chain)) {
1124
+ const chainParsed = (0, utils_1.parseCaipChainId)(chain);
1125
+ if (chainParsed.namespace === namespace) {
1126
+ result.push(chain);
1127
+ }
1030
1128
  }
1031
1129
  }
1032
1130
  }
1033
- else if (namespace === 'eip155' && reference?.startsWith('0x')) {
1131
+ else if (namespace === 'eip155' && (0, utils_1.isStrictHexString)(reference)) {
1034
1132
  // Normalize hex to decimal for EIP155
1035
1133
  result.push(`eip155:${parseInt(reference, 16)}`);
1036
1134
  }
@@ -1050,7 +1148,7 @@ async function _AssetsController_handleAccountGroupChanged() {
1050
1148
  accountIds: accounts.map((a) => a.id),
1051
1149
  });
1052
1150
  // Subscribe and fetch for the new account group
1053
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToDataSources).call(this);
1151
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1054
1152
  if (accounts.length > 0) {
1055
1153
  await this.getAssets(accounts, {
1056
1154
  chainIds: [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")],
@@ -1084,7 +1182,7 @@ async function _AssetsController_handleAccountGroupChanged() {
1084
1182
  // Users may want to see historical balances even if the network is currently disabled.
1085
1183
  // The data will simply not be updated until the network is re-enabled.
1086
1184
  // Refresh subscriptions for new chain set
1087
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToDataSources).call(this);
1185
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
1088
1186
  // Do one-time fetch for newly enabled chains
1089
1187
  if (addedChains.length > 0 && __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length > 0) {
1090
1188
  await this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
@@ -1092,28 +1190,5 @@ async function _AssetsController_handleAccountGroupChanged() {
1092
1190
  forceUpdate: true,
1093
1191
  });
1094
1192
  }
1095
- }, _AssetsController_handleSubscriptionUpdate =
1096
- /**
1097
- * Handle an async update from a data source subscription.
1098
- * Enriches response with token metadata before updating state.
1099
- *
1100
- * @param response - The data response from the data source.
1101
- * @param _sourceId - The source ID (unused but kept for logging context).
1102
- * @param request - Optional original request for context.
1103
- */
1104
- async function _AssetsController_handleSubscriptionUpdate(response, _sourceId, request) {
1105
- // Run through enrichment middlewares (Event Stack: Detection → Token → Price)
1106
- // Include 'metadata' in dataTypes so TokenDataSource runs to enrich detected assets
1107
- const enrichedResponse = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
1108
- this.messenger.call('DetectionMiddleware:getAssetsMiddleware'),
1109
- this.messenger.call('TokenDataSource:getAssetsMiddleware'),
1110
- this.messenger.call('PriceDataSource:getAssetsMiddleware'),
1111
- ], request ?? {
1112
- accounts: [],
1113
- chainIds: [],
1114
- dataTypes: ['balance', 'metadata', 'price'],
1115
- }, response);
1116
- // Update state
1117
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, enrichedResponse);
1118
1193
  };
1119
1194
  //# sourceMappingURL=AssetsController.cjs.map