@metamask-previews/assets-controller 2.0.2-preview-3d4d0d0ef → 2.0.2-preview-0866a6f

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 (90) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/dist/AssetsController-method-action-types.cjs.map +1 -1
  3. package/dist/AssetsController-method-action-types.d.cts +5 -0
  4. package/dist/AssetsController-method-action-types.d.cts.map +1 -1
  5. package/dist/AssetsController-method-action-types.d.mts +5 -0
  6. package/dist/AssetsController-method-action-types.d.mts.map +1 -1
  7. package/dist/AssetsController-method-action-types.mjs.map +1 -1
  8. package/dist/AssetsController.cjs +148 -29
  9. package/dist/AssetsController.cjs.map +1 -1
  10. package/dist/AssetsController.d.cts +37 -5
  11. package/dist/AssetsController.d.cts.map +1 -1
  12. package/dist/AssetsController.d.mts +37 -5
  13. package/dist/AssetsController.d.mts.map +1 -1
  14. package/dist/AssetsController.mjs +148 -29
  15. package/dist/AssetsController.mjs.map +1 -1
  16. package/dist/data-sources/AccountsApiDataSource.cjs +1 -0
  17. package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -1
  18. package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -1
  19. package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -1
  20. package/dist/data-sources/AccountsApiDataSource.mjs +1 -0
  21. package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -1
  22. package/dist/data-sources/BackendWebsocketDataSource.cjs +16 -4
  23. package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -1
  24. package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -1
  25. package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -1
  26. package/dist/data-sources/BackendWebsocketDataSource.mjs +13 -4
  27. package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -1
  28. package/dist/data-sources/PriceDataSource.cjs +20 -14
  29. package/dist/data-sources/PriceDataSource.cjs.map +1 -1
  30. package/dist/data-sources/PriceDataSource.d.cts +2 -2
  31. package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
  32. package/dist/data-sources/PriceDataSource.d.mts +2 -2
  33. package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
  34. package/dist/data-sources/PriceDataSource.mjs +20 -14
  35. package/dist/data-sources/PriceDataSource.mjs.map +1 -1
  36. package/dist/data-sources/RpcDataSource.cjs +2 -0
  37. package/dist/data-sources/RpcDataSource.cjs.map +1 -1
  38. package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
  39. package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
  40. package/dist/data-sources/RpcDataSource.mjs +2 -0
  41. package/dist/data-sources/RpcDataSource.mjs.map +1 -1
  42. package/dist/data-sources/SnapDataSource.cjs +3 -2
  43. package/dist/data-sources/SnapDataSource.cjs.map +1 -1
  44. package/dist/data-sources/SnapDataSource.d.cts.map +1 -1
  45. package/dist/data-sources/SnapDataSource.d.mts.map +1 -1
  46. package/dist/data-sources/SnapDataSource.mjs +3 -2
  47. package/dist/data-sources/SnapDataSource.mjs.map +1 -1
  48. package/dist/data-sources/TokenDataSource.cjs +1 -0
  49. package/dist/data-sources/TokenDataSource.cjs.map +1 -1
  50. package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
  51. package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
  52. package/dist/data-sources/TokenDataSource.mjs +1 -0
  53. package/dist/data-sources/TokenDataSource.mjs.map +1 -1
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.d.cts +2 -1
  56. package/dist/index.d.cts.map +1 -1
  57. package/dist/index.d.mts +2 -1
  58. package/dist/index.d.mts.map +1 -1
  59. package/dist/index.mjs.map +1 -1
  60. package/dist/middlewares/DetectionMiddleware.cjs +44 -27
  61. package/dist/middlewares/DetectionMiddleware.cjs.map +1 -1
  62. package/dist/middlewares/DetectionMiddleware.d.cts +15 -9
  63. package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -1
  64. package/dist/middlewares/DetectionMiddleware.d.mts +15 -9
  65. package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -1
  66. package/dist/middlewares/DetectionMiddleware.mjs +44 -27
  67. package/dist/middlewares/DetectionMiddleware.mjs.map +1 -1
  68. package/dist/middlewares/ParallelMiddleware.cjs +216 -0
  69. package/dist/middlewares/ParallelMiddleware.cjs.map +1 -0
  70. package/dist/middlewares/ParallelMiddleware.d.cts +45 -0
  71. package/dist/middlewares/ParallelMiddleware.d.cts.map +1 -0
  72. package/dist/middlewares/ParallelMiddleware.d.mts +45 -0
  73. package/dist/middlewares/ParallelMiddleware.d.mts.map +1 -0
  74. package/dist/middlewares/ParallelMiddleware.mjs +214 -0
  75. package/dist/middlewares/ParallelMiddleware.mjs.map +1 -0
  76. package/dist/middlewares/index.cjs +5 -1
  77. package/dist/middlewares/index.cjs.map +1 -1
  78. package/dist/middlewares/index.d.cts +2 -0
  79. package/dist/middlewares/index.d.cts.map +1 -1
  80. package/dist/middlewares/index.d.mts +2 -0
  81. package/dist/middlewares/index.d.mts.map +1 -1
  82. package/dist/middlewares/index.mjs +1 -0
  83. package/dist/middlewares/index.mjs.map +1 -1
  84. package/dist/types.cjs.map +1 -1
  85. package/dist/types.d.cts +16 -0
  86. package/dist/types.d.cts.map +1 -1
  87. package/dist/types.d.mts +16 -0
  88. package/dist/types.d.mts.map +1 -1
  89. package/dist/types.mjs.map +1 -1
  90. package/package.json +6 -5
