@metamask/assets-controller 6.0.0 → 6.2.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 (156) hide show
  1. package/CHANGELOG.md +50 -4
  2. package/dist/AssetsController.cjs +205 -29
  3. package/dist/AssetsController.cjs.map +1 -1
  4. package/dist/AssetsController.d.cts +8 -1
  5. package/dist/AssetsController.d.cts.map +1 -1
  6. package/dist/AssetsController.d.mts +8 -1
  7. package/dist/AssetsController.d.mts.map +1 -1
  8. package/dist/AssetsController.mjs +206 -30
  9. package/dist/AssetsController.mjs.map +1 -1
  10. package/dist/data-sources/AccountsApiDataSource.cjs +6 -3
  11. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  12. package/dist/data-sources/AccountsApiDataSource.d.cts +6 -0
  13. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  14. package/dist/data-sources/AccountsApiDataSource.d.mts +6 -0
  15. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  16. package/dist/data-sources/AccountsApiDataSource.mjs +7 -4
  17. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  18. package/dist/data-sources/BackendWebsocketDataSource.cjs +5 -3
  19. package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
  20. package/dist/data-sources/BackendWebsocketDataSource.d.cts +3 -1
  21. package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
  22. package/dist/data-sources/BackendWebsocketDataSource.d.mts +3 -1
  23. package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
  24. package/dist/data-sources/BackendWebsocketDataSource.mjs +5 -3
  25. package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
  26. package/dist/data-sources/PriceDataSource.cjs +12 -8
  27. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  28. package/dist/data-sources/PriceDataSource.d.cts +5 -0
  29. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  30. package/dist/data-sources/PriceDataSource.d.mts +5 -0
  31. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  32. package/dist/data-sources/PriceDataSource.mjs +12 -8
  33. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  34. package/dist/data-sources/RpcDataSource.cjs +25 -10
  35. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  36. package/dist/data-sources/RpcDataSource.d.cts +4 -3
  37. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  38. package/dist/data-sources/RpcDataSource.d.mts +4 -3
  39. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  40. package/dist/data-sources/RpcDataSource.mjs +25 -10
  41. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  42. package/dist/data-sources/TokenDataSource.cjs +24 -14
  43. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  44. package/dist/data-sources/TokenDataSource.d.cts +5 -0
  45. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  46. package/dist/data-sources/TokenDataSource.d.mts +5 -0
  47. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  48. package/dist/data-sources/TokenDataSource.mjs +24 -14
  49. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  50. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs +8 -0
  51. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs.map +1 -1
  52. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts.map +1 -1
  53. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts.map +1 -1
  54. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs +8 -0
  55. package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs.map +1 -1
  56. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +45 -25
  57. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
  58. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +11 -2
  59. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
  60. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +11 -2
  61. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
  62. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +45 -25
  63. package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
  64. package/dist/data-sources/evm-rpc-services/types/state.cjs.map +1 -1
  65. package/dist/data-sources/evm-rpc-services/types/state.d.cts +6 -0
  66. package/dist/data-sources/evm-rpc-services/types/state.d.cts.map +1 -1
  67. package/dist/data-sources/evm-rpc-services/types/state.d.mts +6 -0
  68. package/dist/data-sources/evm-rpc-services/types/state.d.mts.map +1 -1
  69. package/dist/data-sources/evm-rpc-services/types/state.mjs.map +1 -1
  70. package/dist/errors.cjs +25 -0
  71. package/dist/errors.cjs.map +1 -0
  72. package/dist/errors.d.cts +25 -0
  73. package/dist/errors.d.cts.map +1 -0
  74. package/dist/errors.d.mts +25 -0
  75. package/dist/errors.d.mts.map +1 -0
  76. package/dist/errors.mjs +21 -0
  77. package/dist/errors.mjs.map +1 -0
  78. package/dist/index.cjs +5 -1
  79. package/dist/index.cjs.map +1 -1
  80. package/dist/index.d.cts +3 -1
  81. package/dist/index.d.cts.map +1 -1
  82. package/dist/index.d.mts +3 -1
  83. package/dist/index.d.mts.map +1 -1
  84. package/dist/index.mjs +2 -1
  85. package/dist/index.mjs.map +1 -1
  86. package/dist/middlewares/CustomAssetGraduationMiddleware.cjs +121 -0
  87. package/dist/middlewares/CustomAssetGraduationMiddleware.cjs.map +1 -0
  88. package/dist/middlewares/CustomAssetGraduationMiddleware.d.cts +25 -0
  89. package/dist/middlewares/CustomAssetGraduationMiddleware.d.cts.map +1 -0
  90. package/dist/middlewares/CustomAssetGraduationMiddleware.d.mts +25 -0
  91. package/dist/middlewares/CustomAssetGraduationMiddleware.d.mts.map +1 -0
  92. package/dist/middlewares/CustomAssetGraduationMiddleware.mjs +117 -0
  93. package/dist/middlewares/CustomAssetGraduationMiddleware.mjs.map +1 -0
  94. package/dist/middlewares/RpcFallbackMiddleware.cjs +90 -0
  95. package/dist/middlewares/RpcFallbackMiddleware.cjs.map +1 -0
  96. package/dist/middlewares/RpcFallbackMiddleware.d.cts +23 -0
  97. package/dist/middlewares/RpcFallbackMiddleware.d.cts.map +1 -0
  98. package/dist/middlewares/RpcFallbackMiddleware.d.mts +23 -0
  99. package/dist/middlewares/RpcFallbackMiddleware.d.mts.map +1 -0
  100. package/dist/middlewares/RpcFallbackMiddleware.mjs +86 -0
  101. package/dist/middlewares/RpcFallbackMiddleware.mjs.map +1 -0
  102. package/dist/middlewares/index.cjs +5 -1
  103. package/dist/middlewares/index.cjs.map +1 -1
  104. package/dist/middlewares/index.d.cts +4 -0
  105. package/dist/middlewares/index.d.cts.map +1 -1
  106. package/dist/middlewares/index.d.mts +4 -0
  107. package/dist/middlewares/index.d.mts.map +1 -1
  108. package/dist/middlewares/index.mjs +2 -0
  109. package/dist/middlewares/index.mjs.map +1 -1
  110. package/dist/types.cjs.map +1 -1
  111. package/dist/types.d.cts +7 -0
  112. package/dist/types.d.cts.map +1 -1
  113. package/dist/types.d.mts +7 -0
  114. package/dist/types.d.mts.map +1 -1
  115. package/dist/types.mjs.map +1 -1
  116. package/dist/utils/fetchWithTimeout.cjs +30 -0
  117. package/dist/utils/fetchWithTimeout.cjs.map +1 -0
  118. package/dist/utils/fetchWithTimeout.d.cts +11 -0
  119. package/dist/utils/fetchWithTimeout.d.cts.map +1 -0
  120. package/dist/utils/fetchWithTimeout.d.mts +11 -0
  121. package/dist/utils/fetchWithTimeout.d.mts.map +1 -0
  122. package/dist/utils/fetchWithTimeout.mjs +26 -0
  123. package/dist/utils/fetchWithTimeout.mjs.map +1 -0
  124. package/dist/utils/formatExchangeRatesForBridge.cjs +10 -8
  125. package/dist/utils/formatExchangeRatesForBridge.cjs.map +1 -1
  126. package/dist/utils/formatExchangeRatesForBridge.d.cts +5 -3
  127. package/dist/utils/formatExchangeRatesForBridge.d.cts.map +1 -1
  128. package/dist/utils/formatExchangeRatesForBridge.d.mts +5 -3
  129. package/dist/utils/formatExchangeRatesForBridge.d.mts.map +1 -1
  130. package/dist/utils/formatExchangeRatesForBridge.mjs +11 -9
  131. package/dist/utils/formatExchangeRatesForBridge.mjs.map +1 -1
  132. package/dist/utils/formatStateForTransactionPay.cjs +8 -6
  133. package/dist/utils/formatStateForTransactionPay.cjs.map +1 -1
  134. package/dist/utils/formatStateForTransactionPay.d.cts +2 -2
  135. package/dist/utils/formatStateForTransactionPay.d.cts.map +1 -1
  136. package/dist/utils/formatStateForTransactionPay.d.mts +2 -2
  137. package/dist/utils/formatStateForTransactionPay.d.mts.map +1 -1
  138. package/dist/utils/formatStateForTransactionPay.mjs +8 -6
  139. package/dist/utils/formatStateForTransactionPay.mjs.map +1 -1
  140. package/dist/utils/index.cjs +6 -1
  141. package/dist/utils/index.cjs.map +1 -1
  142. package/dist/utils/index.d.cts +2 -0
  143. package/dist/utils/index.d.cts.map +1 -1
  144. package/dist/utils/index.d.mts +2 -0
  145. package/dist/utils/index.d.mts.map +1 -1
  146. package/dist/utils/index.mjs +2 -0
  147. package/dist/utils/index.mjs.map +1 -1
  148. package/dist/utils/native-assets.cjs +63 -0
  149. package/dist/utils/native-assets.cjs.map +1 -0
  150. package/dist/utils/native-assets.d.cts +19 -0
  151. package/dist/utils/native-assets.d.cts.map +1 -0
  152. package/dist/utils/native-assets.d.mts +19 -0
  153. package/dist/utils/native-assets.d.mts.map +1 -0
  154. package/dist/utils/native-assets.mjs +58 -0
  155. package/dist/utils/native-assets.mjs.map +1 -0
  156. package/package.json +8 -8
