@metamask/assets-controllers 104.0.0 → 104.1.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.
- package/CHANGELOG.md +51 -53
- package/dist/AccountTrackerController.cjs +5 -3
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +5 -3
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.cjs +150 -58
- package/dist/MultichainAssetsController/MultichainAssetsController.cjs.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.d.cts +20 -3
- package/dist/MultichainAssetsController/MultichainAssetsController.d.cts.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.d.mts +20 -3
- package/dist/MultichainAssetsController/MultichainAssetsController.d.mts.map +1 -1
- package/dist/MultichainAssetsController/MultichainAssetsController.mjs +150 -58
- package/dist/MultichainAssetsController/MultichainAssetsController.mjs.map +1 -1
- package/dist/selectors/token-selectors.d.cts +18 -18
- package/dist/selectors/token-selectors.d.mts +18 -18
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [104.1.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `MultichainAssetsController`: periodic Blockaid re-scan of stored SPL-style `token:` assets (default once per day) so tokens that become malicious after a prior scan are dropped; use constructor option `blockaidTokenRescanInterval` (ms), or `0` to disable. ([#8400](https://github.com/MetaMask/core/pull/8400))
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Bump `@metamask/account-tree-controller` from `^7.0.0` to `^7.1.0` ([#8472](https://github.com/MetaMask/core/pull/8472))
|
|
19
|
+
- Bump `@metamask/transaction-controller` from `^64.2.0` to `^64.3.0` ([#8482](https://github.com/MetaMask/core/pull/8482))
|
|
20
|
+
- Bump `@metamask/keyring-api` from `^21.6.0` to `^23.0.1` ([#8464](https://github.com/MetaMask/core/pull/8464))
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- `MultichainAssetsController`: fungible `token:` assets from automatic detection are no longer added when Blockaid bulk scan fails, returns empty, or omits that address (previously fail open); an explicit non-malicious per-token result from `PhishingController:bulkScanTokens` is now required before add. ([#8400](https://github.com/MetaMask/core/pull/8400))
|
|
25
|
+
- Fix `AccountTrackerController` wiping existing balances on other chains when syncing accounts for a chain that has no state entry yet ([#8505](https://github.com/MetaMask/core/pull/8505))
|
|
26
|
+
|
|
10
27
|
## [104.0.0]
|
|
11
28
|
|
|
12
29
|
### Changed
|
|
@@ -205,7 +222,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
205
222
|
### Changed
|
|
206
223
|
|
|
207
224
|
- Bump `@metamask/network-enablement-controller` from `^4.1.2` to `^4.2.0` ([#8107](https://github.com/MetaMask/core/pull/8107))
|
|
208
|
-
- Bump `@metamask/transaction-controller` from `^62.18.0` to `^62.20.0` ([#8031](https://github.com/MetaMask/core/pull/8031) [#8104](https://github.com/MetaMask/core/pull/8104))
|
|
225
|
+
- Bump `@metamask/transaction-controller` from `^62.18.0` to `^62.20.0` ([#8031](https://github.com/MetaMask/core/pull/8031), [#8104](https://github.com/MetaMask/core/pull/8104))
|
|
209
226
|
|
|
210
227
|
### Fixed
|
|
211
228
|
|
|
@@ -280,9 +297,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
280
297
|
|
|
281
298
|
- Bump `@metamask/accounts-controller` from `^35.0.2` to `^36.0.0` ([#7897](https://github.com/MetaMask/core/pull/7897))
|
|
282
299
|
- Bump `@metamask/keyring-api` from `^21.0.0` to `^21.5.0` ([#7857](https://github.com/MetaMask/core/pull/7857))
|
|
283
|
-
- Bump `@metamask/account-tree-controller` from `^4.0.0` to `^4.1.1` ([#7869](https://github.com/MetaMask/core/pull/7869)
|
|
284
|
-
- Bump `@metamask/multichain-account-service` from `^5.1.0` to `^7.0.0` ([#7869](https://github.com/MetaMask/core/pull/7869)
|
|
285
|
-
- Bump `@metamask/transaction-controller` from `^62.15.0` to `^62.17.0` ([#7872](https://github.com/MetaMask/core/pull/7872)
|
|
300
|
+
- Bump `@metamask/account-tree-controller` from `^4.0.0` to `^4.1.1` ([#7869](https://github.com/MetaMask/core/pull/7869), [#7897](https://github.com/MetaMask/core/pull/7897))
|
|
301
|
+
- Bump `@metamask/multichain-account-service` from `^5.1.0` to `^7.0.0` ([#7869](https://github.com/MetaMask/core/pull/7869), [#7897](https://github.com/MetaMask/core/pull/7897))
|
|
302
|
+
- Bump `@metamask/transaction-controller` from `^62.15.0` to `^62.17.0` ([#7872](https://github.com/MetaMask/core/pull/7872), [#7897](https://github.com/MetaMask/core/pull/7897))
|
|
286
303
|
- Bump `@metamask/phishing-controller` from `^16.1.0` to `^16.2.0` ([#7883](https://github.com/MetaMask/core/pull/7883))
|
|
287
304
|
- Optimize Price API performance by deduplicating concurrent API calls ([#7811](https://github.com/MetaMask/core/pull/7811))
|
|
288
305
|
- Add in-flight promise caching for `fetchSupportedNetworks()` to prevent duplicate concurrent requests
|
|
@@ -292,13 +309,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
292
309
|
|
|
293
310
|
### Fixed
|
|
294
311
|
|
|
295
|
-
- Remove `Tempo Testnet` multicall address ([#7858](https://github.com/MetaMask/core/pull/7858))
|
|
312
|
+
- Remove `Tempo Testnet` multicall address. ([#7858](https://github.com/MetaMask/core/pull/7858))
|
|
296
313
|
|
|
297
314
|
## [99.3.0]
|
|
298
315
|
|
|
299
316
|
### Added
|
|
300
317
|
|
|
301
|
-
- Add optional `rwaData` support when adding tokens in `TokensController
|
|
318
|
+
- Add optional `rwaData` support when adding tokens in `TokensController`. ([#7804](https://github.com/MetaMask/core/pull/7804))
|
|
302
319
|
|
|
303
320
|
### Changed
|
|
304
321
|
|
|
@@ -749,7 +766,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
749
766
|
- **BREAKING:** Added constructor argument `tokenPricesService` in `currencyRateController` ([#6863](https://github.com/MetaMask/core/pull/6863))
|
|
750
767
|
- Added `fetchExchangeRates` function to fetch exchange rates from price-api ([#6863](https://github.com/MetaMask/core/pull/6863))
|
|
751
768
|
- Added `ignoreAssets` to allow ignoring assets for non-EVM chains ([#6981](https://github.com/MetaMask/core/pull/6981))
|
|
752
|
-
|
|
753
769
|
- Added `searchTokens` function to search for tokens across multiple networks using CAIP format chain IDs ([#7004](https://github.com/MetaMask/core/pull/7004))
|
|
754
770
|
|
|
755
771
|
### Changed
|
|
@@ -929,8 +945,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
929
945
|
- **BREAKING:** Rename `openSeaEnabled` to `displayNftMedia` in `NftController` ([#4774](https://github.com/MetaMask/core/pull/4774))
|
|
930
946
|
- Ensure compatibility for extension preferences controller state
|
|
931
947
|
- **BREAKING:** Remove `setApiKey` function and `openSeaApiKey` from `NftController` since opensea is not used anymore for NFT data ([#4774](https://github.com/MetaMask/core/pull/4774))
|
|
932
|
-
- Bump `@metamask/phishing-controller` from `^13.1.0` to `^14.0.0` ([#6716](https://github.com/MetaMask/core/pull/6716), [#6629](https://github.com/MetaMask/core/pull/
|
|
933
|
-
- Bump `@metamask/preferences-controller` from `^19.0.0` to `^20.0.0` ([#6716](https://github.com/MetaMask/core/pull/6716), [#6629](https://github.com/MetaMask/core/pull/
|
|
948
|
+
- Bump `@metamask/phishing-controller` from `^13.1.0` to `^14.0.0` ([#6716](https://github.com/MetaMask/core/pull/6716), [#6629](https://github.com/MetaMask/core/pull/6629))
|
|
949
|
+
- Bump `@metamask/preferences-controller` from `^19.0.0` to `^20.0.0` ([#6716](https://github.com/MetaMask/core/pull/6716), [#6629](https://github.com/MetaMask/core/pull/6629))
|
|
934
950
|
|
|
935
951
|
## [76.0.0]
|
|
936
952
|
|
|
@@ -1002,9 +1018,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1002
1018
|
### Fixed
|
|
1003
1019
|
|
|
1004
1020
|
- Fix values returned from multicall fetcher to use the correct BN type, not BigNumber ([#6411](https://github.com/MetaMask/core/pull/6411))
|
|
1005
|
-
|
|
1006
1021
|
- Ensure every access to the state of `AccountTrackerController` is done with a checksumed address ([#6411](https://github.com/MetaMask/core/pull/6411))
|
|
1007
|
-
|
|
1008
1022
|
- Ensure the balance passed to update `AccountTrackerController:updateNativeBalances` is of type `Hex` ([#6411](https://github.com/MetaMask/core/pull/6411))
|
|
1009
1023
|
|
|
1010
1024
|
## [74.3.0]
|
|
@@ -1042,22 +1056,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1042
1056
|
### Changed
|
|
1043
1057
|
|
|
1044
1058
|
- Bump `@metamask/base-controller` from `^8.1.0` to `^8.2.0` ([#6355](https://github.com/MetaMask/core/pull/6355))
|
|
1045
|
-
|
|
1046
1059
|
- Add new `accountId` field to the `Asset` type ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
1047
1060
|
|
|
1048
1061
|
### Fixed
|
|
1049
1062
|
|
|
1050
1063
|
- Uses `InternalAccount['type']` for the `Asset['type']` property ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
1051
|
-
|
|
1052
1064
|
- Ensure that the evm addresses used to fetch balances from AccountTrackerController state is lowercase, in order to account for discrepancies between clients ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
1053
|
-
|
|
1054
1065
|
- Prevents mutation of memoized fields used inside selectors ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
1055
|
-
|
|
1056
1066
|
- Fix duplicate token balance entries caused by case-sensitive address comparison in `TokenBalancesController.updateBalances` ([#6354](https://github.com/MetaMask/core/pull/6354))
|
|
1057
|
-
|
|
1058
1067
|
- Normalize token addresses to proper EIP-55 checksum format before using as object keys to prevent the same token from appearing multiple times with different cases
|
|
1059
1068
|
- Add comprehensive unit tests for token address normalization scenarios
|
|
1060
|
-
|
|
1061
1069
|
- Fix TokenBalancesController timeout handling by replacing `safelyExecuteWithTimeout` with proper `Promise.race` implementation ([#6365](https://github.com/MetaMask/core/pull/6365))
|
|
1062
1070
|
- Replace `safelyExecuteWithTimeout` which was silently swallowing timeout errors with direct `Promise.race` that properly throws
|
|
1063
1071
|
- Reduce RPC timeout from 3 minutes to 15 seconds for better responsiveness and batch size
|
|
@@ -1293,11 +1301,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1293
1301
|
### Added
|
|
1294
1302
|
|
|
1295
1303
|
- **BREAKING:** Add event listener for `AccountsController:accountRemoved` on `TokenBalancesController` to remove token balances for the removed account ([#5726](https://github.com/MetaMask/core/pull/5726))
|
|
1296
|
-
|
|
1297
1304
|
- **BREAKING:** Add event listener for `AccountsController:accountRemoved` on `TokensController` to remove tokens for the removed account ([#5726](https://github.com/MetaMask/core/pull/5726))
|
|
1298
|
-
|
|
1299
1305
|
- **BREAKING:** Add `listAccounts` action to `TokensController` ([#5726](https://github.com/MetaMask/core/pull/5726))
|
|
1300
|
-
|
|
1301
1306
|
- **BREAKING:** Add `listAccounts` action to `TokenBalancesController` ([#5726](https://github.com/MetaMask/core/pull/5726))
|
|
1302
1307
|
|
|
1303
1308
|
### Changed
|
|
@@ -1447,8 +1452,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1447
1452
|
|
|
1448
1453
|
### Fixed
|
|
1449
1454
|
|
|
1450
|
-
- Update token rate request key to handle when new tokens are detected inside the `TokenRatesController` ([#5531](https://github.com/MetaMask/core/pull/
|
|
1451
|
-
- Update `CurrencyRateController` to prevent undefined or empty currencies from being queried ([#5458](https://github.com/MetaMask/core/pull/5458))
|
|
1455
|
+
- Update token rate request key to handle when new tokens are detected inside the `TokenRatesController`) ([#5531](https://github.com/MetaMask/core/pull/5531))
|
|
1456
|
+
- Update `CurrencyRateController` to prevent undefined or empty currencies from being queried) ([#5458](https://github.com/MetaMask/core/pull/5458))
|
|
1452
1457
|
|
|
1453
1458
|
## [55.0.1]
|
|
1454
1459
|
|
|
@@ -1600,9 +1605,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1600
1605
|
- `cockatiel` should still be in the dependency tree because it's now a dependency of `@metamask/controller-utils`
|
|
1601
1606
|
- Re-introduce `@metamask/keyring-api` as a runtime dependency ([#5206](https://github.com/MetaMask/core/pull/5206))
|
|
1602
1607
|
- This was required since the introduction of the `MultichainBalancesController`.
|
|
1603
|
-
- Bump `@metamask/keyring-api` from `^14.0.0` to `^16.1.0
|
|
1604
|
-
- Bump `@metamask/keyring-internal-api` from `^2.0.1` to `^4.0.1
|
|
1605
|
-
- Bump `@metamask/keyring-snap-client` from `^3.0.0` to `^3.0.3
|
|
1608
|
+
- Bump `@metamask/keyring-api` from `^14.0.0` to `^16.1.0`, ([#5190](https://github.com/MetaMask/core/pull/5190), [#5208](https://github.com/MetaMask/core/pull/5208))
|
|
1609
|
+
- Bump `@metamask/keyring-internal-api` from `^2.0.1` to `^4.0.1`, ([#5190](https://github.com/MetaMask/core/pull/5190), [#5208](https://github.com/MetaMask/core/pull/5208))
|
|
1610
|
+
- Bump `@metamask/keyring-snap-client` from `^3.0.0` to `^3.0.3`, ([#5190](https://github.com/MetaMask/core/pull/5190), [#5208](https://github.com/MetaMask/core/pull/5208))
|
|
1606
1611
|
|
|
1607
1612
|
## [46.0.1]
|
|
1608
1613
|
|
|
@@ -1630,7 +1635,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1630
1635
|
### Changed
|
|
1631
1636
|
|
|
1632
1637
|
- **BREAKING:** Bump `@metamask/accounts-controller` peer dependency from `^20.0.0` to `^21.0.0` ([#5140](https://github.com/MetaMask/core/pull/5140))
|
|
1633
|
-
- Bump `@metamask/base-controller` from `^7.0.0` to `^7.1.1
|
|
1638
|
+
- Bump `@metamask/base-controller` from `^7.0.0` to `^7.1.1`, ([#5079](https://github.com/MetaMask/core/pull/5079), [#5135](https://github.com/MetaMask/core/pull/5135))
|
|
1634
1639
|
- Bump `@metamask/keyring-api` from `^12.0.0` to `^13.0.0` ([#5066](https://github.com/MetaMask/core/pull/5066))
|
|
1635
1640
|
- Bump `@metamask/utils` to `^11.0.1` ([#5080](https://github.com/MetaMask/core/pull/5080))
|
|
1636
1641
|
- Bump `@metamask/rpc-errors` to `^7.0.2` ([#5080](https://github.com/MetaMask/core/pull/5080))
|
|
@@ -1694,9 +1699,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1694
1699
|
|
|
1695
1700
|
### Changed
|
|
1696
1701
|
|
|
1697
|
-
- **BREAKING:** Bump `@metamask/keyring-controller` peer dependency from `^18.0.0` to `^19.0.0` ([#
|
|
1698
|
-
- **BREAKING:** Bump `@metamask/accounts-controller` peer dependency from `^19.0.0` to `^20.0.0` ([#
|
|
1699
|
-
- **BREAKING:** Bump `@metamask/preferences-controller` peer dependency from `^14.0.0` to `^15.0.0` ([#
|
|
1702
|
+
- **BREAKING:** Bump `@metamask/keyring-controller` peer dependency from `^18.0.0` to `^19.0.0` ([#4956](https://github.com/MetaMask/core/pull/4956))
|
|
1703
|
+
- **BREAKING:** Bump `@metamask/accounts-controller` peer dependency from `^19.0.0` to `^20.0.0` ([#4956](https://github.com/MetaMask/core/pull/4956))
|
|
1704
|
+
- **BREAKING:** Bump `@metamask/preferences-controller` peer dependency from `^14.0.0` to `^15.0.0` ([#4956](https://github.com/MetaMask/core/pull/4956))
|
|
1700
1705
|
|
|
1701
1706
|
## [44.1.0]
|
|
1702
1707
|
|
|
@@ -1709,7 +1714,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1709
1714
|
### Changed
|
|
1710
1715
|
|
|
1711
1716
|
- Fixes an issue where the token detection was unnecessarily falling back to an RPC approach, causing redundant detections. ([#4928](https://github.com/MetaMask/core/pull/4928))
|
|
1712
|
-
|
|
1713
1717
|
- Fixes an issue where `TokensController.addTokens` was not respecting the network client id passed to it. ([#4940](https://github.com/MetaMask/core/pull/4940))
|
|
1714
1718
|
|
|
1715
1719
|
## [44.0.0]
|
|
@@ -1717,13 +1721,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1717
1721
|
### Changed
|
|
1718
1722
|
|
|
1719
1723
|
- **BREAKING**: The `TokenBalancesController` state is now across all chains and accounts under the field `tokenBalances`, as a mapping from account address -> chain id -> token address -> balance. ([#4782](https://github.com/MetaMask/core/pull/4782))
|
|
1720
|
-
|
|
1721
1724
|
- **BREAKING**: The `TokenBalancesController` now extends `StaticIntervalPollingController`, and the new polling API `startPolling` must be used to initiate polling (`startPolling`, `stopPollingByPollingToken`). ([#4782](https://github.com/MetaMask/core/pull/4782))
|
|
1722
|
-
|
|
1723
1725
|
- **BREAKING**: `TokenBalancesController` now requires subscriptions to the `PreferencesController:stateChange` and `NetworkController:stateChange` events. And access to the `NetworkController:getNetworkClientById`, `NetworkController:getState`, `TokensController:getState`, and `PreferencesController:getState` actions. ([#4782](https://github.com/MetaMask/core/pull/4782))
|
|
1724
|
-
|
|
1725
1726
|
- **BREAKING**: `TokensController` requires a subscription to the `NetworkController:stateChange` event. It now now removes state for chain IDs when their network is removed. ([#4782](https://github.com/MetaMask/core/pull/4782))
|
|
1726
|
-
|
|
1727
1727
|
- `TokenRatesController` now removes state for chain IDs when their network is removed. ([#4782](https://github.com/MetaMask/core/pull/4782))
|
|
1728
1728
|
|
|
1729
1729
|
## [43.1.1]
|
|
@@ -1817,7 +1817,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1817
1817
|
### Changed
|
|
1818
1818
|
|
|
1819
1819
|
- Parallelization of detected tokens with balance ([#4697](https://github.com/MetaMask/core/pull/4697))
|
|
1820
|
-
- Bump accounts related packages ([#4713](https://github.com/MetaMask/core/pull/4713)
|
|
1820
|
+
- Bump accounts related packages, ([#4713](https://github.com/MetaMask/core/pull/4713), [#4728](https://github.com/MetaMask/core/pull/4728))
|
|
1821
1821
|
- Those packages are now built slightly differently and are part of the [accounts monorepo](https://github.com/MetaMask/accounts).
|
|
1822
1822
|
- Bump `@metamask/keyring-api` from `^8.1.0` to `^8.1.4`
|
|
1823
1823
|
|
|
@@ -1833,7 +1833,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1833
1833
|
["Are the Types Wrong?"](https://arethetypeswrong.github.io/) tool as
|
|
1834
1834
|
["masquerading as CJS"](https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md).
|
|
1835
1835
|
All of the ATTW checks now pass.
|
|
1836
|
-
- Remove chunk files ([#4648](https://github.com/MetaMask/core/pull/4648))
|
|
1836
|
+
- Remove chunk files. ([#4648](https://github.com/MetaMask/core/pull/4648))
|
|
1837
1837
|
- Previously, the build tool we used to generate JavaScript files extracted
|
|
1838
1838
|
common code to "chunk" files. While this was intended to make this package
|
|
1839
1839
|
more tree-shakeable, it also made debugging more difficult for our
|
|
@@ -2210,7 +2210,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2210
2210
|
### Added
|
|
2211
2211
|
|
|
2212
2212
|
- `CodefiTokenPricesServiceV2` exports `SUPPORTED_CHAIN_IDS`, an array of chain IDs supported by Codefi Price API V2. ([#4079](https://github.com/MetaMask/core/pull/4079))
|
|
2213
|
-
|
|
2214
2213
|
- Added `tokenURI` key to `compareNftMetadata` function to compare nft metadata entries with. ([#3856](https://github.com/MetaMask/core/pull/3856))
|
|
2215
2214
|
|
|
2216
2215
|
## [27.1.0]
|
|
@@ -2249,15 +2248,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2249
2248
|
|
|
2250
2249
|
### Added
|
|
2251
2250
|
|
|
2252
|
-
- **BREAKING:** `TokenDetectionController` newly subscribes to the `PreferencesController:stateChange`, `AccountsController:selectedAccountChange`, `KeyringController:lock`, and `KeyringController:unlock` events, and allows messenger actions `AccountsController:getSelectedAccount`, `NetworkController:getNetworkClientById`, `NetworkController:getNetworkConfigurationByNetworkClientId`, `NetworkController:getState`, `KeyringController:getState`, `PreferencesController:getState`, `TokenListController:getState`, `TokensController:getState`, and `TokensController:addDetectedTokens` ([#3775](https://github.com/MetaMask/core/pull/3775
|
|
2253
|
-
- `TokensController` now exports `TokensControllerActions`, `TokensControllerGetStateAction`, `TokensControllerAddDetectedTokensAction`, `TokensControllerEvents`, and `TokensControllerStateChangeEvent` ([#3690](https://github.com/MetaMask/core/pull/3690
|
|
2251
|
+
- **BREAKING:** `TokenDetectionController` newly subscribes to the `PreferencesController:stateChange`, `AccountsController:selectedAccountChange`, `KeyringController:lock`, and `KeyringController:unlock` events, and allows messenger actions `AccountsController:getSelectedAccount`, `NetworkController:getNetworkClientById`, `NetworkController:getNetworkConfigurationByNetworkClientId`, `NetworkController:getState`, `KeyringController:getState`, `PreferencesController:getState`, `TokenListController:getState`, `TokensController:getState`, and `TokensController:addDetectedTokens` ([#3775](https://github.com/MetaMask/core/pull/3775), [#3923](https://github.com/MetaMask/core/pull/3923), [#3938](https://github.com/MetaMask/core/pull/3938))
|
|
2252
|
+
- `TokensController` now exports `TokensControllerActions`, `TokensControllerGetStateAction`, `TokensControllerAddDetectedTokensAction`, `TokensControllerEvents`, and `TokensControllerStateChangeEvent` ([#3690](https://github.com/MetaMask/core/pull/3690))
|
|
2254
2253
|
|
|
2255
2254
|
### Changed
|
|
2256
2255
|
|
|
2257
|
-
- **BREAKING:** Add `@metamask/accounts-controller` `^11.0.0` as dependency and peer dependency ([#3775](https://github.com/MetaMask/core/pull/3775
|
|
2256
|
+
- **BREAKING:** Add `@metamask/accounts-controller` `^11.0.0` as dependency and peer dependency ([#3775](https://github.com/MetaMask/core/pull/3775), [#4007](https://github.com/MetaMask/core/pull/4007))
|
|
2258
2257
|
- **BREAKING:** Add `@metamask/keyring-controller` `^13.0.0` as dependency and peer dependency ([#3775](https://github.com/MetaMask/core/pull/3775), [#4007](https://github.com/MetaMask/core/pull/4007))
|
|
2259
2258
|
- **BREAKING:** Bump `@metamask/preferences-controller` dependency and peer dependency to `^8.0.0` ([#4007](https://github.com/MetaMask/core/pull/4007))
|
|
2260
|
-
- **BREAKING:** `TokenDetectionController` is merged with `DetectTokensController` from the `metamask-extension` repo ([#3775](https://github.com/MetaMask/core/pull/3775
|
|
2259
|
+
- **BREAKING:** `TokenDetectionController` is merged with `DetectTokensController` from the `metamask-extension` repo, ([#3775](https://github.com/MetaMask/core/pull/3775), [#3923](https://github.com/MetaMask/core/pull/3923), [#3938](https://github.com/MetaMask/core/pull/3938))
|
|
2261
2260
|
- **BREAKING:** `TokenDetectionController` now resets its polling interval to the default value of 3 minutes when token detection is triggered by external controller events `KeyringController:unlock`, `TokenListController:stateChange`, `PreferencesController:stateChange`, `AccountsController:selectedAccountChange`.
|
|
2262
2261
|
- **BREAKING:** `TokenDetectionController` now refetches tokens on `NetworkController:networkDidChange` if the `networkClientId` is changed instead of `chainId`.
|
|
2263
2262
|
- **BREAKING:** `TokenDetectionController` cannot initiate polling or token detection if `KeyringController` state is locked.
|
|
@@ -2281,11 +2280,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2281
2280
|
|
|
2282
2281
|
### Removed
|
|
2283
2282
|
|
|
2284
|
-
- **BREAKING:** `TokenDetectionController` constructor no longer accepts options `networkClientId`, `onPreferencesStateChange`, `getPreferencesState`, `getTokensState`, or `addDetectedTokens` ([#3690](https://github.com/MetaMask/core/pull/3690
|
|
2285
|
-
- **BREAKING:** `TokenDetectionController` no longer allows the `NetworkController:stateChange` event. ([#3775](https://github.com/MetaMask/core/pull/3775
|
|
2283
|
+
- **BREAKING:** `TokenDetectionController` constructor no longer accepts options `networkClientId`, `onPreferencesStateChange`, `getPreferencesState`, `getTokensState`, or `addDetectedTokens` ([#3690](https://github.com/MetaMask/core/pull/3690), [#3775](https://github.com/MetaMask/core/pull/3775), [#3938](https://github.com/MetaMask/core/pull/3938))
|
|
2284
|
+
- **BREAKING:** `TokenDetectionController` no longer allows the `NetworkController:stateChange` event. ([#3775](https://github.com/MetaMask/core/pull/3775))
|
|
2286
2285
|
- The `NetworkController:networkDidChange` event can be used instead.
|
|
2287
|
-
- **BREAKING:** `TokenDetectionController` constructor no longer accepts options `networkClientId`, `onPreferencesStateChange`, `getPreferencesState`, `getTokensState`, or `addDetectedTokens` ([#3690](https://github.com/MetaMask/core/pull/3690
|
|
2288
|
-
- **BREAKING:** `TokenBalancesController` constructor no longer accepts options `onTokensStateChange`, `getSelectedAddress` ([#3690](https://github.com/MetaMask/core/pull/3690
|
|
2286
|
+
- **BREAKING:** `TokenDetectionController` constructor no longer accepts options `networkClientId`, `onPreferencesStateChange`, `getPreferencesState`, `getTokensState`, or `addDetectedTokens` ([#3690](https://github.com/MetaMask/core/pull/3690), [#3775](https://github.com/MetaMask/core/pull/3775), [#3938](https://github.com/MetaMask/core/pull/3938))
|
|
2287
|
+
- **BREAKING:** `TokenBalancesController` constructor no longer accepts options `onTokensStateChange`, `getSelectedAddress` ([#3690](https://github.com/MetaMask/core/pull/3690))
|
|
2289
2288
|
|
|
2290
2289
|
### Fixed
|
|
2291
2290
|
|
|
@@ -2343,9 +2342,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2343
2342
|
- Add `onBreak` handler to `CodefiTokenPricesServiceV2` ([#3677](https://github.com/MetaMask/core/pull/3677))
|
|
2344
2343
|
- This allows listening for "circuit breaks", which can indicate an outage. Useful for metrics.
|
|
2345
2344
|
- Add `fetchTokenContractExchangeRates` utility method ([#3657](https://github.com/MetaMask/core/pull/3657))
|
|
2346
|
-
- `TokenListController` now exports a `TokenListControllerMessenger` type ([#3609](https://github.com/MetaMask/core/pull/3609))
|
|
2347
|
-
- `TokenDetectionController` exports types `TokenDetectionControllerMessenger`, `TokenDetectionControllerActions`, `TokenDetectionControllerGetStateAction`, `TokenDetectionControllerEvents`, `TokenDetectionControllerStateChangeEvent
|
|
2348
|
-
- Add `enable` and `disable` methods to `TokenDetectionController`, which control whether the controller is able to make polling requests or all of its network calls are blocked
|
|
2345
|
+
- `TokenListController` now exports a `TokenListControllerMessenger` type. ([#3609](https://github.com/MetaMask/core/pull/3609))
|
|
2346
|
+
- `TokenDetectionController` exports types `TokenDetectionControllerMessenger`, `TokenDetectionControllerActions`, `TokenDetectionControllerGetStateAction`, `TokenDetectionControllerEvents`, `TokenDetectionControllerStateChangeEvent`. ([#3609](https://github.com/MetaMask/core/pull/3609))
|
|
2347
|
+
- Add `enable` and `disable` methods to `TokenDetectionController`, which control whether the controller is able to make polling requests or all of its network calls are blocked.. ([#3609](https://github.com/MetaMask/core/pull/3609))
|
|
2349
2348
|
- Note that if the controller is initiated without the `disabled` constructor option set to `false`, the `enable` method will need to be called before the controller can make polling requests in response to subscribed events.
|
|
2350
2349
|
|
|
2351
2350
|
### Changed
|
|
@@ -2354,7 +2353,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2354
2353
|
- **BREAKING:** Bump `@metamask/network-controller` dependency and peer dependency from `^17.0.0` to `^17.1.0` ([#3695](https://github.com/MetaMask/core/pull/3695))
|
|
2355
2354
|
- **BREAKING:** Bump `@metamask/preferences-controller` dependency and peer dependency from `^5.0.0` to `^5.0.1` ([#3695](https://github.com/MetaMask/core/pull/3695))
|
|
2356
2355
|
- **BREAKING:** Update `OpenSeaV2Contract` type, renaming `supply` to `total_supply` ([#3692](https://github.com/MetaMask/core/pull/3692))
|
|
2357
|
-
- **BREAKING:** `TokenDetectionController` is upgraded to extend `BaseControllerV2` and `StaticIntervalPollingController
|
|
2356
|
+
- **BREAKING:** `TokenDetectionController` is upgraded to extend `BaseControllerV2` and `StaticIntervalPollingController`. ([#3609](https://github.com/MetaMask/core/pull/3609))
|
|
2358
2357
|
- The constructor now expects an options object as its only argument, with required properties `messenger`, `networkClientId`, required callbacks `onPreferencesStateChange`, `getBalancesInSingleCall`, `addDetectedTokens`, `getTokenState`, `getPreferencesState`, and optional properties `disabled`, `interval`, `selectedAddress`.
|
|
2359
2358
|
- Bump `@metamask/base-controller` to `^4.0.1` ([#3695](https://github.com/MetaMask/core/pull/3695))
|
|
2360
2359
|
- Bump `@metamask/polling-controller` to `^4.0.0` ([#3695](https://github.com/MetaMask/core/pull/3695))
|
|
@@ -2380,7 +2379,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2380
2379
|
|
|
2381
2380
|
### Added
|
|
2382
2381
|
|
|
2383
|
-
- Add `CodefiTokenPricesServiceV2` ([#3600](https://github.com/MetaMask/core/pull/3600), [#3655](https://github.com/MetaMask/core/pull/3655)
|
|
2382
|
+
- Add `CodefiTokenPricesServiceV2` ([#3600](https://github.com/MetaMask/core/pull/3600), [#3655](https://github.com/MetaMask/core/pull/3655))
|
|
2384
2383
|
- This class can be used for the new `tokenPricesService` argument for TokenRatesController. It uses a MetaMask API to fetch prices for tokens instead of CoinGecko.
|
|
2385
2384
|
- The `CodefiTokenPricesServiceV2` will retry if the token price update fails
|
|
2386
2385
|
- We retry each request up to 3 times using a randomized exponential backoff strategy
|
|
@@ -2923,9 +2922,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2923
2922
|
### Added
|
|
2924
2923
|
|
|
2925
2924
|
- Initial release
|
|
2926
|
-
|
|
2927
2925
|
- As a result of converting our shared controllers repo into a monorepo ([#831](https://github.com/MetaMask/core/pull/831)), we've created this package from select parts of [`@metamask/controllers` v33.0.0](https://github.com/MetaMask/core/tree/v33.0.0), namely:
|
|
2928
|
-
|
|
2929
2926
|
- Everything in `src/assets`
|
|
2930
2927
|
- Asset-related functions from `src/util.ts` and accompanying tests
|
|
2931
2928
|
|
|
@@ -2935,7 +2932,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
2935
2932
|
|
|
2936
2933
|
- Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
|
|
2937
2934
|
|
|
2938
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@104.
|
|
2935
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@104.1.0...HEAD
|
|
2936
|
+
[104.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@104.0.0...@metamask/assets-controllers@104.1.0
|
|
2939
2937
|
[104.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@103.1.1...@metamask/assets-controllers@104.0.0
|
|
2940
2938
|
[103.1.1]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@103.1.0...@metamask/assets-controllers@103.1.1
|
|
2941
2939
|
[103.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@103.0.0...@metamask/assets-controllers@103.1.0
|
|
@@ -424,9 +424,11 @@ _AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerControlle
|
|
|
424
424
|
const oldAddresses = existing.filter((address) => !addresses.includes(address));
|
|
425
425
|
Object.keys(accountsByChainId).forEach((chainId) => {
|
|
426
426
|
newAddresses.forEach((address) => {
|
|
427
|
-
accountsByChainId[chainId][address]
|
|
428
|
-
|
|
429
|
-
|
|
427
|
+
if (!accountsByChainId[chainId][address]) {
|
|
428
|
+
accountsByChainId[chainId][address] = {
|
|
429
|
+
balance: '0x0',
|
|
430
|
+
};
|
|
431
|
+
}
|
|
430
432
|
});
|
|
431
433
|
});
|
|
432
434
|
Object.keys(accountsByChainId).forEach((chainId) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountTrackerController.cjs","sourceRoot":"","sources":["../src/AccountTrackerController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport type {\n AccountsControllerSelectedEvmAccountChangeEvent,\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerListAccountsAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n query,\n safelyExecuteWithTimeout,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport EthQuery from '@metamask/eth-query';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkClient,\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerNetworkAddedEvent,\n} from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerListPopularEvmNetworksAction,\n} from '@metamask/network-enablement-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n TransactionControllerTransactionConfirmedEvent,\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport { assert, KnownCaipNamespace } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { cloneDeep, isEqual } from 'lodash';\n\nimport type { AccountTrackerControllerMethodActions } from './AccountTrackerController-method-action-types';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from './AssetsContractController';\nimport type {\n AssetsContractController,\n StakedBalance,\n} from './AssetsContractController';\nimport { shouldIncludeNativeToken } from './constants';\nimport { AccountsApiBalanceFetcher } from './multi-chain-accounts-service/api-balance-fetcher';\nimport type {\n BalanceFetcher,\n BalanceFetchResult,\n ProcessedBalance,\n} from './multi-chain-accounts-service/api-balance-fetcher';\nimport { RpcBalanceFetcher } from './rpc-service/rpc-balance-fetcher';\n\n/**\n * The name of the {@link AccountTrackerController}.\n */\nconst controllerName = 'AccountTrackerController';\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\n/**\n * Creates an RPC balance fetcher configured for AccountTracker use case.\n * Returns only native balances and staked balances (no token balances).\n *\n * @param getProvider - Function to get Web3Provider for a given chain ID\n * @param getNetworkClient - Function to get NetworkClient for a given chain ID\n * @param includeStakedAssets - Whether to include staked assets in the fetch\n * @returns BalanceFetcher configured to fetch only native and optionally staked balances\n */\nfunction createAccountTrackerRpcBalanceFetcher(\n getProvider: (chainId: Hex) => Web3Provider,\n getNetworkClient: (chainId: Hex) => NetworkClient,\n includeStakedAssets: boolean,\n): BalanceFetcher {\n // Provide empty tokens state to ensure only native and staked balances are fetched\n const getEmptyTokensState = (): {\n allTokens: Record<string, never>;\n allDetectedTokens: Record<string, never>;\n } => ({\n allTokens: {},\n allDetectedTokens: {},\n });\n\n const rpcBalanceFetcher = new RpcBalanceFetcher(\n getProvider,\n getNetworkClient,\n getEmptyTokensState,\n );\n\n // Wrap the RpcBalanceFetcher to filter staked balances when not needed\n return {\n supports(_chainId: ChainIdHex): boolean {\n return rpcBalanceFetcher.supports();\n },\n\n async fetch(\n params: Parameters<BalanceFetcher['fetch']>[0],\n ): Promise<BalanceFetchResult> {\n const result = await rpcBalanceFetcher.fetch(params);\n\n if (!includeStakedAssets) {\n // Filter out staked balances from the results\n return {\n balances: result.balances.filter(\n (balance) => balance.token === ZERO_ADDRESS,\n ),\n unprocessedChainIds: result.unprocessedChainIds,\n };\n }\n\n return result;\n },\n };\n}\n\n/**\n * AccountInformation\n *\n * Account information object\n *\n * balance - Hex string of an account balance in wei\n *\n * stakedBalance - Hex string of an account staked balance in wei\n */\nexport type AccountInformation = {\n balance: string;\n stakedBalance?: string;\n};\n\n/**\n * AccountTrackerControllerState\n *\n * Account tracker controller state\n *\n * accountsByChainId - Map of addresses to account information by chain\n */\nexport type AccountTrackerControllerState = {\n accountsByChainId: Record<string, { [address: string]: AccountInformation }>;\n};\n\nconst accountTrackerMetadata: StateMetadata<AccountTrackerControllerState> = {\n accountsByChainId: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n};\n\n/**\n * The action that can be performed to get the state of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTrackerControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerActions =\n | AccountTrackerControllerGetStateAction\n | AccountTrackerControllerMethodActions;\n\n/**\n * The messenger of the {@link AccountTrackerController} for communication.\n */\nexport type AllowedActions =\n | AccountsControllerListAccountsAction\n | {\n type: 'PreferencesController:getState';\n handler: () => { isMultiAccountBalancesEnabled: boolean };\n }\n | AccountsControllerGetSelectedAccountAction\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkEnablementControllerGetStateAction\n | NetworkEnablementControllerListPopularEvmNetworksAction\n | KeyringControllerGetStateAction;\n\n/**\n * The event that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n AccountTrackerControllerState\n >;\n\n/**\n * The events that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerEvents =\n AccountTrackerControllerStateChangeEvent;\n\n/**\n * The external events available to the {@link AccountTrackerController}.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedEvmAccountChangeEvent\n | TransactionControllerUnapprovedTransactionAddedEvent\n | TransactionControllerTransactionConfirmedEvent\n | NetworkControllerNetworkAddedEvent\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent;\n\n/**\n * The messenger of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerMessenger = Messenger<\n typeof controllerName,\n AccountTrackerControllerActions | AllowedActions,\n AccountTrackerControllerEvents | AllowedEvents\n>;\n\n/** The input to start polling for the {@link AccountTrackerController} */\ntype AccountTrackerPollingInput = {\n networkClientIds: NetworkClientId[];\n queryAllAccounts?: boolean;\n};\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'updateNativeBalances',\n 'updateStakedBalances',\n] as const;\n\n/**\n * Controller that tracks the network balances for all user accounts.\n */\nexport class AccountTrackerController extends StaticIntervalPollingController<AccountTrackerPollingInput>()<\n typeof controllerName,\n AccountTrackerControllerState,\n AccountTrackerControllerMessenger\n> {\n readonly #refreshMutex = new Mutex();\n\n readonly #includeStakedAssets: boolean;\n\n readonly #accountsApiChainIds: () => ChainIdHex[];\n\n readonly #getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n\n readonly #balanceFetchers: BalanceFetcher[];\n\n readonly #fetchingEnabled: () => boolean;\n\n readonly #isOnboarded: () => boolean;\n\n readonly #isHomepageSectionsV1Enabled: () => boolean;\n\n /** Track if the keyring is locked */\n #isLocked = true;\n\n /**\n * Creates an AccountTracker instance.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new account balances.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messenger.\n * @param options.getStakedBalanceForChain - The function to get the staked native asset balance for a chain.\n * @param options.includeStakedAssets - Whether to include staked assets in the account balances.\n * @param options.accountsApiChainIds - Function that returns array of chainIds that should use Accounts-API strategy (if supported by API).\n * @param options.allowExternalServices - Disable external HTTP calls (privacy / offline mode).\n * @param options.fetchingEnabled - Function that returns whether the controller is fetching enabled.\n * @param options.isOnboarded - Whether the user has completed onboarding. If false, balance updates are skipped.\n * @param options.isHomepageSectionsV1Enabled - Whether the homepage sections v1 is enabled.\n */\n constructor({\n interval = 10000,\n state,\n messenger,\n getStakedBalanceForChain,\n includeStakedAssets = false,\n accountsApiChainIds = (): ChainIdHex[] => [],\n allowExternalServices = (): boolean => true,\n fetchingEnabled = (): boolean => true,\n isOnboarded = (): boolean => true,\n isHomepageSectionsV1Enabled = (): boolean => false,\n }: {\n interval?: number;\n state?: Partial<AccountTrackerControllerState>;\n messenger: AccountTrackerControllerMessenger;\n getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n includeStakedAssets?: boolean;\n accountsApiChainIds?: () => ChainIdHex[];\n isHomepageSectionsV1Enabled?: () => boolean;\n allowExternalServices?: () => boolean;\n fetchingEnabled?: () => boolean;\n isOnboarded?: () => boolean;\n }) {\n const { selectedNetworkClientId } = messenger.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n super({\n name: controllerName,\n messenger,\n state: {\n accountsByChainId: {\n [chainId]: {},\n },\n ...state,\n },\n metadata: accountTrackerMetadata,\n });\n this.#getStakedBalanceForChain = getStakedBalanceForChain;\n\n this.#includeStakedAssets = includeStakedAssets;\n this.#accountsApiChainIds = accountsApiChainIds;\n this.#isHomepageSectionsV1Enabled = isHomepageSectionsV1Enabled;\n\n // Initialize balance fetchers - Strategy order: API first, then RPC fallback\n this.#balanceFetchers = [\n ...(accountsApiChainIds().length > 0 && allowExternalServices()\n ? [this.#createAccountsApiFetcher()]\n : []),\n createAccountTrackerRpcBalanceFetcher(\n this.#getProvider,\n this.#getNetworkClient,\n this.#includeStakedAssets,\n ),\n ];\n\n this.#fetchingEnabled = fetchingEnabled;\n this.#isOnboarded = isOnboarded;\n\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n this.#isLocked = !isUnlocked;\n\n this.setIntervalLength(interval);\n\n this.messenger.subscribe(\n 'AccountsController:selectedEvmAccountChange',\n (newAddress, prevAddress) => {\n if (newAddress !== prevAddress) {\n // Making an async call for this new event\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.refresh(this.#getNetworkClientIds());\n }\n },\n (event): string => event.address,\n );\n\n this.messenger.subscribe(\n 'NetworkController:networkAdded',\n (networkConfiguration) => {\n const { networkClientId } =\n networkConfiguration.rpcEndpoints[\n networkConfiguration.defaultRpcEndpointIndex\n ];\n this.refresh([networkClientId]).catch(() => {\n // Silently handle refresh errors\n });\n },\n );\n\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isLocked = false;\n const networkClientIds = this.#getNetworkClientIds();\n this.refresh(networkClientIds).catch((error) => {\n console.error('Error refreshing balances after keyring unlock:', error);\n });\n });\n\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isLocked = true;\n });\n\n this.messenger.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n (transactionMeta: TransactionMeta) => {\n const addresses = [transactionMeta.txParams.from];\n if (transactionMeta.txParams.to) {\n addresses.push(transactionMeta.txParams.to);\n }\n this.refreshAddresses({\n networkClientIds: [transactionMeta.networkClientId],\n addresses,\n }).catch(() => {\n // Silently handle refresh errors\n });\n },\n );\n\n this.messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n (transactionMeta: TransactionMeta) => {\n const addresses = [transactionMeta.txParams.from];\n if (transactionMeta.txParams.to) {\n addresses.push(transactionMeta.txParams.to);\n }\n this.refreshAddresses({\n networkClientIds: [transactionMeta.networkClientId],\n addresses,\n }).catch(() => {\n // Silently handle refresh errors\n });\n },\n );\n\n messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);\n }\n\n /**\n * Whether the controller is active (keyring is unlocked and user is onboarded).\n * When locked or not onboarded, balance updates should be skipped.\n *\n * @returns Whether the controller should perform balance updates.\n */\n get isActive(): boolean {\n return !this.#isLocked && this.#isOnboarded();\n }\n\n #syncAccounts(newChainIds: string[]): void {\n const accountsByChainId = cloneDeep(this.state.accountsByChainId);\n const { selectedNetworkClientId } = this.messenger.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId: currentChainId },\n } = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n const existing = Object.keys(accountsByChainId?.[currentChainId] ?? {});\n\n // Initialize new chain IDs if they don't exist\n newChainIds.forEach((newChainId) => {\n if (!accountsByChainId[newChainId]) {\n accountsByChainId[newChainId] = {};\n existing.forEach((address) => {\n accountsByChainId[newChainId][address] = { balance: '0x0' };\n });\n }\n });\n\n // Note: The address from the preferences controller are checksummed\n // The addresses from the accounts controller are lowercased\n const addresses = Object.values(\n this.messenger\n .call('AccountsController:listAccounts')\n .map((internalAccount) =>\n toChecksumHexAddress(internalAccount.address),\n ),\n );\n const newAddresses = addresses.filter(\n (address) => !existing.includes(address),\n );\n const oldAddresses = existing.filter(\n (address) => !addresses.includes(address),\n );\n Object.keys(accountsByChainId).forEach((chainId) => {\n newAddresses.forEach((address) => {\n accountsByChainId[chainId][address] = {\n balance: '0x0',\n };\n });\n });\n\n Object.keys(accountsByChainId).forEach((chainId) => {\n oldAddresses.forEach((address) => {\n delete accountsByChainId[chainId][address];\n });\n });\n\n if (!isEqual(this.state.accountsByChainId, accountsByChainId)) {\n this.update((state) => {\n state.accountsByChainId = accountsByChainId;\n });\n }\n }\n\n readonly #getProvider = (chainId: Hex): Web3Provider => {\n const { networkConfigurationsByChainId } = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfig = networkConfigurationsByChainId[chainId];\n const { networkClientId } =\n networkConfig.rpcEndpoints[networkConfig.defaultRpcEndpointIndex];\n const client = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return new Web3Provider(client.provider);\n };\n\n readonly #getNetworkClient = (chainId: Hex): NetworkClient => {\n const { networkConfigurationsByChainId } = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfig = networkConfigurationsByChainId[chainId];\n const { networkClientId } =\n networkConfig.rpcEndpoints[networkConfig.defaultRpcEndpointIndex];\n return this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n };\n\n /**\n * Creates an AccountsApiBalanceFetcher that only supports chains in the accountsApiChainIds array\n *\n * @returns A BalanceFetcher that wraps AccountsApiBalanceFetcher with chainId filtering\n */\n readonly #createAccountsApiFetcher = (): BalanceFetcher => {\n const originalFetcher = new AccountsApiBalanceFetcher(\n 'extension',\n this.#getProvider,\n );\n\n return {\n supports: (chainId: ChainIdHex): boolean => {\n // Only support chains that are both:\n // 1. In our specified accountsApiChainIds array\n // 2. Actually supported by the AccountsApi\n return (\n this.#accountsApiChainIds().includes(chainId) &&\n originalFetcher.supports(chainId)\n );\n },\n fetch: originalFetcher.fetch.bind(originalFetcher),\n };\n };\n\n /**\n * Resolves a networkClientId to a network client config\n * or globally selected network config if not provided\n *\n * @param networkClientId - Optional networkClientId to fetch a network client with\n * @returns network client config\n */\n #getCorrectNetworkClient(networkClientId?: NetworkClientId): {\n chainId: Hex;\n provider: NetworkClient['provider'];\n ethQuery: EthQuery;\n blockTracker: NetworkClient['blockTracker'];\n } {\n const selectedNetworkClientId =\n networkClientId ??\n this.messenger.call('NetworkController:getState').selectedNetworkClientId;\n const {\n configuration: { chainId },\n provider,\n blockTracker,\n } = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n return {\n chainId,\n provider,\n ethQuery: new EthQuery(provider),\n blockTracker,\n };\n }\n\n /**\n * Retrieves the list of network client IDs.\n *\n * @returns An array of network client IDs.\n */\n #getNetworkClientIds(): NetworkClientId[] {\n const { networkConfigurationsByChainId } = this.messenger.call(\n 'NetworkController:getState',\n );\n\n if (this.#isHomepageSectionsV1Enabled()) {\n const popularEvmChainIds = this.messenger.call(\n 'NetworkEnablementController:listPopularEvmNetworks',\n );\n return popularEvmChainIds\n .map((hexChainId) => {\n const networkConfig = networkConfigurationsByChainId[hexChainId];\n return networkConfig?.rpcEndpoints[\n networkConfig.defaultRpcEndpointIndex\n ]?.networkClientId;\n })\n .filter((id): id is NetworkClientId => id !== undefined);\n }\n\n const { enabledNetworkMap } = this.messenger.call(\n 'NetworkEnablementController:getState',\n );\n\n const evmEnabledStorageKeys = enabledNetworkMap[KnownCaipNamespace.Eip155]\n ? Object.keys(enabledNetworkMap[KnownCaipNamespace.Eip155])\n : [];\n\n return evmEnabledStorageKeys\n .map((hexChainId) => {\n const networkConfig = networkConfigurationsByChainId[hexChainId as Hex];\n return networkConfig?.rpcEndpoints[\n networkConfig.defaultRpcEndpointIndex\n ]?.networkClientId;\n })\n .filter((id): id is NetworkClientId => id !== undefined);\n }\n\n /**\n * Refreshes the balances of the accounts using the networkClientId\n *\n * @param input - The input for the poll.\n * @param input.networkClientIds - The network client IDs used to get balances.\n * @param input.queryAllAccounts - Whether to query all accounts or just the selected account\n */\n async _executePoll({\n networkClientIds,\n queryAllAccounts = false,\n }: AccountTrackerPollingInput): Promise<void> {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.refresh(networkClientIds, queryAllAccounts);\n }\n\n /**\n * Refreshes the balances of the accounts depending on the multi-account setting.\n * If multi-account is disabled, only updates the selected account balance.\n * If multi-account is enabled, updates balances for all accounts.\n *\n * @param networkClientIds - Optional network client IDs to fetch a network client with\n * @param queryAllAccounts - Whether to query all accounts or just the selected account\n */\n async refresh(\n networkClientIds: NetworkClientId[],\n queryAllAccounts: boolean = false,\n ): Promise<void> {\n const selectedAccount = this.messenger.call(\n 'AccountsController:getSelectedAccount',\n );\n const allAccounts = this.messenger.call('AccountsController:listAccounts');\n const { isMultiAccountBalancesEnabled } = this.messenger.call(\n 'PreferencesController:getState',\n );\n\n await this.#refreshAccounts({\n networkClientIds,\n queryAllAccounts: queryAllAccounts ?? isMultiAccountBalancesEnabled,\n selectedAccount: toChecksumHexAddress(\n selectedAccount.address,\n ) as ChecksumAddress,\n allAccounts,\n });\n }\n\n async refreshAddresses({\n networkClientIds,\n addresses,\n }: {\n networkClientIds: NetworkClientId[];\n addresses: string[];\n }): Promise<void> {\n const checksummedAddresses = addresses.map((address) =>\n toChecksumHexAddress(address),\n );\n\n const accounts = this.messenger\n .call('AccountsController:listAccounts')\n .filter((account) =>\n checksummedAddresses.includes(toChecksumHexAddress(account.address)),\n );\n\n await this.#refreshAccounts({\n networkClientIds,\n queryAllAccounts: true,\n selectedAccount: '0x0',\n allAccounts: accounts,\n });\n }\n\n async #refreshAccounts({\n networkClientIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: {\n networkClientIds: NetworkClientId[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<void> {\n const releaseLock = await this.#refreshMutex.acquire();\n try {\n const chainIds = networkClientIds.map((networkClientId) => {\n const { chainId } = this.#getCorrectNetworkClient(networkClientId);\n return chainId;\n });\n\n this.#syncAccounts(chainIds);\n\n if (!this.#fetchingEnabled() || !this.isActive) {\n return;\n }\n\n // Use balance fetchers with fallback strategy\n const aggregated: ProcessedBalance[] = [];\n let remainingChains = [...chainIds] as ChainIdHex[];\n\n // Temporary normalization to lowercase for balance fetching to match TokenBalancesController and enable HTTP caching\n const lowerCaseSelectedAccount =\n selectedAccount.toLowerCase() as ChecksumAddress;\n const lowerCaseAllAccounts = allAccounts.map((account) => ({\n ...account,\n address: account.address.toLowerCase(),\n }));\n\n // Try each fetcher in order, removing successfully processed chains\n for (const fetcher of this.#balanceFetchers) {\n const supportedChains = remainingChains.filter((chainId) =>\n fetcher.supports(chainId),\n );\n if (!supportedChains.length) {\n continue;\n }\n\n try {\n const result = await fetcher.fetch({\n chainIds: supportedChains,\n queryAllAccounts,\n selectedAccount: lowerCaseSelectedAccount,\n allAccounts: lowerCaseAllAccounts,\n });\n\n if (result.balances && result.balances.length > 0) {\n aggregated.push(...result.balances);\n // Remove chains that were successfully processed\n const processedChains = new Set(\n result.balances.map((b) => b.chainId),\n );\n remainingChains = remainingChains.filter(\n (chain) => !processedChains.has(chain),\n );\n }\n\n // Add unprocessed chains back to remainingChains for next fetcher\n if (\n result.unprocessedChainIds &&\n result.unprocessedChainIds.length > 0\n ) {\n // Only add chains that were originally requested and aren't already in remainingChains\n const currentRemainingChains = remainingChains;\n const chainsToAdd = result.unprocessedChainIds.filter(\n (chainId) =>\n supportedChains.includes(chainId) &&\n !currentRemainingChains.includes(chainId),\n );\n remainingChains.push(...chainsToAdd);\n }\n } catch (error) {\n console.warn(\n `Balance fetcher failed for chains ${supportedChains.join(', ')}: ${String(error)}`,\n );\n // Continue to next fetcher (fallback)\n }\n\n // If all chains have been processed, break early\n if (remainingChains.length === 0) {\n break;\n }\n }\n\n // Build a _copy_ of the current state and track whether anything changed\n const nextAccountsByChainId: AccountTrackerControllerState['accountsByChainId'] =\n cloneDeep(this.state.accountsByChainId);\n let hasChanges = false;\n\n // Process the aggregated balance results\n const stakedBalancesByChainAndAddress: Record<\n string,\n Record<string, string>\n > = {};\n\n aggregated.forEach(({ success, value, account, token, chainId }) => {\n if (success && value !== undefined) {\n const checksumAddress = toChecksumHexAddress(account);\n const hexValue = `0x${value.toString(16)}`;\n\n if (token === ZERO_ADDRESS) {\n // Native balance\n // Ensure the account entry exists before accessing it\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n }\n if (!nextAccountsByChainId[chainId][checksumAddress]) {\n nextAccountsByChainId[chainId][checksumAddress] = {\n balance: '0x0',\n };\n }\n\n if (\n nextAccountsByChainId[chainId][checksumAddress].balance !==\n hexValue\n ) {\n nextAccountsByChainId[chainId][checksumAddress].balance =\n hexValue;\n hasChanges = true;\n }\n } else if (\n STAKING_CONTRACT_ADDRESS_BY_CHAINID[chainId]?.toLowerCase() ===\n token.toLowerCase()\n ) {\n // Staked balance (from staking contract address)\n if (!stakedBalancesByChainAndAddress[chainId]) {\n stakedBalancesByChainAndAddress[chainId] = {};\n }\n stakedBalancesByChainAndAddress[chainId][checksumAddress] =\n hexValue;\n }\n }\n });\n\n // Apply staked balances\n Object.entries(stakedBalancesByChainAndAddress).forEach(\n ([chainId, balancesByAddress]) => {\n Object.entries(balancesByAddress).forEach(\n ([address, stakedBalance]) => {\n // Ensure account structure exists\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n }\n if (!nextAccountsByChainId[chainId][address]) {\n nextAccountsByChainId[chainId][address] = { balance: '0x0' };\n }\n if (\n nextAccountsByChainId[chainId][address].stakedBalance !==\n stakedBalance\n ) {\n nextAccountsByChainId[chainId][address].stakedBalance =\n stakedBalance;\n hasChanges = true;\n }\n },\n );\n },\n );\n\n // Only update state if something changed\n if (hasChanges) {\n this.update((state) => {\n state.accountsByChainId = nextAccountsByChainId;\n });\n }\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Sync accounts balances with some additional addresses.\n *\n * @param addresses - the additional addresses, may be hardware wallet addresses.\n * @param networkClientId - Optional networkClientId to fetch a network client with.\n * @returns accounts - addresses with synced balance\n */\n async syncBalanceWithAddresses(\n addresses: string[],\n networkClientId?: NetworkClientId,\n ): Promise<\n Record<string, { balance: string; stakedBalance?: StakedBalance }>\n > {\n // Skip balance fetching if locked or not onboarded to avoid unnecessary RPC calls\n if (!this.isActive) {\n return {};\n }\n\n const { ethQuery, chainId } =\n this.#getCorrectNetworkClient(networkClientId);\n\n // Skip native token fetching for chains that return arbitrary large numbers\n if (!shouldIncludeNativeToken(chainId)) {\n // Return empty balances for chains that skip native token fetching\n return addresses.reduce<\n Record<string, { balance: string; stakedBalance?: StakedBalance }>\n >((acc, address) => {\n acc[address] = { balance: '0x0' };\n return acc;\n }, {});\n }\n\n // TODO: This should use multicall when enabled by the user.\n return await Promise.all(\n addresses.map(\n (address): Promise<[string, string, StakedBalance] | undefined> => {\n return safelyExecuteWithTimeout(async () => {\n assert(ethQuery, 'Provider not set.');\n const balance = await query(ethQuery, 'getBalance', [address]);\n\n let stakedBalance: StakedBalance;\n if (this.#includeStakedAssets) {\n stakedBalance = (\n await this.#getStakedBalanceForChain([address], networkClientId)\n )[address];\n }\n return [address, balance, stakedBalance];\n });\n },\n ),\n ).then((value) => {\n return value.reduce((obj, item) => {\n if (!item) {\n return obj;\n }\n\n const [address, balance, stakedBalance] = item;\n return {\n ...obj,\n [address]: {\n balance,\n stakedBalance,\n },\n };\n }, {});\n });\n }\n\n /**\n * Updates the balances of multiple native tokens in a single batch operation.\n * This is more efficient than calling updateNativeToken multiple times as it\n * triggers only one state update.\n *\n * @param balances - Array of balance updates, each containing address, chainId, and balance.\n */\n updateNativeBalances(\n balances: { address: string; chainId: Hex; balance: Hex }[],\n ): void {\n const nextAccountsByChainId = cloneDeep(this.state.accountsByChainId);\n let hasChanges = false;\n\n balances.forEach(({ address, chainId, balance }) => {\n const checksumAddress = toChecksumHexAddress(address);\n\n // Ensure the chainId exists in the state\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n hasChanges = true;\n }\n\n // Check if the address exists for this chain\n const accountExists = Boolean(\n nextAccountsByChainId[chainId][checksumAddress],\n );\n\n // Ensure the address exists for this chain\n if (!accountExists) {\n nextAccountsByChainId[chainId][checksumAddress] = {\n balance: '0x0',\n };\n hasChanges = true;\n }\n\n // Only update the balance if it has changed, or if this is a new account\n const currentBalance =\n nextAccountsByChainId[chainId][checksumAddress].balance;\n if (!accountExists || currentBalance !== balance) {\n nextAccountsByChainId[chainId][checksumAddress].balance = balance;\n hasChanges = true;\n }\n });\n\n // Only call update if there are actual changes\n if (hasChanges) {\n this.update((state) => {\n state.accountsByChainId = nextAccountsByChainId;\n });\n }\n }\n\n /**\n * Updates the staked balances of multiple accounts in a single batch operation.\n * This is more efficient than updating staked balances individually as it\n * triggers only one state update.\n *\n * @param stakedBalances - Array of staked balance updates, each containing address, chainId, and stakedBalance.\n */\n updateStakedBalances(\n stakedBalances: {\n address: string;\n chainId: Hex;\n stakedBalance: StakedBalance;\n }[],\n ): void {\n const nextAccountsByChainId = cloneDeep(this.state.accountsByChainId);\n let hasChanges = false;\n\n stakedBalances.forEach(({ address, chainId, stakedBalance }) => {\n const checksumAddress = toChecksumHexAddress(address);\n\n // Ensure the chainId exists in the state\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n hasChanges = true;\n }\n\n // Check if the address exists for this chain\n const accountExists = Boolean(\n nextAccountsByChainId[chainId][checksumAddress],\n );\n\n // Ensure the address exists for this chain\n if (!accountExists) {\n nextAccountsByChainId[chainId][checksumAddress] = {\n balance: '0x0',\n };\n hasChanges = true;\n }\n\n // Only update the staked balance if it has changed, or if this is a new account\n const currentStakedBalance =\n nextAccountsByChainId[chainId][checksumAddress].stakedBalance;\n if (!accountExists || !isEqual(currentStakedBalance, stakedBalance)) {\n nextAccountsByChainId[chainId][checksumAddress].stakedBalance =\n stakedBalance;\n hasChanges = true;\n }\n });\n\n // Only call update if there are actual changes\n if (hasChanges) {\n this.update((state) => {\n state.accountsByChainId = nextAccountsByChainId;\n });\n }\n }\n}\n\nexport default AccountTrackerController;\n"]}
|
|
1
|
+
{"version":3,"file":"AccountTrackerController.cjs","sourceRoot":"","sources":["../src/AccountTrackerController.ts"],"names":[],"mappings":"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","sourcesContent":["import { Web3Provider } from '@ethersproject/providers';\nimport type {\n AccountsControllerSelectedEvmAccountChangeEvent,\n AccountsControllerGetSelectedAccountAction,\n AccountsControllerListAccountsAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n StateMetadata,\n} from '@metamask/base-controller';\nimport {\n query,\n safelyExecuteWithTimeout,\n toChecksumHexAddress,\n} from '@metamask/controller-utils';\nimport EthQuery from '@metamask/eth-query';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n NetworkClient,\n NetworkClientId,\n NetworkControllerGetNetworkClientByIdAction,\n NetworkControllerGetStateAction,\n NetworkControllerNetworkAddedEvent,\n} from '@metamask/network-controller';\nimport type {\n NetworkEnablementControllerGetStateAction,\n NetworkEnablementControllerListPopularEvmNetworksAction,\n} from '@metamask/network-enablement-controller';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n TransactionControllerTransactionConfirmedEvent,\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport { assert, KnownCaipNamespace } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { cloneDeep, isEqual } from 'lodash';\n\nimport type { AccountTrackerControllerMethodActions } from './AccountTrackerController-method-action-types';\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from './AssetsContractController';\nimport type {\n AssetsContractController,\n StakedBalance,\n} from './AssetsContractController';\nimport { shouldIncludeNativeToken } from './constants';\nimport { AccountsApiBalanceFetcher } from './multi-chain-accounts-service/api-balance-fetcher';\nimport type {\n BalanceFetcher,\n BalanceFetchResult,\n ProcessedBalance,\n} from './multi-chain-accounts-service/api-balance-fetcher';\nimport { RpcBalanceFetcher } from './rpc-service/rpc-balance-fetcher';\n\n/**\n * The name of the {@link AccountTrackerController}.\n */\nconst controllerName = 'AccountTrackerController';\n\nexport type ChainIdHex = Hex;\nexport type ChecksumAddress = Hex;\n\nconst ZERO_ADDRESS =\n '0x0000000000000000000000000000000000000000' as ChecksumAddress;\n\n/**\n * Creates an RPC balance fetcher configured for AccountTracker use case.\n * Returns only native balances and staked balances (no token balances).\n *\n * @param getProvider - Function to get Web3Provider for a given chain ID\n * @param getNetworkClient - Function to get NetworkClient for a given chain ID\n * @param includeStakedAssets - Whether to include staked assets in the fetch\n * @returns BalanceFetcher configured to fetch only native and optionally staked balances\n */\nfunction createAccountTrackerRpcBalanceFetcher(\n getProvider: (chainId: Hex) => Web3Provider,\n getNetworkClient: (chainId: Hex) => NetworkClient,\n includeStakedAssets: boolean,\n): BalanceFetcher {\n // Provide empty tokens state to ensure only native and staked balances are fetched\n const getEmptyTokensState = (): {\n allTokens: Record<string, never>;\n allDetectedTokens: Record<string, never>;\n } => ({\n allTokens: {},\n allDetectedTokens: {},\n });\n\n const rpcBalanceFetcher = new RpcBalanceFetcher(\n getProvider,\n getNetworkClient,\n getEmptyTokensState,\n );\n\n // Wrap the RpcBalanceFetcher to filter staked balances when not needed\n return {\n supports(_chainId: ChainIdHex): boolean {\n return rpcBalanceFetcher.supports();\n },\n\n async fetch(\n params: Parameters<BalanceFetcher['fetch']>[0],\n ): Promise<BalanceFetchResult> {\n const result = await rpcBalanceFetcher.fetch(params);\n\n if (!includeStakedAssets) {\n // Filter out staked balances from the results\n return {\n balances: result.balances.filter(\n (balance) => balance.token === ZERO_ADDRESS,\n ),\n unprocessedChainIds: result.unprocessedChainIds,\n };\n }\n\n return result;\n },\n };\n}\n\n/**\n * AccountInformation\n *\n * Account information object\n *\n * balance - Hex string of an account balance in wei\n *\n * stakedBalance - Hex string of an account staked balance in wei\n */\nexport type AccountInformation = {\n balance: string;\n stakedBalance?: string;\n};\n\n/**\n * AccountTrackerControllerState\n *\n * Account tracker controller state\n *\n * accountsByChainId - Map of addresses to account information by chain\n */\nexport type AccountTrackerControllerState = {\n accountsByChainId: Record<string, { [address: string]: AccountInformation }>;\n};\n\nconst accountTrackerMetadata: StateMetadata<AccountTrackerControllerState> = {\n accountsByChainId: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n};\n\n/**\n * The action that can be performed to get the state of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AccountTrackerControllerState\n>;\n\n/**\n * The actions that can be performed using the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerActions =\n | AccountTrackerControllerGetStateAction\n | AccountTrackerControllerMethodActions;\n\n/**\n * The messenger of the {@link AccountTrackerController} for communication.\n */\nexport type AllowedActions =\n | AccountsControllerListAccountsAction\n | {\n type: 'PreferencesController:getState';\n handler: () => { isMultiAccountBalancesEnabled: boolean };\n }\n | AccountsControllerGetSelectedAccountAction\n | NetworkControllerGetStateAction\n | NetworkControllerGetNetworkClientByIdAction\n | NetworkEnablementControllerGetStateAction\n | NetworkEnablementControllerListPopularEvmNetworksAction\n | KeyringControllerGetStateAction;\n\n/**\n * The event that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n AccountTrackerControllerState\n >;\n\n/**\n * The events that {@link AccountTrackerController} can emit.\n */\nexport type AccountTrackerControllerEvents =\n AccountTrackerControllerStateChangeEvent;\n\n/**\n * The external events available to the {@link AccountTrackerController}.\n */\nexport type AllowedEvents =\n | AccountsControllerSelectedEvmAccountChangeEvent\n | TransactionControllerUnapprovedTransactionAddedEvent\n | TransactionControllerTransactionConfirmedEvent\n | NetworkControllerNetworkAddedEvent\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent;\n\n/**\n * The messenger of the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerMessenger = Messenger<\n typeof controllerName,\n AccountTrackerControllerActions | AllowedActions,\n AccountTrackerControllerEvents | AllowedEvents\n>;\n\n/** The input to start polling for the {@link AccountTrackerController} */\ntype AccountTrackerPollingInput = {\n networkClientIds: NetworkClientId[];\n queryAllAccounts?: boolean;\n};\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'updateNativeBalances',\n 'updateStakedBalances',\n] as const;\n\n/**\n * Controller that tracks the network balances for all user accounts.\n */\nexport class AccountTrackerController extends StaticIntervalPollingController<AccountTrackerPollingInput>()<\n typeof controllerName,\n AccountTrackerControllerState,\n AccountTrackerControllerMessenger\n> {\n readonly #refreshMutex = new Mutex();\n\n readonly #includeStakedAssets: boolean;\n\n readonly #accountsApiChainIds: () => ChainIdHex[];\n\n readonly #getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n\n readonly #balanceFetchers: BalanceFetcher[];\n\n readonly #fetchingEnabled: () => boolean;\n\n readonly #isOnboarded: () => boolean;\n\n readonly #isHomepageSectionsV1Enabled: () => boolean;\n\n /** Track if the keyring is locked */\n #isLocked = true;\n\n /**\n * Creates an AccountTracker instance.\n *\n * @param options - The controller options.\n * @param options.interval - Polling interval used to fetch new account balances.\n * @param options.state - Initial state to set on this controller.\n * @param options.messenger - The controller messenger.\n * @param options.getStakedBalanceForChain - The function to get the staked native asset balance for a chain.\n * @param options.includeStakedAssets - Whether to include staked assets in the account balances.\n * @param options.accountsApiChainIds - Function that returns array of chainIds that should use Accounts-API strategy (if supported by API).\n * @param options.allowExternalServices - Disable external HTTP calls (privacy / offline mode).\n * @param options.fetchingEnabled - Function that returns whether the controller is fetching enabled.\n * @param options.isOnboarded - Whether the user has completed onboarding. If false, balance updates are skipped.\n * @param options.isHomepageSectionsV1Enabled - Whether the homepage sections v1 is enabled.\n */\n constructor({\n interval = 10000,\n state,\n messenger,\n getStakedBalanceForChain,\n includeStakedAssets = false,\n accountsApiChainIds = (): ChainIdHex[] => [],\n allowExternalServices = (): boolean => true,\n fetchingEnabled = (): boolean => true,\n isOnboarded = (): boolean => true,\n isHomepageSectionsV1Enabled = (): boolean => false,\n }: {\n interval?: number;\n state?: Partial<AccountTrackerControllerState>;\n messenger: AccountTrackerControllerMessenger;\n getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n includeStakedAssets?: boolean;\n accountsApiChainIds?: () => ChainIdHex[];\n isHomepageSectionsV1Enabled?: () => boolean;\n allowExternalServices?: () => boolean;\n fetchingEnabled?: () => boolean;\n isOnboarded?: () => boolean;\n }) {\n const { selectedNetworkClientId } = messenger.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId },\n } = messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n super({\n name: controllerName,\n messenger,\n state: {\n accountsByChainId: {\n [chainId]: {},\n },\n ...state,\n },\n metadata: accountTrackerMetadata,\n });\n this.#getStakedBalanceForChain = getStakedBalanceForChain;\n\n this.#includeStakedAssets = includeStakedAssets;\n this.#accountsApiChainIds = accountsApiChainIds;\n this.#isHomepageSectionsV1Enabled = isHomepageSectionsV1Enabled;\n\n // Initialize balance fetchers - Strategy order: API first, then RPC fallback\n this.#balanceFetchers = [\n ...(accountsApiChainIds().length > 0 && allowExternalServices()\n ? [this.#createAccountsApiFetcher()]\n : []),\n createAccountTrackerRpcBalanceFetcher(\n this.#getProvider,\n this.#getNetworkClient,\n this.#includeStakedAssets,\n ),\n ];\n\n this.#fetchingEnabled = fetchingEnabled;\n this.#isOnboarded = isOnboarded;\n\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n this.#isLocked = !isUnlocked;\n\n this.setIntervalLength(interval);\n\n this.messenger.subscribe(\n 'AccountsController:selectedEvmAccountChange',\n (newAddress, prevAddress) => {\n if (newAddress !== prevAddress) {\n // Making an async call for this new event\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.refresh(this.#getNetworkClientIds());\n }\n },\n (event): string => event.address,\n );\n\n this.messenger.subscribe(\n 'NetworkController:networkAdded',\n (networkConfiguration) => {\n const { networkClientId } =\n networkConfiguration.rpcEndpoints[\n networkConfiguration.defaultRpcEndpointIndex\n ];\n this.refresh([networkClientId]).catch(() => {\n // Silently handle refresh errors\n });\n },\n );\n\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isLocked = false;\n const networkClientIds = this.#getNetworkClientIds();\n this.refresh(networkClientIds).catch((error) => {\n console.error('Error refreshing balances after keyring unlock:', error);\n });\n });\n\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isLocked = true;\n });\n\n this.messenger.subscribe(\n 'TransactionController:unapprovedTransactionAdded',\n (transactionMeta: TransactionMeta) => {\n const addresses = [transactionMeta.txParams.from];\n if (transactionMeta.txParams.to) {\n addresses.push(transactionMeta.txParams.to);\n }\n this.refreshAddresses({\n networkClientIds: [transactionMeta.networkClientId],\n addresses,\n }).catch(() => {\n // Silently handle refresh errors\n });\n },\n );\n\n this.messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n (transactionMeta: TransactionMeta) => {\n const addresses = [transactionMeta.txParams.from];\n if (transactionMeta.txParams.to) {\n addresses.push(transactionMeta.txParams.to);\n }\n this.refreshAddresses({\n networkClientIds: [transactionMeta.networkClientId],\n addresses,\n }).catch(() => {\n // Silently handle refresh errors\n });\n },\n );\n\n messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);\n }\n\n /**\n * Whether the controller is active (keyring is unlocked and user is onboarded).\n * When locked or not onboarded, balance updates should be skipped.\n *\n * @returns Whether the controller should perform balance updates.\n */\n get isActive(): boolean {\n return !this.#isLocked && this.#isOnboarded();\n }\n\n #syncAccounts(newChainIds: string[]): void {\n const accountsByChainId = cloneDeep(this.state.accountsByChainId);\n const { selectedNetworkClientId } = this.messenger.call(\n 'NetworkController:getState',\n );\n const {\n configuration: { chainId: currentChainId },\n } = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n const existing = Object.keys(accountsByChainId?.[currentChainId] ?? {});\n\n // Initialize new chain IDs if they don't exist\n newChainIds.forEach((newChainId) => {\n if (!accountsByChainId[newChainId]) {\n accountsByChainId[newChainId] = {};\n existing.forEach((address) => {\n accountsByChainId[newChainId][address] = { balance: '0x0' };\n });\n }\n });\n\n // Note: The address from the preferences controller are checksummed\n // The addresses from the accounts controller are lowercased\n const addresses = Object.values(\n this.messenger\n .call('AccountsController:listAccounts')\n .map((internalAccount) =>\n toChecksumHexAddress(internalAccount.address),\n ),\n );\n const newAddresses = addresses.filter(\n (address) => !existing.includes(address),\n );\n const oldAddresses = existing.filter(\n (address) => !addresses.includes(address),\n );\n Object.keys(accountsByChainId).forEach((chainId) => {\n newAddresses.forEach((address) => {\n if (!accountsByChainId[chainId][address]) {\n accountsByChainId[chainId][address] = {\n balance: '0x0',\n };\n }\n });\n });\n\n Object.keys(accountsByChainId).forEach((chainId) => {\n oldAddresses.forEach((address) => {\n delete accountsByChainId[chainId][address];\n });\n });\n\n if (!isEqual(this.state.accountsByChainId, accountsByChainId)) {\n this.update((state) => {\n state.accountsByChainId = accountsByChainId;\n });\n }\n }\n\n readonly #getProvider = (chainId: Hex): Web3Provider => {\n const { networkConfigurationsByChainId } = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfig = networkConfigurationsByChainId[chainId];\n const { networkClientId } =\n networkConfig.rpcEndpoints[networkConfig.defaultRpcEndpointIndex];\n const client = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n return new Web3Provider(client.provider);\n };\n\n readonly #getNetworkClient = (chainId: Hex): NetworkClient => {\n const { networkConfigurationsByChainId } = this.messenger.call(\n 'NetworkController:getState',\n );\n const networkConfig = networkConfigurationsByChainId[chainId];\n const { networkClientId } =\n networkConfig.rpcEndpoints[networkConfig.defaultRpcEndpointIndex];\n return this.messenger.call(\n 'NetworkController:getNetworkClientById',\n networkClientId,\n );\n };\n\n /**\n * Creates an AccountsApiBalanceFetcher that only supports chains in the accountsApiChainIds array\n *\n * @returns A BalanceFetcher that wraps AccountsApiBalanceFetcher with chainId filtering\n */\n readonly #createAccountsApiFetcher = (): BalanceFetcher => {\n const originalFetcher = new AccountsApiBalanceFetcher(\n 'extension',\n this.#getProvider,\n );\n\n return {\n supports: (chainId: ChainIdHex): boolean => {\n // Only support chains that are both:\n // 1. In our specified accountsApiChainIds array\n // 2. Actually supported by the AccountsApi\n return (\n this.#accountsApiChainIds().includes(chainId) &&\n originalFetcher.supports(chainId)\n );\n },\n fetch: originalFetcher.fetch.bind(originalFetcher),\n };\n };\n\n /**\n * Resolves a networkClientId to a network client config\n * or globally selected network config if not provided\n *\n * @param networkClientId - Optional networkClientId to fetch a network client with\n * @returns network client config\n */\n #getCorrectNetworkClient(networkClientId?: NetworkClientId): {\n chainId: Hex;\n provider: NetworkClient['provider'];\n ethQuery: EthQuery;\n blockTracker: NetworkClient['blockTracker'];\n } {\n const selectedNetworkClientId =\n networkClientId ??\n this.messenger.call('NetworkController:getState').selectedNetworkClientId;\n const {\n configuration: { chainId },\n provider,\n blockTracker,\n } = this.messenger.call(\n 'NetworkController:getNetworkClientById',\n selectedNetworkClientId,\n );\n\n return {\n chainId,\n provider,\n ethQuery: new EthQuery(provider),\n blockTracker,\n };\n }\n\n /**\n * Retrieves the list of network client IDs.\n *\n * @returns An array of network client IDs.\n */\n #getNetworkClientIds(): NetworkClientId[] {\n const { networkConfigurationsByChainId } = this.messenger.call(\n 'NetworkController:getState',\n );\n\n if (this.#isHomepageSectionsV1Enabled()) {\n const popularEvmChainIds = this.messenger.call(\n 'NetworkEnablementController:listPopularEvmNetworks',\n );\n return popularEvmChainIds\n .map((hexChainId) => {\n const networkConfig = networkConfigurationsByChainId[hexChainId];\n return networkConfig?.rpcEndpoints[\n networkConfig.defaultRpcEndpointIndex\n ]?.networkClientId;\n })\n .filter((id): id is NetworkClientId => id !== undefined);\n }\n\n const { enabledNetworkMap } = this.messenger.call(\n 'NetworkEnablementController:getState',\n );\n\n const evmEnabledStorageKeys = enabledNetworkMap[KnownCaipNamespace.Eip155]\n ? Object.keys(enabledNetworkMap[KnownCaipNamespace.Eip155])\n : [];\n\n return evmEnabledStorageKeys\n .map((hexChainId) => {\n const networkConfig = networkConfigurationsByChainId[hexChainId as Hex];\n return networkConfig?.rpcEndpoints[\n networkConfig.defaultRpcEndpointIndex\n ]?.networkClientId;\n })\n .filter((id): id is NetworkClientId => id !== undefined);\n }\n\n /**\n * Refreshes the balances of the accounts using the networkClientId\n *\n * @param input - The input for the poll.\n * @param input.networkClientIds - The network client IDs used to get balances.\n * @param input.queryAllAccounts - Whether to query all accounts or just the selected account\n */\n async _executePoll({\n networkClientIds,\n queryAllAccounts = false,\n }: AccountTrackerPollingInput): Promise<void> {\n // TODO: Either fix this lint violation or explain why it's necessary to ignore.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this.refresh(networkClientIds, queryAllAccounts);\n }\n\n /**\n * Refreshes the balances of the accounts depending on the multi-account setting.\n * If multi-account is disabled, only updates the selected account balance.\n * If multi-account is enabled, updates balances for all accounts.\n *\n * @param networkClientIds - Optional network client IDs to fetch a network client with\n * @param queryAllAccounts - Whether to query all accounts or just the selected account\n */\n async refresh(\n networkClientIds: NetworkClientId[],\n queryAllAccounts: boolean = false,\n ): Promise<void> {\n const selectedAccount = this.messenger.call(\n 'AccountsController:getSelectedAccount',\n );\n const allAccounts = this.messenger.call('AccountsController:listAccounts');\n const { isMultiAccountBalancesEnabled } = this.messenger.call(\n 'PreferencesController:getState',\n );\n\n await this.#refreshAccounts({\n networkClientIds,\n queryAllAccounts: queryAllAccounts ?? isMultiAccountBalancesEnabled,\n selectedAccount: toChecksumHexAddress(\n selectedAccount.address,\n ) as ChecksumAddress,\n allAccounts,\n });\n }\n\n async refreshAddresses({\n networkClientIds,\n addresses,\n }: {\n networkClientIds: NetworkClientId[];\n addresses: string[];\n }): Promise<void> {\n const checksummedAddresses = addresses.map((address) =>\n toChecksumHexAddress(address),\n );\n\n const accounts = this.messenger\n .call('AccountsController:listAccounts')\n .filter((account) =>\n checksummedAddresses.includes(toChecksumHexAddress(account.address)),\n );\n\n await this.#refreshAccounts({\n networkClientIds,\n queryAllAccounts: true,\n selectedAccount: '0x0',\n allAccounts: accounts,\n });\n }\n\n async #refreshAccounts({\n networkClientIds,\n queryAllAccounts,\n selectedAccount,\n allAccounts,\n }: {\n networkClientIds: NetworkClientId[];\n queryAllAccounts: boolean;\n selectedAccount: ChecksumAddress;\n allAccounts: InternalAccount[];\n }): Promise<void> {\n const releaseLock = await this.#refreshMutex.acquire();\n try {\n const chainIds = networkClientIds.map((networkClientId) => {\n const { chainId } = this.#getCorrectNetworkClient(networkClientId);\n return chainId;\n });\n\n this.#syncAccounts(chainIds);\n\n if (!this.#fetchingEnabled() || !this.isActive) {\n return;\n }\n\n // Use balance fetchers with fallback strategy\n const aggregated: ProcessedBalance[] = [];\n let remainingChains = [...chainIds] as ChainIdHex[];\n\n // Temporary normalization to lowercase for balance fetching to match TokenBalancesController and enable HTTP caching\n const lowerCaseSelectedAccount =\n selectedAccount.toLowerCase() as ChecksumAddress;\n const lowerCaseAllAccounts = allAccounts.map((account) => ({\n ...account,\n address: account.address.toLowerCase(),\n }));\n\n // Try each fetcher in order, removing successfully processed chains\n for (const fetcher of this.#balanceFetchers) {\n const supportedChains = remainingChains.filter((chainId) =>\n fetcher.supports(chainId),\n );\n if (!supportedChains.length) {\n continue;\n }\n\n try {\n const result = await fetcher.fetch({\n chainIds: supportedChains,\n queryAllAccounts,\n selectedAccount: lowerCaseSelectedAccount,\n allAccounts: lowerCaseAllAccounts,\n });\n\n if (result.balances && result.balances.length > 0) {\n aggregated.push(...result.balances);\n // Remove chains that were successfully processed\n const processedChains = new Set(\n result.balances.map((b) => b.chainId),\n );\n remainingChains = remainingChains.filter(\n (chain) => !processedChains.has(chain),\n );\n }\n\n // Add unprocessed chains back to remainingChains for next fetcher\n if (\n result.unprocessedChainIds &&\n result.unprocessedChainIds.length > 0\n ) {\n // Only add chains that were originally requested and aren't already in remainingChains\n const currentRemainingChains = remainingChains;\n const chainsToAdd = result.unprocessedChainIds.filter(\n (chainId) =>\n supportedChains.includes(chainId) &&\n !currentRemainingChains.includes(chainId),\n );\n remainingChains.push(...chainsToAdd);\n }\n } catch (error) {\n console.warn(\n `Balance fetcher failed for chains ${supportedChains.join(', ')}: ${String(error)}`,\n );\n // Continue to next fetcher (fallback)\n }\n\n // If all chains have been processed, break early\n if (remainingChains.length === 0) {\n break;\n }\n }\n\n // Build a _copy_ of the current state and track whether anything changed\n const nextAccountsByChainId: AccountTrackerControllerState['accountsByChainId'] =\n cloneDeep(this.state.accountsByChainId);\n let hasChanges = false;\n\n // Process the aggregated balance results\n const stakedBalancesByChainAndAddress: Record<\n string,\n Record<string, string>\n > = {};\n\n aggregated.forEach(({ success, value, account, token, chainId }) => {\n if (success && value !== undefined) {\n const checksumAddress = toChecksumHexAddress(account);\n const hexValue = `0x${value.toString(16)}`;\n\n if (token === ZERO_ADDRESS) {\n // Native balance\n // Ensure the account entry exists before accessing it\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n }\n if (!nextAccountsByChainId[chainId][checksumAddress]) {\n nextAccountsByChainId[chainId][checksumAddress] = {\n balance: '0x0',\n };\n }\n\n if (\n nextAccountsByChainId[chainId][checksumAddress].balance !==\n hexValue\n ) {\n nextAccountsByChainId[chainId][checksumAddress].balance =\n hexValue;\n hasChanges = true;\n }\n } else if (\n STAKING_CONTRACT_ADDRESS_BY_CHAINID[chainId]?.toLowerCase() ===\n token.toLowerCase()\n ) {\n // Staked balance (from staking contract address)\n if (!stakedBalancesByChainAndAddress[chainId]) {\n stakedBalancesByChainAndAddress[chainId] = {};\n }\n stakedBalancesByChainAndAddress[chainId][checksumAddress] =\n hexValue;\n }\n }\n });\n\n // Apply staked balances\n Object.entries(stakedBalancesByChainAndAddress).forEach(\n ([chainId, balancesByAddress]) => {\n Object.entries(balancesByAddress).forEach(\n ([address, stakedBalance]) => {\n // Ensure account structure exists\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n }\n if (!nextAccountsByChainId[chainId][address]) {\n nextAccountsByChainId[chainId][address] = { balance: '0x0' };\n }\n if (\n nextAccountsByChainId[chainId][address].stakedBalance !==\n stakedBalance\n ) {\n nextAccountsByChainId[chainId][address].stakedBalance =\n stakedBalance;\n hasChanges = true;\n }\n },\n );\n },\n );\n\n // Only update state if something changed\n if (hasChanges) {\n this.update((state) => {\n state.accountsByChainId = nextAccountsByChainId;\n });\n }\n } finally {\n releaseLock();\n }\n }\n\n /**\n * Sync accounts balances with some additional addresses.\n *\n * @param addresses - the additional addresses, may be hardware wallet addresses.\n * @param networkClientId - Optional networkClientId to fetch a network client with.\n * @returns accounts - addresses with synced balance\n */\n async syncBalanceWithAddresses(\n addresses: string[],\n networkClientId?: NetworkClientId,\n ): Promise<\n Record<string, { balance: string; stakedBalance?: StakedBalance }>\n > {\n // Skip balance fetching if locked or not onboarded to avoid unnecessary RPC calls\n if (!this.isActive) {\n return {};\n }\n\n const { ethQuery, chainId } =\n this.#getCorrectNetworkClient(networkClientId);\n\n // Skip native token fetching for chains that return arbitrary large numbers\n if (!shouldIncludeNativeToken(chainId)) {\n // Return empty balances for chains that skip native token fetching\n return addresses.reduce<\n Record<string, { balance: string; stakedBalance?: StakedBalance }>\n >((acc, address) => {\n acc[address] = { balance: '0x0' };\n return acc;\n }, {});\n }\n\n // TODO: This should use multicall when enabled by the user.\n return await Promise.all(\n addresses.map(\n (address): Promise<[string, string, StakedBalance] | undefined> => {\n return safelyExecuteWithTimeout(async () => {\n assert(ethQuery, 'Provider not set.');\n const balance = await query(ethQuery, 'getBalance', [address]);\n\n let stakedBalance: StakedBalance;\n if (this.#includeStakedAssets) {\n stakedBalance = (\n await this.#getStakedBalanceForChain([address], networkClientId)\n )[address];\n }\n return [address, balance, stakedBalance];\n });\n },\n ),\n ).then((value) => {\n return value.reduce((obj, item) => {\n if (!item) {\n return obj;\n }\n\n const [address, balance, stakedBalance] = item;\n return {\n ...obj,\n [address]: {\n balance,\n stakedBalance,\n },\n };\n }, {});\n });\n }\n\n /**\n * Updates the balances of multiple native tokens in a single batch operation.\n * This is more efficient than calling updateNativeToken multiple times as it\n * triggers only one state update.\n *\n * @param balances - Array of balance updates, each containing address, chainId, and balance.\n */\n updateNativeBalances(\n balances: { address: string; chainId: Hex; balance: Hex }[],\n ): void {\n const nextAccountsByChainId = cloneDeep(this.state.accountsByChainId);\n let hasChanges = false;\n\n balances.forEach(({ address, chainId, balance }) => {\n const checksumAddress = toChecksumHexAddress(address);\n\n // Ensure the chainId exists in the state\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n hasChanges = true;\n }\n\n // Check if the address exists for this chain\n const accountExists = Boolean(\n nextAccountsByChainId[chainId][checksumAddress],\n );\n\n // Ensure the address exists for this chain\n if (!accountExists) {\n nextAccountsByChainId[chainId][checksumAddress] = {\n balance: '0x0',\n };\n hasChanges = true;\n }\n\n // Only update the balance if it has changed, or if this is a new account\n const currentBalance =\n nextAccountsByChainId[chainId][checksumAddress].balance;\n if (!accountExists || currentBalance !== balance) {\n nextAccountsByChainId[chainId][checksumAddress].balance = balance;\n hasChanges = true;\n }\n });\n\n // Only call update if there are actual changes\n if (hasChanges) {\n this.update((state) => {\n state.accountsByChainId = nextAccountsByChainId;\n });\n }\n }\n\n /**\n * Updates the staked balances of multiple accounts in a single batch operation.\n * This is more efficient than updating staked balances individually as it\n * triggers only one state update.\n *\n * @param stakedBalances - Array of staked balance updates, each containing address, chainId, and stakedBalance.\n */\n updateStakedBalances(\n stakedBalances: {\n address: string;\n chainId: Hex;\n stakedBalance: StakedBalance;\n }[],\n ): void {\n const nextAccountsByChainId = cloneDeep(this.state.accountsByChainId);\n let hasChanges = false;\n\n stakedBalances.forEach(({ address, chainId, stakedBalance }) => {\n const checksumAddress = toChecksumHexAddress(address);\n\n // Ensure the chainId exists in the state\n if (!nextAccountsByChainId[chainId]) {\n nextAccountsByChainId[chainId] = {};\n hasChanges = true;\n }\n\n // Check if the address exists for this chain\n const accountExists = Boolean(\n nextAccountsByChainId[chainId][checksumAddress],\n );\n\n // Ensure the address exists for this chain\n if (!accountExists) {\n nextAccountsByChainId[chainId][checksumAddress] = {\n balance: '0x0',\n };\n hasChanges = true;\n }\n\n // Only update the staked balance if it has changed, or if this is a new account\n const currentStakedBalance =\n nextAccountsByChainId[chainId][checksumAddress].stakedBalance;\n if (!accountExists || !isEqual(currentStakedBalance, stakedBalance)) {\n nextAccountsByChainId[chainId][checksumAddress].stakedBalance =\n stakedBalance;\n hasChanges = true;\n }\n });\n\n // Only call update if there are actual changes\n if (hasChanges) {\n this.update((state) => {\n state.accountsByChainId = nextAccountsByChainId;\n });\n }\n }\n}\n\nexport default AccountTrackerController;\n"]}
|