package/CHANGELOG.md CHANGED
@@ -7,10 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add `PendingTokenMetadata` type and optional `pendingMetadata` parameter to `addCustomAsset(accountId, assetId, pendingMetadata?)`. When provided (e.g. from the extension's pending-tokens flow), token metadata is written to `assetsInfo` immediately so the UI can render the token without waiting for the pipeline ([#8021](https://github.com/MetaMask/core/pull/8021))
13
+ - Add `currentCurrency` state (ISO 4217 code, default `'usd'`) and `setCurrentCurrency(currentCurrency)` to `AssetsController`. Changing the currency updates state and triggers a one-off price refetch so displayed prices use the new currency ([#7991](https://github.com/MetaMask/core/pull/7991))
14
+ - Add support for forcibly updating prices ([#7991](https://github.com/MetaMask/core/pull/7991))
15
+ - Add parallel middlewares in `ParallelMiddleware.ts`: `createParallelBalanceMiddleware` runs balance data sources (Accounts API, Snap, RPC) in parallel with chain partitioning and a fallback round for failed chains; `createParallelMiddleware` runs TokenDataSource and PriceDataSource in parallel (same request, merged response). Both use `mergeDataResponses` and limited concurrency via `p-limit` ([#7950](https://github.com/MetaMask/core/pull/7950))
16
+ - Add `@metamask/client-controller` dependency and subscribe to `ClientController:stateChange`. Asset tracking runs only when the UI is open (ClientController) and the keyring is unlocked (KeyringController), and stops when either the UI closes or the keyring locks (Client + Keyring lifecycle) ([#7950](https://github.com/MetaMask/core/pull/7950))
17
+ - Add full and merge update modes: `DataResponse.updateMode` and type `AssetsUpdateMode` (`'full'` | `'merge'`). Fetch uses `'full'` (response is authoritative for scope; custom assets not in response are preserved). Subscriptions could use `'merge'` or `'full'` depending on data sources. Default is `'merge'` when omitted ([#7950](https://github.com/MetaMask/core/pull/7950))
18
+
10
19
  ### Changed
11
20
 
12
- - Bump `@metamask/transaction-controller` from `^62.17.1` to `^62.18.0` ([#8005](https://github.com/MetaMask/core/pull/8005))
21
+ - Bump `@metamask/transaction-controller` from `^62.17.1` to `^62.19.0` ([#8005](https://github.com/MetaMask/core/pull/8005), [#8031](https://github.com/MetaMask/core/pull/8031))
13
22
  - Bump `@metamask/assets-controllers` from `^100.0.1` to `^100.0.2` ([#8004](https://github.com/MetaMask/core/pull/8004))
23
+ - Bump `@metamask/assets-controllers` from `^100.0.2` to `^100.0.3` ([#8029](https://github.com/MetaMask/core/pull/8029))
24
+
25
+ ### Fixed
26
+
27
+ - Convert WebSocket balance updates in `BackendWebsocketDataSource` from raw smallest-units to human-readable amounts using asset decimals (same behavior as RPC/Accounts API), so `assetsBalance` remains consistent across data sources ([#8032](https://github.com/MetaMask/core/pull/8032))
28
+ - Include all assets from balance and each account's custom assets from state in `detectedAssets`, so prices and metadata are fetched for existing assets and custom tokens (previously only assets without metadata were included, so existing assets did not get prices) ([#8021](https://github.com/MetaMask/core/pull/8021))
29
+ - Request `includeAggregators: true` when fetching token metadata from the v3 assets API so aggregator data is returned and stored in `assetsInfo` ([#8021](https://github.com/MetaMask/core/pull/8021))
14
30
 
15
31
  ## [2.0.2]
16
32
 
@@ -1 +1 @@
1
- {"version":3,"file":"AssetsController-method-action-types.cjs","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { AssetsController } from './AssetsController';\n\nexport type AssetsControllerGetAssetsAction = {\n type: `AssetsController:getAssets`;\n handler: AssetsController['getAssets'];\n};\n\nexport type AssetsControllerGetAssetsBalanceAction = {\n type: `AssetsController:getAssetsBalance`;\n handler: AssetsController['getAssetsBalance'];\n};\n\nexport type AssetsControllerGetAssetMetadataAction = {\n type: `AssetsController:getAssetMetadata`;\n handler: AssetsController['getAssetMetadata'];\n};\n\nexport type AssetsControllerGetAssetsPriceAction = {\n type: `AssetsController:getAssetsPrice`;\n handler: AssetsController['getAssetsPrice'];\n};\n\n/**\n * Add a custom asset for an account.\n * Custom assets are included in subscription and fetch operations.\n * Adding a custom asset also unhides it if it was previously hidden.\n *\n * @param accountId - The account ID to add the custom asset for.\n * @param assetId - The CAIP-19 asset ID to add.\n */\nexport type AssetsControllerAddCustomAssetAction = {\n type: `AssetsController:addCustomAsset`;\n handler: AssetsController['addCustomAsset'];\n};\n\n/**\n * Remove a custom asset from an account.\n *\n * @param accountId - The account ID to remove the custom asset from.\n * @param assetId - The CAIP-19 asset ID to remove.\n */\nexport type AssetsControllerRemoveCustomAssetAction = {\n type: `AssetsController:removeCustomAsset`;\n handler: AssetsController['removeCustomAsset'];\n};\n\n/**\n * Get all custom assets for an account.\n *\n * @param accountId - The account ID to get custom assets for.\n * @returns Array of CAIP-19 asset IDs for the account's custom assets.\n */\nexport type AssetsControllerGetCustomAssetsAction = {\n type: `AssetsController:getCustomAssets`;\n handler: AssetsController['getCustomAssets'];\n};\n\n/**\n * Hide an asset globally.\n * Hidden assets are excluded from the asset list returned by getAssets.\n * The hidden state is stored in assetPreferences.\n *\n * @param assetId - The CAIP-19 asset ID to hide.\n */\nexport type AssetsControllerHideAssetAction = {\n type: `AssetsController:hideAsset`;\n handler: AssetsController['hideAsset'];\n};\n\n/**\n * Unhide an asset globally.\n *\n * @param assetId - The CAIP-19 asset ID to unhide.\n */\nexport type AssetsControllerUnhideAssetAction = {\n type: `AssetsController:unhideAsset`;\n handler: AssetsController['unhideAsset'];\n};\n\n/**\n * Union of all AssetsController action types.\n */\nexport type AssetsControllerMethodActions =\n | AssetsControllerGetAssetsAction\n | AssetsControllerGetAssetsBalanceAction\n | AssetsControllerGetAssetMetadataAction\n | AssetsControllerGetAssetsPriceAction\n | AssetsControllerAddCustomAssetAction\n | AssetsControllerRemoveCustomAssetAction\n | AssetsControllerGetCustomAssetsAction\n | AssetsControllerHideAssetAction\n | AssetsControllerUnhideAssetAction;\n"]}
1
+ {"version":3,"file":"AssetsController-method-action-types.cjs","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { AssetsController } from './AssetsController';\n\nexport type AssetsControllerGetAssetsAction = {\n type: `AssetsController:getAssets`;\n handler: AssetsController['getAssets'];\n};\n\nexport type AssetsControllerGetAssetsBalanceAction = {\n type: `AssetsController:getAssetsBalance`;\n handler: AssetsController['getAssetsBalance'];\n};\n\nexport type AssetsControllerGetAssetMetadataAction = {\n type: `AssetsController:getAssetMetadata`;\n handler: AssetsController['getAssetMetadata'];\n};\n\nexport type AssetsControllerGetAssetsPriceAction = {\n type: `AssetsController:getAssetsPrice`;\n handler: AssetsController['getAssetsPrice'];\n};\n\n/**\n * Add a custom asset for an account.\n * Custom assets are included in subscription and fetch operations.\n * Adding a custom asset also unhides it if it was previously hidden.\n *\n * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens\n * flow), the token metadata is persisted immediately into `assetsInfo` so the\n * UI can render it without waiting for the next pipeline fetch.\n *\n * @param accountId - The account ID to add the custom asset for.\n * @param assetId - The CAIP-19 asset ID to add.\n * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).\n */\nexport type AssetsControllerAddCustomAssetAction = {\n type: `AssetsController:addCustomAsset`;\n handler: AssetsController['addCustomAsset'];\n};\n\n/**\n * Remove a custom asset from an account.\n *\n * @param accountId - The account ID to remove the custom asset from.\n * @param assetId - The CAIP-19 asset ID to remove.\n */\nexport type AssetsControllerRemoveCustomAssetAction = {\n type: `AssetsController:removeCustomAsset`;\n handler: AssetsController['removeCustomAsset'];\n};\n\n/**\n * Get all custom assets for an account.\n *\n * @param accountId - The account ID to get custom assets for.\n * @returns Array of CAIP-19 asset IDs for the account's custom assets.\n */\nexport type AssetsControllerGetCustomAssetsAction = {\n type: `AssetsController:getCustomAssets`;\n handler: AssetsController['getCustomAssets'];\n};\n\n/**\n * Hide an asset globally.\n * Hidden assets are excluded from the asset list returned by getAssets.\n * The hidden state is stored in assetPreferences.\n *\n * @param assetId - The CAIP-19 asset ID to hide.\n */\nexport type AssetsControllerHideAssetAction = {\n type: `AssetsController:hideAsset`;\n handler: AssetsController['hideAsset'];\n};\n\n/**\n * Unhide an asset globally.\n *\n * @param assetId - The CAIP-19 asset ID to unhide.\n */\nexport type AssetsControllerUnhideAssetAction = {\n type: `AssetsController:unhideAsset`;\n handler: AssetsController['unhideAsset'];\n};\n\n/**\n * Union of all AssetsController action types.\n */\nexport type AssetsControllerMethodActions =\n | AssetsControllerGetAssetsAction\n | AssetsControllerGetAssetsBalanceAction\n | AssetsControllerGetAssetMetadataAction\n | AssetsControllerGetAssetsPriceAction\n | AssetsControllerAddCustomAssetAction\n | AssetsControllerRemoveCustomAssetAction\n | AssetsControllerGetCustomAssetsAction\n | AssetsControllerHideAssetAction\n | AssetsControllerUnhideAssetAction;\n"]}
@@ -24,8 +24,13 @@ export type AssetsControllerGetAssetsPriceAction = {
24
24
  * Custom assets are included in subscription and fetch operations.
25
25
  * Adding a custom asset also unhides it if it was previously hidden.
26
26
  *
27
+ * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
28
+ * flow), the token metadata is persisted immediately into `assetsInfo` so the
29
+ * UI can render it without waiting for the next pipeline fetch.
30
+ *
27
31
  * @param accountId - The account ID to add the custom asset for.
28
32
  * @param assetId - The CAIP-19 asset ID to add.
33
+ * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
29
34
  */
30
35
  export type AssetsControllerAddCustomAssetAction = {
31
36
  type: `AssetsController:addCustomAsset`;
@@ -1 +1 @@
1
- {"version":3,"file":"AssetsController-method-action-types.d.cts","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,+BAA2B;AAE3D,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;CAChD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,kCAAkC,CAAC;IACzC,OAAO,EAAE,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;CAC9C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;CAC1C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,+BAA+B,GAC/B,sCAAsC,GACtC,sCAAsC,GACtC,oCAAoC,GACpC,oCAAoC,GACpC,uCAAuC,GACvC,qCAAqC,GACrC,+BAA+B,GAC/B,iCAAiC,CAAC"}
1
+ {"version":3,"file":"AssetsController-method-action-types.d.cts","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,+BAA2B;AAE3D,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;CAChD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,kCAAkC,CAAC;IACzC,OAAO,EAAE,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;CAC9C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;CAC1C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,+BAA+B,GAC/B,sCAAsC,GACtC,sCAAsC,GACtC,oCAAoC,GACpC,oCAAoC,GACpC,uCAAuC,GACvC,qCAAqC,GACrC,+BAA+B,GAC/B,iCAAiC,CAAC"}
@@ -24,8 +24,13 @@ export type AssetsControllerGetAssetsPriceAction = {
24
24
  * Custom assets are included in subscription and fetch operations.
25
25
  * Adding a custom asset also unhides it if it was previously hidden.
26
26
  *
27
+ * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
28
+ * flow), the token metadata is persisted immediately into `assetsInfo` so the
29
+ * UI can render it without waiting for the next pipeline fetch.
30
+ *
27
31
  * @param accountId - The account ID to add the custom asset for.
28
32
  * @param assetId - The CAIP-19 asset ID to add.
33
+ * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
29
34
  */
30
35
  export type AssetsControllerAddCustomAssetAction = {
31
36
  type: `AssetsController:addCustomAsset`;
@@ -1 +1 @@
1
- {"version":3,"file":"AssetsController-method-action-types.d.mts","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,+BAA2B;AAE3D,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;CAChD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,kCAAkC,CAAC;IACzC,OAAO,EAAE,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;CAC9C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;CAC1C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,+BAA+B,GAC/B,sCAAsC,GACtC,sCAAsC,GACtC,oCAAoC,GACpC,oCAAoC,GACpC,uCAAuC,GACvC,qCAAqC,GACrC,+BAA+B,GAC/B,iCAAiC,CAAC"}
1
+ {"version":3,"file":"AssetsController-method-action-types.d.mts","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,+BAA2B;AAE3D,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACnD,IAAI,EAAE,mCAAmC,CAAC;IAC1C,OAAO,EAAE,gBAAgB,CAAC,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,IAAI,EAAE,iCAAiC,CAAC;IACxC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,uCAAuC,GAAG;IACpD,IAAI,EAAE,oCAAoC,CAAC;IAC3C,OAAO,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;CAChD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qCAAqC,GAAG;IAClD,IAAI,EAAE,kCAAkC,CAAC;IACzC,OAAO,EAAE,gBAAgB,CAAC,iBAAiB,CAAC,CAAC;CAC9C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,gBAAgB,CAAC,aAAa,CAAC,CAAC;CAC1C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,+BAA+B,GAC/B,sCAAsC,GACtC,sCAAsC,GACtC,oCAAoC,GACpC,oCAAoC,GACpC,uCAAuC,GACvC,qCAAqC,GACrC,+BAA+B,GAC/B,iCAAiC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetsController-method-action-types.mjs","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { AssetsController } from './AssetsController';\n\nexport type AssetsControllerGetAssetsAction = {\n type: `AssetsController:getAssets`;\n handler: AssetsController['getAssets'];\n};\n\nexport type AssetsControllerGetAssetsBalanceAction = {\n type: `AssetsController:getAssetsBalance`;\n handler: AssetsController['getAssetsBalance'];\n};\n\nexport type AssetsControllerGetAssetMetadataAction = {\n type: `AssetsController:getAssetMetadata`;\n handler: AssetsController['getAssetMetadata'];\n};\n\nexport type AssetsControllerGetAssetsPriceAction = {\n type: `AssetsController:getAssetsPrice`;\n handler: AssetsController['getAssetsPrice'];\n};\n\n/**\n * Add a custom asset for an account.\n * Custom assets are included in subscription and fetch operations.\n * Adding a custom asset also unhides it if it was previously hidden.\n *\n * @param accountId - The account ID to add the custom asset for.\n * @param assetId - The CAIP-19 asset ID to add.\n */\nexport type AssetsControllerAddCustomAssetAction = {\n type: `AssetsController:addCustomAsset`;\n handler: AssetsController['addCustomAsset'];\n};\n\n/**\n * Remove a custom asset from an account.\n *\n * @param accountId - The account ID to remove the custom asset from.\n * @param assetId - The CAIP-19 asset ID to remove.\n */\nexport type AssetsControllerRemoveCustomAssetAction = {\n type: `AssetsController:removeCustomAsset`;\n handler: AssetsController['removeCustomAsset'];\n};\n\n/**\n * Get all custom assets for an account.\n *\n * @param accountId - The account ID to get custom assets for.\n * @returns Array of CAIP-19 asset IDs for the account's custom assets.\n */\nexport type AssetsControllerGetCustomAssetsAction = {\n type: `AssetsController:getCustomAssets`;\n handler: AssetsController['getCustomAssets'];\n};\n\n/**\n * Hide an asset globally.\n * Hidden assets are excluded from the asset list returned by getAssets.\n * The hidden state is stored in assetPreferences.\n *\n * @param assetId - The CAIP-19 asset ID to hide.\n */\nexport type AssetsControllerHideAssetAction = {\n type: `AssetsController:hideAsset`;\n handler: AssetsController['hideAsset'];\n};\n\n/**\n * Unhide an asset globally.\n *\n * @param assetId - The CAIP-19 asset ID to unhide.\n */\nexport type AssetsControllerUnhideAssetAction = {\n type: `AssetsController:unhideAsset`;\n handler: AssetsController['unhideAsset'];\n};\n\n/**\n * Union of all AssetsController action types.\n */\nexport type AssetsControllerMethodActions =\n | AssetsControllerGetAssetsAction\n | AssetsControllerGetAssetsBalanceAction\n | AssetsControllerGetAssetMetadataAction\n | AssetsControllerGetAssetsPriceAction\n | AssetsControllerAddCustomAssetAction\n | AssetsControllerRemoveCustomAssetAction\n | AssetsControllerGetCustomAssetsAction\n | AssetsControllerHideAssetAction\n | AssetsControllerUnhideAssetAction;\n"]}
1
+ {"version":3,"file":"AssetsController-method-action-types.mjs","sourceRoot":"","sources":["../src/AssetsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { AssetsController } from './AssetsController';\n\nexport type AssetsControllerGetAssetsAction = {\n type: `AssetsController:getAssets`;\n handler: AssetsController['getAssets'];\n};\n\nexport type AssetsControllerGetAssetsBalanceAction = {\n type: `AssetsController:getAssetsBalance`;\n handler: AssetsController['getAssetsBalance'];\n};\n\nexport type AssetsControllerGetAssetMetadataAction = {\n type: `AssetsController:getAssetMetadata`;\n handler: AssetsController['getAssetMetadata'];\n};\n\nexport type AssetsControllerGetAssetsPriceAction = {\n type: `AssetsController:getAssetsPrice`;\n handler: AssetsController['getAssetsPrice'];\n};\n\n/**\n * Add a custom asset for an account.\n * Custom assets are included in subscription and fetch operations.\n * Adding a custom asset also unhides it if it was previously hidden.\n *\n * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens\n * flow), the token metadata is persisted immediately into `assetsInfo` so the\n * UI can render it without waiting for the next pipeline fetch.\n *\n * @param accountId - The account ID to add the custom asset for.\n * @param assetId - The CAIP-19 asset ID to add.\n * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).\n */\nexport type AssetsControllerAddCustomAssetAction = {\n type: `AssetsController:addCustomAsset`;\n handler: AssetsController['addCustomAsset'];\n};\n\n/**\n * Remove a custom asset from an account.\n *\n * @param accountId - The account ID to remove the custom asset from.\n * @param assetId - The CAIP-19 asset ID to remove.\n */\nexport type AssetsControllerRemoveCustomAssetAction = {\n type: `AssetsController:removeCustomAsset`;\n handler: AssetsController['removeCustomAsset'];\n};\n\n/**\n * Get all custom assets for an account.\n *\n * @param accountId - The account ID to get custom assets for.\n * @returns Array of CAIP-19 asset IDs for the account's custom assets.\n */\nexport type AssetsControllerGetCustomAssetsAction = {\n type: `AssetsController:getCustomAssets`;\n handler: AssetsController['getCustomAssets'];\n};\n\n/**\n * Hide an asset globally.\n * Hidden assets are excluded from the asset list returned by getAssets.\n * The hidden state is stored in assetPreferences.\n *\n * @param assetId - The CAIP-19 asset ID to hide.\n */\nexport type AssetsControllerHideAssetAction = {\n type: `AssetsController:hideAsset`;\n handler: AssetsController['hideAsset'];\n};\n\n/**\n * Unhide an asset globally.\n *\n * @param assetId - The CAIP-19 asset ID to unhide.\n */\nexport type AssetsControllerUnhideAssetAction = {\n type: `AssetsController:unhideAsset`;\n handler: AssetsController['unhideAsset'];\n};\n\n/**\n * Union of all AssetsController action types.\n */\nexport type AssetsControllerMethodActions =\n | AssetsControllerGetAssetsAction\n | AssetsControllerGetAssetsBalanceAction\n | AssetsControllerGetAssetMetadataAction\n | AssetsControllerGetAssetsPriceAction\n | AssetsControllerAddCustomAssetAction\n | AssetsControllerRemoveCustomAssetAction\n | AssetsControllerGetCustomAssetsAction\n | AssetsControllerHideAssetAction\n | AssetsControllerUnhideAssetAction;\n"]}
@@ -13,10 +13,11 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
13
13
  var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
- var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trackMetaMetricsEvent, _AssetsController_firstInitFetchReported, _AssetsController_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;
16
+ var _AssetsController_instances, _AssetsController_isEnabled, _AssetsController_isBasicFunctionality, _AssetsController_defaultUpdateInterval, _AssetsController_trackMetaMetricsEvent, _AssetsController_firstInitFetchReported, _AssetsController_uiOpen, _AssetsController_keyringUnlocked, _AssetsController_controllerMutex, _AssetsController_activeSubscriptions, _AssetsController_enabledChains, _AssetsController_selectedAccounts_get, _AssetsController_backendWebsocketDataSource, _AssetsController_accountsApiDataSource, _AssetsController_snapDataSource, _AssetsController_rpcDataSource, _AssetsController_stakedBalanceDataSource, _AssetsController_allBalanceDataSources_get, _AssetsController_priceDataSource, _AssetsController_detectionMiddleware, _AssetsController_tokenDataSource, _AssetsController_unsubscribeBasicFunctionality, _AssetsController_initializeState, _AssetsController_extractEnabledChains, _AssetsController_normalizeChainReference, _AssetsController_subscribeToEvents, _AssetsController_updateActive, _AssetsController_registerActionHandlers, _AssetsController_executeMiddlewares, _AssetsController_updateState, _AssetsController_getAssetsFromState, _AssetsController_tokenStandardToAssetType, _AssetsController_start, _AssetsController_stop, _AssetsController_subscribeAssets, _AssetsController_subscribeAssetsBalance, _AssetsController_subscribeStakedBalance, _AssetsController_buildChainToAccountsMap, _AssetsController_subscribeDataSource, _AssetsController_unsubscribeDataSource, _AssetsController_buildDataRequest, _AssetsController_getEnabledChainsForAccount, _AssetsController_handleAccountGroupChanged, _AssetsController_handleEnabledNetworksChanged;
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");
20
+ const client_controller_1 = require("@metamask/client-controller");
20
21
  const utils_1 = require("@metamask/utils");
21
22
  const async_mutex_1 = require("async-mutex");
22
23
  const bignumber_js_1 = __importDefault(require("bignumber.js"));
@@ -30,6 +31,7 @@ const StakedBalanceDataSource_1 = require("./data-sources/StakedBalanceDataSourc
30
31
  const TokenDataSource_1 = require("./data-sources/TokenDataSource.cjs");
31
32
  const logger_1 = require("./logger.cjs");
32
33
  const DetectionMiddleware_1 = require("./middlewares/DetectionMiddleware.cjs");
34
+ const ParallelMiddleware_1 = require("./middlewares/ParallelMiddleware.cjs");
33
35
  const utils_2 = require("./utils.cjs");
34
36
  // ============================================================================
35
37
  // CONTROLLER CONSTANTS
@@ -62,6 +64,7 @@ function getDefaultAssetsControllerState() {
62
64
  assetsPrice: {},
63
65
  customAssets: {},
64
66
  assetPreferences: {},
67
+ selectedCurrency: 'usd',
65
68
  };
66
69
  }
67
70
  exports.getDefaultAssetsControllerState = getDefaultAssetsControllerState;
@@ -99,6 +102,12 @@ const stateMetadata = {
99
102
  includeInDebugSnapshot: false,
100
103
  usedInUi: true,
101
104
  },
105
+ selectedCurrency: {
106
+ persist: true,
107
+ includeInStateLogs: false,
108
+ includeInDebugSnapshot: false,
109
+ usedInUi: true,
110
+ },
102
111
  };
103
112
  // ============================================================================
104
113
  // HELPER FUNCTIONS
@@ -152,6 +161,9 @@ function normalizeResponse(response) {
152
161
  if (response.errors) {
153
162
  normalized.errors = { ...response.errors };
154
163
  }
164
+ if (response.updateMode) {
165
+ normalized.updateMode = response.updateMode;
166
+ }
155
167
  return normalized;
156
168
  }
157
169
  // ============================================================================
@@ -173,8 +185,10 @@ function normalizeResponse(response) {
173
185
  * based on which chains they support. When active chains change, the controller
174
186
  * dynamically adjusts subscriptions.
175
187
  *
176
- * 4. **Keyring Lifecycle**: Listens to KeyringController unlock/lock events to
177
- * start/stop subscriptions when the wallet is unlocked or locked.
188
+ * 4. **Client + Keyring Lifecycle**: Starts subscriptions only when both the UI is
189
+ * open (ClientController) and the wallet is unlocked (KeyringController).
190
+ * Stops when either the UI closes or the keyring locks. See client-controller
191
+ * README for the combined pattern.
178
192
  *
179
193
  * ## Architecture
180
194
  *
@@ -204,6 +218,10 @@ class AssetsController extends base_controller_1.BaseController {
204
218
  _AssetsController_trackMetaMetricsEvent.set(this, void 0);
205
219
  /** Whether we have already reported first init fetch for this session (reset on #stop). */
206
220
  _AssetsController_firstInitFetchReported.set(this, false);
221
+ /** Whether the client (UI) is open. Combined with #keyringUnlocked for #updateActive. */
222
+ _AssetsController_uiOpen.set(this, false);
223
+ /** Whether the keyring is unlocked. Combined with #uiOpen for #updateActive. */
224
+ _AssetsController_keyringUnlocked.set(this, false);
207
225
  _AssetsController_controllerMutex.set(this, new async_mutex_1.Mutex());
208
226
  /**
209
227
  * Active balance subscriptions keyed by account ID.
@@ -260,6 +278,7 @@ class AssetsController extends base_controller_1.BaseController {
260
278
  }), "f");
261
279
  __classPrivateFieldSet(this, _AssetsController_priceDataSource, new PriceDataSource_1.PriceDataSource({
262
280
  queryApiClient,
281
+ getSelectedCurrency: () => this.state.selectedCurrency,
263
282
  ...priceDataSourceConfig,
264
283
  }), "f");
265
284
  __classPrivateFieldSet(this, _AssetsController_detectionMiddleware, new DetectionMiddleware_1.DetectionMiddleware(), "f");
@@ -273,7 +292,7 @@ class AssetsController extends base_controller_1.BaseController {
273
292
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_initializeState).call(this);
274
293
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_subscribeToEvents).call(this);
275
294
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_registerActionHandlers).call(this);
276
- // Subscriptions start only on KeyringController:unlock -> #start(), not here.
295
+ // Subscriptions start only when both UI is open and keyring unlocked -> #updateActive().
277
296
  // Subscribe to basic-functionality changes after construction so a synchronous
278
297
  // onChange during subscribe cannot run before data sources are initialized.
279
298
  if (subscribeToBasicFunctionalityChange) {
@@ -337,6 +356,9 @@ class AssetsController extends base_controller_1.BaseController {
337
356
  const chainIds = options?.chainIds ?? [...__classPrivateFieldGet(this, _AssetsController_enabledChains, "f")];
338
357
  const assetTypes = options?.assetTypes ?? ['fungible'];
339
358
  const dataTypes = options?.dataTypes ?? ['balance', 'metadata', 'price'];
359
+ if (accounts.length === 0 || chainIds.length === 0) {
360
+ return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
361
+ }
340
362
  // Collect custom assets for all requested accounts
341
363
  const customAssets = [];
342
364
  for (const account of accounts) {
@@ -350,16 +372,21 @@ class AssetsController extends base_controller_1.BaseController {
350
372
  dataTypes,
351
373
  customAssets: customAssets.length > 0 ? customAssets : undefined,
352
374
  forceUpdate: true,
375
+ assetsForPriceUpdate: options?.assetsForPriceUpdate,
353
376
  });
354
377
  const sources = __classPrivateFieldGet(this, _AssetsController_isBasicFunctionality, "f").call(this)
355
378
  ? [
356
- __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
357
- __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
358
- __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
359
- __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
379
+ (0, ParallelMiddleware_1.createParallelBalanceMiddleware)([
380
+ __classPrivateFieldGet(this, _AssetsController_accountsApiDataSource, "f"),
381
+ __classPrivateFieldGet(this, _AssetsController_snapDataSource, "f"),
382
+ __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
383
+ __classPrivateFieldGet(this, _AssetsController_stakedBalanceDataSource, "f"),
384
+ ]),
360
385
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
361
- __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
362
- __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
386
+ (0, ParallelMiddleware_1.createParallelMiddleware)([
387
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
388
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
389
+ ]),
363
390
  ]
364
391
  : [
365
392
  __classPrivateFieldGet(this, _AssetsController_rpcDataSource, "f"),
@@ -367,7 +394,7 @@ class AssetsController extends base_controller_1.BaseController {
367
394
  __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
368
395
  ];
369
396
  const { response, durationByDataSource } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, sources, request);
370
- await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, response);
397
+ await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateState).call(this, { ...response, updateMode: 'full' });
371
398
  if (__classPrivateFieldGet(this, _AssetsController_trackMetaMetricsEvent, "f") && !__classPrivateFieldGet(this, _AssetsController_firstInitFetchReported, "f")) {
372
399
  __classPrivateFieldSet(this, _AssetsController_firstInitFetchReported, true, "f");
373
400
  const durationMs = Date.now() - startTime;
@@ -378,7 +405,8 @@ class AssetsController extends base_controller_1.BaseController {
378
405
  });
379
406
  }
380
407
  }
381
- return __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
408
+ const result = __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_getAssetsFromState).call(this, accounts, chainIds, assetTypes);
409
+ return result;
382
410
  }
383
411
  async getAssetsBalance(accounts, options) {
384
412
  // Reuse getAssets with dataTypes: ['balance'] only
@@ -429,10 +457,15 @@ class AssetsController extends base_controller_1.BaseController {
429
457
  * Custom assets are included in subscription and fetch operations.
430
458
  * Adding a custom asset also unhides it if it was previously hidden.
431
459
  *
460
+ * When `pendingMetadata` is provided (e.g. from the extension's pending-tokens
461
+ * flow), the token metadata is persisted immediately into `assetsInfo` so the
462
+ * UI can render it without waiting for the next pipeline fetch.
463
+ *
432
464
  * @param accountId - The account ID to add the custom asset for.
433
465
  * @param assetId - The CAIP-19 asset ID to add.
466
+ * @param pendingMetadata - Optional token metadata from the UI (pendingTokens format).
434
467
  */
435
- async addCustomAsset(accountId, assetId) {
468
+ async addCustomAsset(accountId, assetId, pendingMetadata) {
436
469
  const normalizedAssetId = (0, utils_2.normalizeAssetId)(assetId);
437
470
  log('Adding custom asset', { accountId, assetId: normalizedAssetId });
438
471
  this.update((state) => {
@@ -452,6 +485,28 @@ class AssetsController extends base_controller_1.BaseController {
452
485
  delete state.assetPreferences[normalizedAssetId];
453
486
  }
454
487
  }
488
+ // Persist metadata from the UI so the token is immediately renderable
489
+ if (pendingMetadata) {
490
+ const parsed = (0, utils_1.parseCaipAssetType)(normalizedAssetId);
491
+ let tokenType = 'erc20';
492
+ if (parsed.assetNamespace === 'slip44') {
493
+ tokenType = 'native';
494
+ }
495
+ else if (parsed.assetNamespace === 'spl') {
496
+ tokenType = 'spl';
497
+ }
498
+ const assetMetadata = {
499
+ type: tokenType,
500
+ symbol: pendingMetadata.symbol,
501
+ name: pendingMetadata.name,
502
+ decimals: pendingMetadata.decimals,
503
+ image: pendingMetadata.iconUrl,
504
+ aggregators: pendingMetadata.aggregators,
505
+ occurrences: pendingMetadata.occurrences,
506
+ };
507
+ state.assetsInfo[normalizedAssetId] =
508
+ assetMetadata;
509
+ }
455
510
  });
456
511
  // Fetch data for the newly added custom asset
457
512
  const account = __classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).find((a) => a.id === accountId);
@@ -530,6 +585,34 @@ class AssetsController extends base_controller_1.BaseController {
530
585
  });
531
586
  }
532
587
  // ============================================================================
588
+ // CURRENT CURRENCY MANAGEMENT
589
+ // ============================================================================
590
+ /**
591
+ * Set the current currency.
592
+ *
593
+ * @param selectedCurrency - The ISO 4217 currency code to set.
594
+ */
595
+ setSelectedCurrency(selectedCurrency) {
596
+ const previousCurrency = this.state.selectedCurrency;
597
+ if (previousCurrency === selectedCurrency) {
598
+ return;
599
+ }
600
+ this.update((state) => {
601
+ state.selectedCurrency = selectedCurrency;
602
+ });
603
+ log('Current currency changed', {
604
+ previousCurrency,
605
+ selectedCurrency,
606
+ });
607
+ this.getAssets(__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get), {
608
+ forceUpdate: true,
609
+ dataTypes: ['price'],
610
+ assetsForPriceUpdate: Object.values(this.state.assetsBalance).flatMap((balances) => Object.keys(balances)),
611
+ }).catch((error) => {
612
+ log('Failed to fetch asset prices after current currency change', error);
613
+ });
614
+ }
615
+ // ============================================================================
533
616
  // SUBSCRIPTIONS
534
617
  // ============================================================================
535
618
  /**
@@ -607,9 +690,15 @@ class AssetsController extends base_controller_1.BaseController {
607
690
  hasBalance: Boolean(response.assetsBalance),
608
691
  hasPrice: Boolean(response.assetsPrice),
609
692
  });
610
- // Run through enrichment middlewares (Event Stack: Detection Token Price)
693
+ // Run through enrichment middlewares (Detection, then Token + Price in parallel)
611
694
  // 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 ?? {
695
+ const { response: enrichedResponse } = await __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_executeMiddlewares).call(this, [
696
+ __classPrivateFieldGet(this, _AssetsController_detectionMiddleware, "f"),
697
+ (0, ParallelMiddleware_1.createParallelMiddleware)([
698
+ __classPrivateFieldGet(this, _AssetsController_tokenDataSource, "f"),
699
+ __classPrivateFieldGet(this, _AssetsController_priceDataSource, "f"),
700
+ ]),
701
+ ], request ?? {
613
702
  accountsWithSupportedChains: [],
614
703
  chainIds: [],
615
704
  dataTypes: ['balance', 'metadata', 'price'],
@@ -649,7 +738,7 @@ class AssetsController extends base_controller_1.BaseController {
649
738
  }
650
739
  }
651
740
  exports.AssetsController = AssetsController;
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() {
741
+ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctionality = new WeakMap(), _AssetsController_defaultUpdateInterval = new WeakMap(), _AssetsController_trackMetaMetricsEvent = new WeakMap(), _AssetsController_firstInitFetchReported = new WeakMap(), _AssetsController_uiOpen = new WeakMap(), _AssetsController_keyringUnlocked = new WeakMap(), _AssetsController_controllerMutex = new WeakMap(), _AssetsController_activeSubscriptions = new WeakMap(), _AssetsController_enabledChains = new WeakMap(), _AssetsController_backendWebsocketDataSource = new WeakMap(), _AssetsController_accountsApiDataSource = new WeakMap(), _AssetsController_snapDataSource = new WeakMap(), _AssetsController_rpcDataSource = new WeakMap(), _AssetsController_stakedBalanceDataSource = new WeakMap(), _AssetsController_priceDataSource = new WeakMap(), _AssetsController_detectionMiddleware = new WeakMap(), _AssetsController_tokenDataSource = new WeakMap(), _AssetsController_unsubscribeBasicFunctionality = new WeakMap(), _AssetsController_instances = new WeakSet(), _AssetsController_selectedAccounts_get = function _AssetsController_selectedAccounts_get() {
653
742
  return this.messenger.call('AccountTreeController:getAccountsFromSelectedAccountGroup');
654
743
  }, _AssetsController_allBalanceDataSources_get = function _AssetsController_allBalanceDataSources_get() {
655
744
  return [
@@ -699,9 +788,27 @@ _AssetsController_isEnabled = new WeakMap(), _AssetsController_isBasicFunctional
699
788
  this.messenger.subscribe('NetworkEnablementController:stateChange', ({ enabledNetworkMap }) => {
700
789
  __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_handleEnabledNetworksChanged).call(this, enabledNetworkMap).catch(console.error);
701
790
  });
702
- // Keyring lifecycle: start when unlocked, stop when locked
703
- this.messenger.subscribe('KeyringController:unlock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this));
704
- this.messenger.subscribe('KeyringController:lock', () => __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this));
791
+ // Client + Keyring lifecycle: only run when UI is open AND keyring is unlocked
792
+ this.messenger.subscribe('ClientController:stateChange', (isUiOpen) => {
793
+ __classPrivateFieldSet(this, _AssetsController_uiOpen, isUiOpen, "f");
794
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
795
+ }, client_controller_1.clientControllerSelectors.selectIsUiOpen);
796
+ this.messenger.subscribe('KeyringController:unlock', () => {
797
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, true, "f");
798
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
799
+ });
800
+ this.messenger.subscribe('KeyringController:lock', () => {
801
+ __classPrivateFieldSet(this, _AssetsController_keyringUnlocked, false, "f");
802
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_updateActive).call(this);
803
+ });
804
+ }, _AssetsController_updateActive = function _AssetsController_updateActive() {
805
+ const shouldRun = __classPrivateFieldGet(this, _AssetsController_uiOpen, "f") && __classPrivateFieldGet(this, _AssetsController_keyringUnlocked, "f");
806
+ if (shouldRun) {
807
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_start).call(this);
808
+ }
809
+ else {
810
+ __classPrivateFieldGet(this, _AssetsController_instances, "m", _AssetsController_stop).call(this);
811
+ }
705
812
  }, _AssetsController_registerActionHandlers = function _AssetsController_registerActionHandlers() {
706
813
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
707
814
  }, _AssetsController_executeMiddlewares =
@@ -759,8 +866,8 @@ async function _AssetsController_executeMiddlewares(sources, request, initialRes
759
866
  // STATE MANAGEMENT
760
867
  // ============================================================================
761
868
  async function _AssetsController_updateState(response) {
762
- // Normalize asset IDs (checksum EVM addresses) before storing in state
763
869
  const normalizedResponse = normalizeResponse(response);
870
+ const mode = normalizedResponse.updateMode ?? 'merge';
764
871
  const releaseLock = await __classPrivateFieldGet(this, _AssetsController_controllerMutex, "f").acquire();
765
872
  try {
766
873
  const previousState = this.state;
@@ -786,15 +893,27 @@ async function _AssetsController_updateState(response) {
786
893
  if (normalizedResponse.assetsBalance) {
787
894
  for (const [accountId, accountBalances] of Object.entries(normalizedResponse.assetsBalance)) {
788
895
  const previousBalances = previousState.assetsBalance[accountId] ?? {};
789
- if (!balances[accountId]) {
790
- balances[accountId] = {};
791
- }
792
- for (const [assetId, balance] of Object.entries(accountBalances)) {
896
+ const customAssetIds = state.customAssets[accountId] ?? [];
897
+ // Full: response is authoritative; preserve custom assets not in response. Merge: response overlays previous.
898
+ const effective = mode === 'full'
899
+ ? (() => {
900
+ const next = {
901
+ ...accountBalances,
902
+ };
903
+ for (const customId of customAssetIds) {
904
+ if (!(customId in next)) {
905
+ const prev = previousBalances[customId];
906
+ next[customId] =
907
+ prev ?? { amount: '0' };
908
+ }
909
+ }
910
+ return next;
911
+ })()
912
+ : { ...previousBalances, ...accountBalances };
913
+ for (const [assetId, balance] of Object.entries(effective)) {
793
914
  const previousBalance = previousBalances[assetId];
794
- const balanceData = balance;
795
- const newAmount = balanceData.amount;
915
+ const newAmount = balance.amount;
796
916
  const oldAmount = previousBalance?.amount;
797
- // Track if balance actually changed
798
917
  if (oldAmount !== newAmount) {
799
918
  changedBalances.push({
800
919
  accountId,
@@ -804,7 +923,7 @@ async function _AssetsController_updateState(response) {
804
923
  });
805
924
  }
806
925
  }
807
- Object.assign(balances[accountId], accountBalances);
926
+ balances[accountId] = effective;
808
927
  }
809
928
  }
810
929
  // Update prices in state
@@ -982,7 +1101,7 @@ async function _AssetsController_updateState(response) {
982
1101
  }
983
1102
  __classPrivateFieldGet(this, _AssetsController_activeSubscriptions, "f").clear();
984
1103
  }, _AssetsController_subscribeAssets = function _AssetsController_subscribeAssets() {
985
- if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0) {
1104
+ if (__classPrivateFieldGet(this, _AssetsController_instances, "a", _AssetsController_selectedAccounts_get).length === 0 || __classPrivateFieldGet(this, _AssetsController_enabledChains, "f").size === 0) {
986
1105
  return;
987
1106
  }
988
1107
  // Subscribe to balance updates (batched by data source)