package/CHANGELOG.md CHANGED
@@ -7,6 +7,51 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [6.2.0]
11
+
12
+ ### Added
13
+
14
+ - Add `CustomAssetGraduationMiddleware` that removes an EVM asset from `customAssets[selectedAccount]` when `AccountsApiDataSource` or `BackendWebsocketDataSource` reports a balance for it ([#8582](https://github.com/MetaMask/core/pull/8582))
15
+ - Non-EVM custom assets (Solana, BTC, Tron) are not affected.
16
+ - `RpcDataSource` continues to be the sole balance fetcher for assets still in `customAssets`.
17
+ - Add `RpcFallbackMiddleware` to the fast pipeline so chains that error in `response.errors` (network error, `unprocessedNetworks`, timeout) fall back to `RpcDataSource` ([#8582](https://github.com/MetaMask/core/pull/8582))
18
+ - Successful RPC results are merged into the response and recovered chains are cleared from `response.errors`.
19
+ - Add a configurable `fetchTimeoutMs` option (default `15000`) to `AccountsApiDataSource`, `PriceDataSource`, and `TokenDataSource` ([#8582](https://github.com/MetaMask/core/pull/8582))
20
+ - On timeout, AccountsAPI marks every requested chain as errored so `RpcFallbackMiddleware` picks them up; price and token enrichment degrade gracefully.
21
+ - Add `fetchWithTimeout` utility that races an async task against a timeout ([#8582](https://github.com/MetaMask/core/pull/8582))
22
+
23
+ ### Changed
24
+
25
+ - Bump `@metamask/transaction-controller` from `^64.3.0` to `^64.4.0` ([#8585](https://github.com/MetaMask/core/pull/8585))
26
+
27
+ ### Fixed
28
+
29
+ - Handle trace callback returning `undefined` without throwing ([#8586](https://github.com/MetaMask/core/pull/8586))
30
+
31
+ ## [6.1.0]
32
+
33
+ ### Added
34
+
35
+ - Add newly supported chains to multicall contract support in `MulticallClient` ([#8346](https://github.com/MetaMask/core/pull/8346))
36
+ - Tempo Mainnet (`4217`/`0x1079`)
37
+ - Tempo Testnet Moderato (`42431`/`0xa5bf`)
38
+ - Ink Mainnet (`57073`/`0xdef1`)
39
+ - Stable mainnet (`988`/`0x3dc`)
40
+
41
+ ### Changed
42
+
43
+ - Bump `@metamask/assets-controllers` from `^104.0.0` to `^104.3.0` ([#8509](https://github.com/MetaMask/core/pull/8509), [#8544](https://github.com/MetaMask/core/pull/8544), [#8559](https://github.com/MetaMask/core/pull/8559))
44
+ - Bump `@metamask/keyring-api` from `^21.6.0` to `^23.0.1` ([#8464](https://github.com/MetaMask/core/pull/8464))
45
+ - Bump `@metamask/keyring-internal-api` from `^10.0.0` to `^10.1.1` ([#8464](https://github.com/MetaMask/core/pull/8464))
46
+ - Bump `@metamask/keyring-snap-client` from `^8.2.0` to `^9.0.1` ([#8464](https://github.com/MetaMask/core/pull/8464))
47
+ - Bump `@metamask/transaction-controller` from `^64.2.0` to `^64.3.0` ([#8482](https://github.com/MetaMask/core/pull/8482))
48
+
49
+ ### Fixed
50
+
51
+ - Native asset detection now correctly identifies native assets across all CAIP-19 representations, not just `slip44:` namespace checks ([#8483](https://github.com/MetaMask/core/pull/8483))
52
+ - Previously, native assets represented as ERC-20 tokens were not recognized as native, causing incorrect token type classification.
53
+ - Exempt mUSD token from EVM ERC-20 minimum-occurrence spam filter so it is no longer incorrectly hidden ([#8541](https://github.com/MetaMask/core/pull/8541))
54
+
10
55
  ## [6.0.0]
11
56
 
12
57
  ### Added
@@ -187,9 +232,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
187
232
 
188
233
  ### Changed
189
234
 
190
- - Bump `@metamask/assets-controllers` from `^100.0.3` to `^100.2.0` ([#8107](https://github.com/MetaMask/core/pull/8107)), ([#8140](https://github.com/MetaMask/core/pull/8140))
235
+ - Bump `@metamask/assets-controllers` from `^100.0.3` to `^100.2.0`, ([#8107](https://github.com/MetaMask/core/pull/8107), [#8140](https://github.com/MetaMask/core/pull/8140))
191
236
  - Bump `@metamask/network-enablement-controller` from `^4.1.2` to `^4.2.0` ([#8107](https://github.com/MetaMask/core/pull/8107))
192
- - Bump `@metamask/transaction-controller` from `^62.19.0` to `^62.21.0` ([#8104](https://github.com/MetaMask/core/pull/8104)), ([#8140](https://github.com/MetaMask/core/pull/8140))
237
+ - Bump `@metamask/transaction-controller` from `^62.19.0` to `^62.21.0`, ([#8104](https://github.com/MetaMask/core/pull/8104), [#8140](https://github.com/MetaMask/core/pull/8140))
193
238
  - Bump `@metamask/account-tree-controller` from `^4.1.1` to `^5.0.0` ([#8140](https://github.com/MetaMask/core/pull/8140))
194
239
  - Bump `@metamask/core-backend` from `^6.0.0` to `^6.1.0` ([#8140](https://github.com/MetaMask/core/pull/8140))
195
240
  - Bump `@metamask/preferences-controller` from `^22.1.0` to `^23.0.0` ([#8140](https://github.com/MetaMask/core/pull/8140))
@@ -302,7 +347,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
302
347
  ### Changed
303
348
 
304
349
  - 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))
305
-
306
350
  - Replace `viem` dependency with `@ethersproject/abi` for ABI encoding/decoding in `MulticallClient` ([#7839](https://github.com/MetaMask/core/pull/7839))
307
351
 
308
352
  ## [0.1.0]
@@ -329,7 +373,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
329
373
  - Refactor `RpcDataSource` to delegate polling to `BalanceFetcher` and `TokenDetector` services ([#7709](https://github.com/MetaMask/core/pull/7709))
330
374
  - Refactor `BalanceFetcher` and `TokenDetector` to extend `StaticIntervalPollingControllerOnly` for independent polling management ([#7709](https://github.com/MetaMask/core/pull/7709))
331
375
 
332
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@6.0.0...HEAD
376
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@6.2.0...HEAD
377
+ [6.2.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@6.1.0...@metamask/assets-controller@6.2.0
378
+ [6.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@6.0.0...@metamask/assets-controller@6.1.0
333
379
  [6.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@5.0.1...@metamask/assets-controller@6.0.0
334
380
  [5.0.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@5.0.0...@metamask/assets-controller@5.0.1
335
381
  [5.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controller@4.0.0...@metamask/assets-controller@5.0.0
@@ -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_trace, _AssetsController_firstInitFetchReported, _AssetsController_stateSizeReported, _AssetsController_emitTrace, _AssetsController_emitStateSizeTrace, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_lastKnownAccountIds, _AssetsController_getSelectedAccounts, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_onUnapprovedTransactionAdded, _AssetsController_updateActive, _AssetsController_handleAccountTreeStateChange, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_shouldHideNativeToken, _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_trace, _AssetsController_captureException, _AssetsController_firstInitFetchReported, _AssetsController_stateSizeReported, _AssetsController_emitTrace, _AssetsController_emitStateSizeTrace, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_lastKnownAccountIds, _AssetsController_getSelectedAccounts, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_customAssetGraduationMiddleware, _AssetsController_rpcFallbackMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_queryApiClient, _AssetsController_onActiveChainsUpdated, _AssetsController_initializeNativeAssetsMap, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_onUnapprovedTransactionAdded, _AssetsController_updateActive, _AssetsController_handleAccountTreeStateChange, _AssetsController_registerActionHandlers, _AssetsController_handleActiveChainsUpdate, _AssetsController_executeMiddlewares, _AssetsController_getNativeAssetMap, _AssetsController_isNativeAsset, _AssetsController_resolveNativeAssetIds, _AssetsController_getNativeAssetIdsForEnabledChains, _AssetsController_getNativeAssetIdsForAccount, _AssetsController_ensureNativeBalancesDefaultZero, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_shouldHideNativeToken, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeRpcCustomAssetsSupplement, _AssetsController_unsubscribeBySubscriptionKey, _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");
@@ -30,10 +30,15 @@ const RpcDataSource_1 = require("./data-sources/RpcDataSource.cjs");
30
30
  const SnapDataSource_1 = require("./data-sources/SnapDataSource.cjs");
31
31
  const StakedBalanceDataSource_1 = require("./data-sources/StakedBalanceDataSource.cjs");
32
32
  const TokenDataSource_1 = require("./data-sources/TokenDataSource.cjs");
33
+ const errors_1 = require("./errors.cjs");
33
34
  const logger_1 = require("./logger.cjs");
35
+ const CustomAssetGraduationMiddleware_1 = require("./middlewares/CustomAssetGraduationMiddleware.cjs");
34
36
  const DetectionMiddleware_1 = require("./middlewares/DetectionMiddleware.cjs");
35
37
  const ParallelMiddleware_1 = require("./middlewares/ParallelMiddleware.cjs");
38
+ const RpcFallbackMiddleware_1 = require("./middlewares/RpcFallbackMiddleware.cjs");
36
39
  const utils_2 = require("./utils/index.cjs");
40
+ const constants_1 = require("./utils/constants.cjs");
41
+ const NATIVE_ASSETS_QUERY_KEY = ['nativeAssets'];
37
42
  // ============================================================================
38
43
  // CONTROLLER CONSTANTS
39
44
  // ============================================================================
@@ -210,7 +215,7 @@ function normalizeResponse(response) {
210
215
  * - The controller does NOT manage polling - it simply receives pushed updates
211
216
  */
212
217
  class AssetsController extends base_controller_1.BaseController {
213
- constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, isBasicFunctionality, subscribeToBasicFunctionalityChange, queryApiClient, rpcDataSourceConfig, trace, accountsApiDataSourceConfig, priceDataSourceConfig, stakedBalanceDataSourceConfig, isOnboarded, }) {
218
+ constructor({ messenger, state = {}, defaultUpdateInterval = DEFAULT_POLLING_INTERVAL_MS, isEnabled = () => true, isBasicFunctionality, subscribeToBasicFunctionalityChange, queryApiClient, rpcDataSourceConfig, trace, captureException, accountsApiDataSourceConfig, priceDataSourceConfig, stakedBalanceDataSourceConfig, isOnboarded, }) {
214
219
  super({
215
220
  name: CONTROLLER_NAME,
216
221
  messenger,
@@ -229,6 +234,8 @@ class AssetsController extends base_controller_1.BaseController {
229
234
  _AssetsController_defaultUpdateInterval.set(this, void 0);
230
235
  /** Optional trace callback for first init/fetch measurement (duration). */
231
236
  _AssetsController_trace.set(this, void 0);
237
+ /** Optional reporter for Issue-style errors (e.g. Sentry.captureException). */
238
+ _AssetsController_captureException.set(this, void 0);
232
239
  /** Whether we have already reported first init fetch for this session (reset on #stop). */
233
240
  _AssetsController_firstInitFetchReported.set(this, false);
234
241
  /** Whether we have already reported state size for this session (reset on #stop). */
@@ -260,14 +267,20 @@ class AssetsController extends base_controller_1.BaseController {
260
267
  _AssetsController_stakedBalanceDataSource.set(this, void 0);
261
268
  _AssetsController_priceDataSource.set(this, void 0);
262
269
  _AssetsController_detectionMiddleware.set(this, void 0);
270
+ _AssetsController_customAssetGraduationMiddleware.set(this, void 0);
271
+ _AssetsController_rpcFallbackMiddleware.set(this, void 0);
263
272
  _AssetsController_tokenDataSource.set(this, void 0);
264
273
  _AssetsController_unsubscribeBasicFunctionality.set(this, null);
274
+ _AssetsController_queryApiClient.set(this, void 0);
265
275
  _AssetsController_onActiveChainsUpdated.set(this, void 0);
266
276
  __classPrivateFieldSet(this, _AssetsController_isEnabled, isEnabled(), "f");
267
277
  __classPrivateFieldSet(this, _AssetsController_isBasicFunctionality, isBasicFunctionality ?? (() => true), "f");
268
278
  __classPrivateFieldSet(this, _AssetsController_defaultUpdateInterval, defaultUpdateInterval, "f");
269
279
  __classPrivateFieldSet(this, _AssetsController_trace, trace, "f");
280
+ __classPrivateFieldSet(this, _AssetsController_captureException, captureException, "f");
281
+ __classPrivateFieldSet(this, _AssetsController_queryApiClient, queryApiClient, "f");
270
282
  const rpcConfig = rpcDataSourceConfig ?? {};
283
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeNativeAssetsMap).call(this, queryApiClient);
271
284
  __classPrivateFieldSet(this, _AssetsController_onActiveChainsUpdated, (dataSourceName, chains, previousChains) => {
272
285
  try {
273
286
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleActiveChainsUpdate).call(this, dataSourceName, chains, previousChains);
@@ -283,6 +296,7 @@ class AssetsController extends base_controller_1.BaseController {
283
296
  messenger: this.messenger,
284
297
  queryApiClient,
285
298
  onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
299
+ isNativeAsset: (assetId) => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isNativeAsset).call(this, assetId),
286
300
  }), "f");
287
301
  __classPrivateFieldSet(this, _AssetsController_accountsApiDataSource, new AccountsApiDataSource_1.AccountsApiDataSource({
288
302
  queryApiClient,
@@ -296,6 +310,8 @@ class AssetsController extends base_controller_1.BaseController {
296
310
  __classPrivateFieldSet(this, _AssetsController_rpcDataSource, new RpcDataSource_1.RpcDataSource({
297
311
  messenger: this.messenger,
298
312
  onActiveChainsUpdated: __classPrivateFieldGet(this, _AssetsController_onActiveChainsUpdated, "f"),
313
+ getNativeAssetForChain: (chainId) => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetMap).call(this)[chainId] ??
314
+ `${chainId}/erc20:${constants_1.ZERO_ADDRESS}`,
299
315
  ...rpcConfig,
300
316
  isOnboarded: rpcConfig.isOnboarded ?? isOnboarded,
301
317
  }), "f");
@@ -307,8 +323,7 @@ class AssetsController extends base_controller_1.BaseController {
307
323
  __classPrivateFieldSet(this, _AssetsController_tokenDataSource, new TokenDataSource_1.TokenDataSource(this.messenger, {
308
324
  queryApiClient,
309
325
  getNativeAssetIds: () => {
310
- const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
311
- return Object.values(nativeAssetIdentifiers);
326
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetIdsForEnabledChains).call(this);
312
327
  },
313
328
  }), "f");
314
329
  __classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource_1.PriceDataSource({
@@ -317,6 +332,20 @@ class AssetsController extends base_controller_1.BaseController {
317
332
  ...priceDataSourceConfig,
318
333
  }), "f");
319
334
  __classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware_1.DetectionMiddleware(), "f");
335
+ __classPrivateFieldSet(this, _AssetsController_customAssetGraduationMiddleware, new CustomAssetGraduationMiddleware_1.CustomAssetGraduationMiddleware({
336
+ getSelectedAccountId: () => {
337
+ try {
338
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this)[0]?.id;
339
+ }
340
+ catch {
341
+ return undefined;
342
+ }
343
+ },
344
+ removeCustomAsset: (accountId, assetId) => this.removeCustomAsset(accountId, assetId),
345
+ }), "f");
346
+ __classPrivateFieldSet(this, _AssetsController_rpcFallbackMiddleware, new RpcFallbackMiddleware_1.RpcFallbackMiddleware({
347
+ rpcDataSource: __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
348
+ }), "f");
320
349
  if (!__classPrivateFieldGet(this, _AssetsController_isEnabled, "f")) {
321
350
  log('AssetsController is disabled, skipping initialization');
322
351
  return;
@@ -385,6 +414,11 @@ class AssetsController extends base_controller_1.BaseController {
385
414
  __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
386
415
  __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
387
416
  ]),
417
+ // Graduation must run BEFORE the RPC fallback so it only sees
418
+ // AccountsApi/Websocket balances. RPC intentionally carries
419
+ // custom assets and must never trigger graduation.
420
+ __classPrivateFieldGet(this, _AssetsController_customAssetGraduationMiddleware, "f"),
421
+ __classPrivateFieldGet(this, _AssetsController_rpcFallbackMiddleware, "f"),
388
422
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
389
423
  (0, ParallelMiddleware_1.createParallelMiddleware)([
390
424
  __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
@@ -496,12 +530,12 @@ class AssetsController extends base_controller_1.BaseController {
496
530
  * @returns Bridge-compatible exchange rate state derived from assetsPrice and selectedCurrency.
497
531
  */
498
532
  getExchangeRatesForBridge() {
499
- const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
500
533
  const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
501
534
  return (0, utils_2.formatExchangeRatesForBridge)({
535
+ assetsInfo: this.state.assetsInfo,
502
536
  assetsPrice: this.state.assetsPrice,
503
537
  selectedCurrency: this.state.selectedCurrency,
504
- nativeAssetIdentifiers,
538
+ nativeAssetIdentifiers: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetMap).call(this),
505
539
  networkConfigurationsByChainId,
506
540
  });
507
541
  }
@@ -516,7 +550,6 @@ class AssetsController extends base_controller_1.BaseController {
516
550
  */
517
551
  getStateForTransactionPay() {
518
552
  const accounts = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getSelectedAccounts).call(this);
519
- const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
520
553
  const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
521
554
  return (0, utils_2.formatStateForTransactionPay)({
522
555
  assetsBalance: this.state.assetsBalance,
@@ -524,7 +557,7 @@ class AssetsController extends base_controller_1.BaseController {
524
557
  assetsPrice: this.state.assetsPrice,
525
558
  selectedCurrency: this.state.selectedCurrency,
526
559
  accounts: accounts.map((a) => ({ id: a.id, address: a.address })),
527
- nativeAssetIdentifiers,
560
+ nativeAssetIdentifiers: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetMap).call(this),
528
561
  networkConfigurationsByChainId,
529
562
  });
530
563
  }
@@ -568,7 +601,7 @@ class AssetsController extends base_controller_1.BaseController {
568
601
  if (pendingMetadata) {
569
602
  const parsed = (0, utils_1.parseCaipAssetType)(normalizedAssetId);
570
603
  let tokenType = 'erc20';
571
- if (parsed.assetNamespace === 'slip44') {
604
+ if (__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_isNativeAsset).call(this, normalizedAssetId)) {
572
605
  tokenType = 'native';
573
606
  }
574
607
  else if (parsed.assetNamespace === 'spl') {
@@ -597,6 +630,9 @@ class AssetsController extends base_controller_1.BaseController {
597
630
  updateMode: 'merge',
598
631
  });
599
632
  }
633
+ // Re-evaluate subscriptions so the supplemental RPC poll picks up the
634
+ // new customAsset on chains another data source already owns.
635
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
600
636
  }
601
637
  /**
602
638
  * Remove a custom asset from an account.
@@ -616,6 +652,9 @@ class AssetsController extends base_controller_1.BaseController {
616
652
  }
617
653
  }
618
654
  });
655
+ // Re-evaluate subscriptions so the supplemental RPC poll for that chain
656
+ // is torn down when no more customAssets remain there.
657
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeAssets).call(this);
619
658
  }
620
659
  /**
621
660
  * Get all custom assets for an account.
@@ -789,7 +828,17 @@ class AssetsController extends base_controller_1.BaseController {
789
828
  ...resolvedRequest,
790
829
  dataTypes: resolvedRequest.dataTypes.filter((dt) => dt !== 'metadata' && dt !== 'price'),
791
830
  };
792
- const enrichmentSources = [__classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f")];
831
+ // Graduate custom assets only when AccountsAPI / Websocket reports them.
832
+ // RPC already fetches custom assets on purpose, and Snap handles non-EVM
833
+ // chains the rule does not apply to, so skip the middleware for those.
834
+ const shouldGraduateCustomAssets = sourceId === 'AccountsApiDataSource' ||
835
+ sourceId === 'BackendWebsocketDataSource';
836
+ const enrichmentSources = [
837
+ ...(shouldGraduateCustomAssets
838
+ ? [__classPrivateFieldGet(this, _AssetsController_customAssetGraduationMiddleware, "f")]
839
+ : []),
840
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
841
+ ];
793
842
  if (__classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)) {
794
843
  enrichmentSources.push((0, ParallelMiddleware_1.createParallelMiddleware)([
795
844
  __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
@@ -844,13 +893,13 @@ class AssetsController extends base_controller_1.BaseController {
844
893
  }
845
894
  }
846
895
  exports.AssetsController = AssetsController;
847
- _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trace = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_stateSizeReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_lastKnownAccountIds = new WeakMap(), _AssetsController_backendWebsocketDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_stakedBalanceDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_onActiveChainsUpdated = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_emitTrace = function _AssetsController_emitTrace(name, data, tags = {
896
+ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trace = new WeakMap(), _AssetsController_captureException = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_stateSizeReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_lastKnownAccountIds = 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_customAssetGraduationMiddleware = new WeakMap(), _AssetsController_rpcFallbackMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_queryApiClient = new WeakMap(), _AssetsController_onActiveChainsUpdated = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_emitTrace = function _AssetsController_emitTrace(name, data, tags = {
848
897
  controller: 'AssetsController',
849
898
  }) {
850
899
  if (!__classPrivateFieldGet(this, _AssetsController_trace, "f")) {
851
900
  return;
852
901
  }
853
- __classPrivateFieldGet(this, _AssetsController_trace, "f").call(this, { name, data, tags }, () => undefined).catch(() => {
902
+ __classPrivateFieldGet(this, _AssetsController_trace, "f").call(this, { name, data, tags }, () => undefined)?.catch(() => {
854
903
  // Telemetry failure must not break.
855
904
  });
856
905
  }, _AssetsController_emitStateSizeTrace = function _AssetsController_emitStateSizeTrace() {
@@ -907,6 +956,25 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
907
956
  __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
908
957
  __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
909
958
  ];
959
+ }, _AssetsController_initializeNativeAssetsMap = function _AssetsController_initializeNativeAssetsMap(queryApiClient) {
960
+ queryApiClient.queryClient
961
+ .fetchQuery({
962
+ queryKey: NATIVE_ASSETS_QUERY_KEY,
963
+ queryFn: utils_2.buildNativeAssetsFromApi,
964
+ staleTime: Infinity,
965
+ gcTime: Infinity,
966
+ })
967
+ .catch((error) => {
968
+ // Failure to populate native asset cache is non-fatal;
969
+ // #isNativeAsset falls back to the seed data from buildNativeAssetsFromConstant.
970
+ log('Failed to populate native asset cache, falling back to seed data', error);
971
+ });
972
+ // Seed the cache synchronously so that synchronous consumers (e.g.
973
+ // #isNativeAsset, #resolveNativeAssetIds) have data available immediately.
974
+ // When fetchQuery resolves (currently instant, future: API), it overwrites
975
+ // this with potentially fresher data.
976
+ const initialNativeAssetMap = (0, utils_2.buildNativeAssetsFromConstant)();
977
+ queryApiClient.setCachedData(NATIVE_ASSETS_QUERY_KEY, initialNativeAssetMap);
910
978
  }, _AssetsController_initializeState = function _AssetsController_initializeState() {
911
979
  const { enabledNetworkMap } = this.messenger.call('NetworkEnablementController:getState');
912
980
  __classPrivateFieldSet(this, _AssetsController_enabledChains, __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_extractEnabledChains).call(this, enabledNetworkMap), "f");
@@ -1135,20 +1203,53 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1135
1203
  account_count: request.accountsWithSupportedChains.length,
1136
1204
  });
1137
1205
  }
1138
- // Emit error traces for failed middlewares
1206
+ // Failed middlewares: Issues (optional) + perf/Dashboard spans
1139
1207
  if (middlewareErrors.length > 0) {
1208
+ const failedSources = middlewareErrors.join(',');
1209
+ const assetsError = new errors_1.AssetsDataSourceError({
1210
+ failedSources,
1211
+ errorCount: middlewareErrors.length,
1212
+ chainCount: request.chainIds.length,
1213
+ });
1214
+ try {
1215
+ __classPrivateFieldGet(this, _AssetsController_captureException, "f")?.call(this, assetsError);
1216
+ }
1217
+ catch {
1218
+ // Never let telemetry throw.
1219
+ }
1140
1220
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_emitTrace).call(this, TRACE_DATA_SOURCE_ERROR, {
1141
- failed_sources: middlewareErrors.join(','),
1221
+ failed_sources: failedSources,
1142
1222
  error_count: middlewareErrors.length,
1143
1223
  chain_count: request.chainIds.length,
1224
+ }, {
1225
+ controller: 'AssetsController',
1226
+ severity: 'error',
1227
+ error_type: assetsError.name,
1144
1228
  });
1145
1229
  }
1146
1230
  return { response: result.response, durationByDataSource };
1231
+ }, _AssetsController_getNativeAssetMap = function _AssetsController_getNativeAssetMap() {
1232
+ return (__classPrivateFieldGet(this, _AssetsController_queryApiClient, "f").getCachedData(NATIVE_ASSETS_QUERY_KEY) ?? {});
1233
+ }, _AssetsController_isNativeAsset = function _AssetsController_isNativeAsset(assetId) {
1234
+ const parsed = (0, utils_1.parseCaipAssetType)(assetId);
1235
+ if (parsed.assetNamespace === 'slip44') {
1236
+ return true;
1237
+ }
1238
+ const lower = assetId.toLowerCase();
1239
+ const isInNativeAssetMap = Object.values(__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetMap).call(this)).some((id) => id.toLowerCase() === lower);
1240
+ if (isInNativeAssetMap) {
1241
+ return true;
1242
+ }
1243
+ if (parsed.assetNamespace === 'erc20' &&
1244
+ parsed.assetReference === constants_1.ZERO_ADDRESS) {
1245
+ return true;
1246
+ }
1247
+ return false;
1147
1248
  }, _AssetsController_resolveNativeAssetIds = function _AssetsController_resolveNativeAssetIds(chains) {
1148
- const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
1249
+ const nativeAssetMap = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getNativeAssetMap).call(this);
1149
1250
  const ids = [];
1150
1251
  for (const chainId of chains) {
1151
- const nativeId = nativeAssetIdentifiers?.[chainId];
1252
+ const nativeId = nativeAssetMap[chainId];
1152
1253
  if (nativeId) {
1153
1254
  ids.push(nativeId);
1154
1255
  }
@@ -1366,7 +1467,7 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1366
1467
  }
1367
1468
  const assetChainId = extractChainId(typedAssetId);
1368
1469
  // Skip native tokens on Tempo networks
1369
- if (__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_shouldHideNativeToken).call(this, assetChainId, typedAssetId, metadata)) {
1470
+ if (__classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_shouldHideNativeToken).call(this, assetChainId, metadata)) {
1370
1471
  continue;
1371
1472
  }
1372
1473
  if (!chainIdSet.has(assetChainId)) {
@@ -1402,14 +1503,12 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1402
1503
  }
1403
1504
  }
1404
1505
  return result;
1405
- }, _AssetsController_shouldHideNativeToken = function _AssetsController_shouldHideNativeToken(chainId, assetId, metadata) {
1506
+ }, _AssetsController_shouldHideNativeToken = function _AssetsController_shouldHideNativeToken(chainId, metadata) {
1406
1507
  // Check if it's a chain that should skip native tokens
1407
1508
  if (!controller_utils_1.CHAIN_IDS_WITH_NO_NATIVE_TOKEN.includes(chainId)) {
1408
1509
  return false;
1409
1510
  }
1410
- // Check if it's a native token (either by metadata type or assetId format)
1411
- const isNative = metadata.type === 'native' || assetId.includes('/slip44:');
1412
- return isNative;
1511
+ return metadata.type === 'native';
1413
1512
  }, _AssetsController_tokenStandardToAssetType = function _AssetsController_tokenStandardToAssetType(tokenStandard) {
1414
1513
  switch (tokenStandard) {
1415
1514
  case 'native':
@@ -1467,12 +1566,20 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1467
1566
  ];
1468
1567
  const subscriptionKeys = [...__classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").keys()];
1469
1568
  for (const subscriptionKey of subscriptionKeys) {
1470
- if (subscriptionKey.startsWith('ds:')) {
1471
- const sourceId = subscriptionKey.slice(3);
1472
- const source = allSources.find((ds) => ds.getName() === sourceId);
1473
- if (source) {
1474
- __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
1475
- }
1569
+ if (!subscriptionKey.startsWith('ds:')) {
1570
+ continue;
1571
+ }
1572
+ // Subscription keys take the form `ds:<SourceName>` for the regular
1573
+ // subscription or `ds:<SourceName>:<suffix>` for supplemental
1574
+ // subscriptions (e.g. `ds:RpcDataSource:custom`). Split on `:` and
1575
+ // pick the source-name segment so both shapes resolve correctly.
1576
+ const [, sourceId] = subscriptionKey.split(':');
1577
+ const source = allSources.find((ds) => ds.getName() === sourceId);
1578
+ if (source) {
1579
+ // Unsubscribe by the actual key — `#unsubscribeDataSource` only
1580
+ // knows the regular `ds:<SourceName>` shape and would miss
1581
+ // supplemental subscriptions, leaking their polling timers.
1582
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeBySubscriptionKey).call(this, source, subscriptionKey);
1476
1583
  }
1477
1584
  }
1478
1585
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
@@ -1495,6 +1602,7 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1495
1602
  const balanceDataSources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
1496
1603
  ? __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_allBalanceDataSources_get)
1497
1604
  : [__classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")];
1605
+ let rpcAssignedChains = new Set();
1498
1606
  for (const source of balanceDataSources) {
1499
1607
  const availableChains = new Set(source.getActiveChainsSync());
1500
1608
  const assignedChains = [];
@@ -1508,6 +1616,9 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1508
1616
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeDataSource).call(this, source);
1509
1617
  continue;
1510
1618
  }
1619
+ if (source === __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f")) {
1620
+ rpcAssignedChains = new Set(assignedChains);
1621
+ }
1511
1622
  const seenIds = new Set();
1512
1623
  const accountsForSource = assignedChains
1513
1624
  .flatMap((chainId) => chainToAccounts.get(chainId) ?? [])
@@ -1516,6 +1627,67 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1516
1627
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, source, accountsForSource, assignedChains);
1517
1628
  }
1518
1629
  }
1630
+ // Supplemental RPC subscription for customAssets on chains another data
1631
+ // source claimed during regular handoff. RPC is the sole balance fetcher
1632
+ // for customAssets, so we must always poll them — even when (e.g.)
1633
+ // AccountsApi is already covering the chain for normal balances. The
1634
+ // supplemental subscription runs in `customAssetsOnly` mode so it does
1635
+ // NOT double-poll the regular tracked balances.
1636
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeRpcCustomAssetsSupplement).call(this, accounts, chainToAccounts, rpcAssignedChains);
1637
+ }, _AssetsController_subscribeRpcCustomAssetsSupplement = function _AssetsController_subscribeRpcCustomAssetsSupplement(accounts, chainToAccounts, rpcAssignedChains) {
1638
+ const rpc = __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f");
1639
+ const rpcAvailableChains = new Set(rpc.getActiveChainsSync());
1640
+ // Collect chains that have customAssets for at least one of the given
1641
+ // accounts and are NOT already covered by the regular RPC subscription.
1642
+ const supplementalChainSet = new Set();
1643
+ const accountsWithCustomAssets = new Set();
1644
+ for (const account of accounts) {
1645
+ const customForAccount = this.state.customAssets[account.id] ?? [];
1646
+ if (customForAccount.length === 0) {
1647
+ continue;
1648
+ }
1649
+ accountsWithCustomAssets.add(account.id);
1650
+ for (const assetId of customForAccount) {
1651
+ let chainId;
1652
+ try {
1653
+ chainId = extractChainId(assetId);
1654
+ }
1655
+ catch {
1656
+ continue;
1657
+ }
1658
+ if (rpcAssignedChains.has(chainId)) {
1659
+ continue;
1660
+ }
1661
+ if (!rpcAvailableChains.has(chainId)) {
1662
+ continue;
1663
+ }
1664
+ if (!chainToAccounts.has(chainId)) {
1665
+ continue;
1666
+ }
1667
+ supplementalChainSet.add(chainId);
1668
+ }
1669
+ }
1670
+ const supplementalKey = `ds:${rpc.getName()}:custom`;
1671
+ if (supplementalChainSet.size === 0) {
1672
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeBySubscriptionKey).call(this, rpc, supplementalKey);
1673
+ return;
1674
+ }
1675
+ const supplementalChains = [...supplementalChainSet];
1676
+ const supplementalAccounts = accounts.filter((account) => accountsWithCustomAssets.has(account.id));
1677
+ if (supplementalAccounts.length === 0) {
1678
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_unsubscribeBySubscriptionKey).call(this, rpc, supplementalKey);
1679
+ return;
1680
+ }
1681
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeDataSource).call(this, rpc, supplementalAccounts, supplementalChains, {
1682
+ subscriptionKey: supplementalKey,
1683
+ customAssetsOnly: true,
1684
+ });
1685
+ }, _AssetsController_unsubscribeBySubscriptionKey = function _AssetsController_unsubscribeBySubscriptionKey(source, subscriptionKey) {
1686
+ const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
1687
+ if (existingSubscription) {
1688
+ source.unsubscribe(subscriptionKey).catch(() => undefined);
1689
+ existingSubscription.unsubscribe();
1690
+ }
1519
1691
  }, _AssetsController_subscribeStakedBalance = function _AssetsController_subscribeStakedBalance(accounts, chainIds) {
1520
1692
  const source = __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f");
1521
1693
  if (!source) {
@@ -1544,9 +1716,9 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1544
1716
  }
1545
1717
  }
1546
1718
  return chainToAccounts;
1547
- }, _AssetsController_subscribeDataSource = function _AssetsController_subscribeDataSource(source, accounts, chains) {
1719
+ }, _AssetsController_subscribeDataSource = function _AssetsController_subscribeDataSource(source, accounts, chains, options = {}) {
1548
1720
  const sourceId = source.getName();
1549
- const subscriptionKey = `ds:${sourceId}`;
1721
+ const subscriptionKey = options.subscriptionKey ?? `ds:${sourceId}`;
1550
1722
  const existingSubscription = __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").get(subscriptionKey);
1551
1723
  const isUpdate = existingSubscription !== undefined;
1552
1724
  log('Subscribe to data source', {
@@ -1555,12 +1727,16 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
1555
1727
  isUpdate,
1556
1728
  accountCount: accounts.length,
1557
1729
  chainCount: chains.length,
1730
+ customAssetsOnly: options.customAssetsOnly === true,
1558
1731
  });
1559
1732
  const subscribeReq = {
1560
1733
  request: __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_buildDataRequest).call(this, accounts, chains, {
1561
1734
  assetTypes: ['fungible'],
1562
1735
  dataTypes: ['balance'],
1563
1736
  updateInterval: __classPrivateFieldGet(this, _AssetsController_defaultUpdateInterval, "f"),
1737
+ ...(options.customAssetsOnly === true
1738
+ ? { customAssetsOnly: true }
1739
+ : {}),
1564
1740
  }),
1565
1741
  subscriptionId: subscriptionKey,
1566
1742
  isUpdate,