@metamask/assets-controllers 73.3.0 → 74.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 -1
- package/dist/AccountTrackerController.cjs +214 -84
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts +7 -1
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts +7 -1
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +216 -85
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/TokenBalancesController.cjs +14 -9
- package/dist/TokenBalancesController.cjs.map +1 -1
- package/dist/TokenBalancesController.d.cts.map +1 -1
- package/dist/TokenBalancesController.d.mts.map +1 -1
- package/dist/TokenBalancesController.mjs +15 -10
- package/dist/TokenBalancesController.mjs.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/multicall.cjs +1 -1
- package/dist/multicall.cjs.map +1 -1
- package/dist/multicall.mjs +1 -1
- package/dist/multicall.mjs.map +1 -1
- package/dist/selectors/stringify-balance.cjs +43 -0
- package/dist/selectors/stringify-balance.cjs.map +1 -0
- package/dist/selectors/stringify-balance.d.cts +8 -0
- package/dist/selectors/stringify-balance.d.cts.map +1 -0
- package/dist/selectors/stringify-balance.d.mts +8 -0
- package/dist/selectors/stringify-balance.d.mts.map +1 -0
- package/dist/selectors/stringify-balance.mjs +39 -0
- package/dist/selectors/stringify-balance.mjs.map +1 -0
- package/dist/selectors/token-selectors.cjs +290 -0
- package/dist/selectors/token-selectors.cjs.map +1 -0
- package/dist/selectors/token-selectors.d.cts +810 -0
- package/dist/selectors/token-selectors.d.cts.map +1 -0
- package/dist/selectors/token-selectors.d.mts +810 -0
- package/dist/selectors/token-selectors.d.mts.map +1 -0
- package/dist/selectors/token-selectors.mjs +287 -0
- package/dist/selectors/token-selectors.mjs.map +1 -0
- package/package.json +12 -12
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [74.1.0]
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Enable `AccountTrackerController` to fetch native balances using AccountsAPI when `allowExternalServices` is enabled ([#6369](https://github.com/MetaMask/core/pull/6369))
|
|
15
|
+
|
|
16
|
+
- Implement native balance fetching via AccountsAPI when `useAccountsAPI` and `allowExternalServices` are both true
|
|
17
|
+
- Add fallback to RPC balance fetching when external services are disabled
|
|
18
|
+
- Add comprehensive test coverage for both AccountsAPI and RPC balance fetching scenarios
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Bump `@metamask/base-controller` from `^8.1.0` to `^8.2.0` ([#6355](https://github.com/MetaMask/core/pull/6355))
|
|
23
|
+
|
|
24
|
+
- Add new `accountId` field to the `Asset` type ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Uses `InternalAccount['type']` for the `Asset['type']` property ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
29
|
+
|
|
30
|
+
- 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))
|
|
31
|
+
|
|
32
|
+
- Prevents mutation of memoized fields used inside selectors ([#6358](https://github.com/MetaMask/core/pull/6358))
|
|
33
|
+
|
|
34
|
+
- Fix duplicate token balance entries caused by case-sensitive address comparison in `TokenBalancesController.updateBalances` ([#6354](https://github.com/MetaMask/core/pull/6354))
|
|
35
|
+
|
|
36
|
+
- 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
|
|
37
|
+
- Add comprehensive unit tests for token address normalization scenarios
|
|
38
|
+
|
|
39
|
+
- Fix TokenBalancesController timeout handling by replacing `safelyExecuteWithTimeout` with proper `Promise.race` implementation ([#6365](https://github.com/MetaMask/core/pull/6365))
|
|
40
|
+
|
|
41
|
+
- Replace `safelyExecuteWithTimeout` which was silently swallowing timeout errors with direct `Promise.race` that properly throws
|
|
42
|
+
- Reduce RPC timeout from 3 minutes to 15 seconds for better responsiveness and batch size
|
|
43
|
+
- Enable proper fallback between API and RPC balance fetchers when timeouts occur
|
|
44
|
+
|
|
45
|
+
## [74.0.0]
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- Added a token selector that returns list of tokens and balances for evm and multichain assets based on the selected account group ([#6226](https://github.com/MetaMask/core/pull/6226))
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- **BREAKING:** Bump peer dependency `@metamask/accounts-controller` from `^32.0.0` to `^33.0.0` ([#6345](https://github.com/MetaMask/core/pull/6345))
|
|
54
|
+
- **BREAKING:** Bump peer dependency `@metamask/keyring-controller` from `^22.0.0` to `^23.0.0` ([#6345](https://github.com/MetaMask/core/pull/6345))
|
|
55
|
+
- **BREAKING:** Bump peer dependency `@metamask/preferences-controller` from `^18.0.0` to `^19.0.0` ([#6345](https://github.com/MetaMask/core/pull/6345))
|
|
56
|
+
- **BREAKING:** Bump peer dependency `@metamask/transaction-controller` from `^59.0.0` to `^60.0.0` ([#6345](https://github.com/MetaMask/core/pull/6345))
|
|
57
|
+
|
|
10
58
|
## [73.3.0]
|
|
11
59
|
|
|
12
60
|
### Changed
|
|
@@ -1866,7 +1914,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
1866
1914
|
|
|
1867
1915
|
- Use Ethers for AssetsContractController ([#845](https://github.com/MetaMask/core/pull/845))
|
|
1868
1916
|
|
|
1869
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@
|
|
1917
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@74.1.0...HEAD
|
|
1918
|
+
[74.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@74.0.0...@metamask/assets-controllers@74.1.0
|
|
1919
|
+
[74.0.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@73.3.0...@metamask/assets-controllers@74.0.0
|
|
1870
1920
|
[73.3.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@73.2.0...@metamask/assets-controllers@73.3.0
|
|
1871
1921
|
[73.2.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@73.1.0...@metamask/assets-controllers@73.2.0
|
|
1872
1922
|
[73.1.0]: https://github.com/MetaMask/core/compare/@metamask/assets-controllers@73.0.2...@metamask/assets-controllers@73.1.0
|
|
@@ -13,7 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
13
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
|
-
var _AccountTrackerController_instances, _AccountTrackerController_refreshMutex, _AccountTrackerController_includeStakedAssets, _AccountTrackerController_getStakedBalanceForChain, _AccountTrackerController_getCorrectNetworkClient, _AccountTrackerController_getNetworkClientIds,
|
|
16
|
+
var _AccountTrackerRpcBalanceFetcher_instances, _AccountTrackerRpcBalanceFetcher_getProvider, _AccountTrackerRpcBalanceFetcher_getNetworkClient, _AccountTrackerRpcBalanceFetcher_includeStakedAssets, _AccountTrackerRpcBalanceFetcher_getStakedBalanceForChain, _AccountTrackerRpcBalanceFetcher_getBalanceFromChain, _AccountTrackerController_instances, _AccountTrackerController_refreshMutex, _AccountTrackerController_includeStakedAssets, _AccountTrackerController_getStakedBalanceForChain, _AccountTrackerController_balanceFetchers, _AccountTrackerController_getProvider, _AccountTrackerController_getNetworkClient, _AccountTrackerController_getCorrectNetworkClient, _AccountTrackerController_getNetworkClientIds, _AccountTrackerController_registerMessageHandlers;
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.AccountTrackerController = void 0;
|
|
19
19
|
const contracts_1 = require("@ethersproject/contracts");
|
|
@@ -23,14 +23,136 @@ const eth_query_1 = __importDefault(require("@metamask/eth-query"));
|
|
|
23
23
|
const polling_controller_1 = require("@metamask/polling-controller");
|
|
24
24
|
const utils_1 = require("@metamask/utils");
|
|
25
25
|
const async_mutex_1 = require("async-mutex");
|
|
26
|
+
const bn_js_1 = __importDefault(require("bn.js"));
|
|
26
27
|
const lodash_1 = require("lodash");
|
|
27
28
|
const single_call_balance_checker_abi_1 = __importDefault(require("single-call-balance-checker-abi"));
|
|
28
29
|
const AssetsContractController_1 = require("./AssetsContractController.cjs");
|
|
29
30
|
const assetsUtil_1 = require("./assetsUtil.cjs");
|
|
31
|
+
const api_balance_fetcher_1 = require("./multi-chain-accounts-service/api-balance-fetcher.cjs");
|
|
30
32
|
/**
|
|
31
33
|
* The name of the {@link AccountTrackerController}.
|
|
32
34
|
*/
|
|
33
35
|
const controllerName = 'AccountTrackerController';
|
|
36
|
+
const DEFAULT_TIMEOUT_MS = 15000;
|
|
37
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
38
|
+
/**
|
|
39
|
+
* RPC-based balance fetcher for AccountTrackerController.
|
|
40
|
+
* Fetches only native balances and staked balances (no token balances).
|
|
41
|
+
*/
|
|
42
|
+
class AccountTrackerRpcBalanceFetcher {
|
|
43
|
+
constructor(getProvider, getNetworkClient, includeStakedAssets, getStakedBalanceForChain) {
|
|
44
|
+
_AccountTrackerRpcBalanceFetcher_instances.add(this);
|
|
45
|
+
_AccountTrackerRpcBalanceFetcher_getProvider.set(this, void 0);
|
|
46
|
+
_AccountTrackerRpcBalanceFetcher_getNetworkClient.set(this, void 0);
|
|
47
|
+
_AccountTrackerRpcBalanceFetcher_includeStakedAssets.set(this, void 0);
|
|
48
|
+
_AccountTrackerRpcBalanceFetcher_getStakedBalanceForChain.set(this, void 0);
|
|
49
|
+
__classPrivateFieldSet(this, _AccountTrackerRpcBalanceFetcher_getProvider, getProvider, "f");
|
|
50
|
+
__classPrivateFieldSet(this, _AccountTrackerRpcBalanceFetcher_getNetworkClient, getNetworkClient, "f");
|
|
51
|
+
__classPrivateFieldSet(this, _AccountTrackerRpcBalanceFetcher_includeStakedAssets, includeStakedAssets, "f");
|
|
52
|
+
__classPrivateFieldSet(this, _AccountTrackerRpcBalanceFetcher_getStakedBalanceForChain, getStakedBalanceForChain, "f");
|
|
53
|
+
}
|
|
54
|
+
supports() {
|
|
55
|
+
return true; // fallback – supports every chain
|
|
56
|
+
}
|
|
57
|
+
async fetch({ chainIds, queryAllAccounts, selectedAccount, allAccounts, }) {
|
|
58
|
+
const results = [];
|
|
59
|
+
for (const chainId of chainIds) {
|
|
60
|
+
const accountsToUpdate = queryAllAccounts
|
|
61
|
+
? Object.values(allAccounts).map((account) => (0, controller_utils_1.toChecksumHexAddress)(account.address))
|
|
62
|
+
: [selectedAccount];
|
|
63
|
+
const { provider, blockTracker } = __classPrivateFieldGet(this, _AccountTrackerRpcBalanceFetcher_getNetworkClient, "f").call(this, chainId);
|
|
64
|
+
const ethQuery = new eth_query_1.default(provider);
|
|
65
|
+
// Force fresh block data before multicall
|
|
66
|
+
await (0, controller_utils_1.safelyExecuteWithTimeout)(() => blockTracker?.checkForLatestBlock?.());
|
|
67
|
+
// Fetch native balances
|
|
68
|
+
if ((0, utils_1.hasProperty)(AssetsContractController_1.SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID, chainId)) {
|
|
69
|
+
const contractAddress = AssetsContractController_1.SINGLE_CALL_BALANCES_ADDRESS_BY_CHAINID[chainId];
|
|
70
|
+
const contract = new contracts_1.Contract(contractAddress, single_call_balance_checker_abi_1.default, __classPrivateFieldGet(this, _AccountTrackerRpcBalanceFetcher_getProvider, "f").call(this, chainId));
|
|
71
|
+
const nativeBalances = await (0, controller_utils_1.safelyExecuteWithTimeout)(() => contract.balances(accountsToUpdate, [ZERO_ADDRESS]), false, 3000);
|
|
72
|
+
if (nativeBalances) {
|
|
73
|
+
accountsToUpdate.forEach((address, index) => {
|
|
74
|
+
results.push({
|
|
75
|
+
success: true,
|
|
76
|
+
value: new bn_js_1.default(nativeBalances[index].toString()),
|
|
77
|
+
account: address,
|
|
78
|
+
token: ZERO_ADDRESS,
|
|
79
|
+
chainId,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Process accounts in batches using reduceInBatchesSerially
|
|
86
|
+
await (0, assetsUtil_1.reduceInBatchesSerially)({
|
|
87
|
+
values: accountsToUpdate,
|
|
88
|
+
batchSize: assetsUtil_1.TOKEN_PRICES_BATCH_SIZE,
|
|
89
|
+
initialResult: undefined,
|
|
90
|
+
eachBatch: async (workingResult, batch) => {
|
|
91
|
+
const balancePromises = batch.map(async (address) => {
|
|
92
|
+
const balanceResult = await __classPrivateFieldGet(this, _AccountTrackerRpcBalanceFetcher_instances, "m", _AccountTrackerRpcBalanceFetcher_getBalanceFromChain).call(this, address, ethQuery).catch(() => null);
|
|
93
|
+
if (balanceResult) {
|
|
94
|
+
results.push({
|
|
95
|
+
success: true,
|
|
96
|
+
value: new bn_js_1.default(balanceResult.replace('0x', ''), 16),
|
|
97
|
+
account: address,
|
|
98
|
+
token: ZERO_ADDRESS,
|
|
99
|
+
chainId,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
results.push({
|
|
104
|
+
success: false,
|
|
105
|
+
account: address,
|
|
106
|
+
token: ZERO_ADDRESS,
|
|
107
|
+
chainId,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
await Promise.allSettled(balancePromises);
|
|
112
|
+
return workingResult;
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Fetch staked balances if enabled
|
|
117
|
+
if (__classPrivateFieldGet(this, _AccountTrackerRpcBalanceFetcher_includeStakedAssets, "f")) {
|
|
118
|
+
const stakedBalancesPromise = __classPrivateFieldGet(this, _AccountTrackerRpcBalanceFetcher_getStakedBalanceForChain, "f").call(this, accountsToUpdate, chainId);
|
|
119
|
+
const stakedBalanceResult = await (0, controller_utils_1.safelyExecuteWithTimeout)(async () => (await stakedBalancesPromise));
|
|
120
|
+
if (stakedBalanceResult) {
|
|
121
|
+
// Find the staking contract address for this chain
|
|
122
|
+
const stakingContractAddress = AssetsContractController_1.STAKING_CONTRACT_ADDRESS_BY_CHAINID[chainId];
|
|
123
|
+
if (stakingContractAddress) {
|
|
124
|
+
Object.entries(stakedBalanceResult).forEach(([address, balance]) => {
|
|
125
|
+
results.push({
|
|
126
|
+
success: true,
|
|
127
|
+
value: balance
|
|
128
|
+
? new bn_js_1.default(balance.replace('0x', ''), 16)
|
|
129
|
+
: new bn_js_1.default('0'),
|
|
130
|
+
account: address,
|
|
131
|
+
token: (0, controller_utils_1.toChecksumHexAddress)(stakingContractAddress),
|
|
132
|
+
chainId,
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return results;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
_AccountTrackerRpcBalanceFetcher_getProvider = new WeakMap(), _AccountTrackerRpcBalanceFetcher_getNetworkClient = new WeakMap(), _AccountTrackerRpcBalanceFetcher_includeStakedAssets = new WeakMap(), _AccountTrackerRpcBalanceFetcher_getStakedBalanceForChain = new WeakMap(), _AccountTrackerRpcBalanceFetcher_instances = new WeakSet(), _AccountTrackerRpcBalanceFetcher_getBalanceFromChain =
|
|
143
|
+
/**
|
|
144
|
+
* Fetches the balance of a given address from the blockchain.
|
|
145
|
+
*
|
|
146
|
+
* @param address - The account address to fetch the balance for.
|
|
147
|
+
* @param ethQuery - The EthQuery instance to query getBalance with.
|
|
148
|
+
* @returns A promise that resolves to the balance in a hex string format.
|
|
149
|
+
*/
|
|
150
|
+
async function _AccountTrackerRpcBalanceFetcher_getBalanceFromChain(address, ethQuery) {
|
|
151
|
+
return await (0, controller_utils_1.safelyExecuteWithTimeout)(async () => {
|
|
152
|
+
(0, utils_1.assert)(ethQuery, 'Provider not set.');
|
|
153
|
+
return await (0, controller_utils_1.query)(ethQuery, 'getBalance', [address]);
|
|
154
|
+
});
|
|
155
|
+
};
|
|
34
156
|
const accountTrackerMetadata = {
|
|
35
157
|
accountsByChainId: {
|
|
36
158
|
persist: true,
|
|
@@ -50,8 +172,10 @@ class AccountTrackerController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
50
172
|
* @param options.messenger - The controller messaging system.
|
|
51
173
|
* @param options.getStakedBalanceForChain - The function to get the staked native asset balance for a chain.
|
|
52
174
|
* @param options.includeStakedAssets - Whether to include staked assets in the account balances.
|
|
175
|
+
* @param options.useAccountsAPI - Enable Accounts‑API strategy (if supported chain).
|
|
176
|
+
* @param options.allowExternalServices - Disable external HTTP calls (privacy / offline mode).
|
|
53
177
|
*/
|
|
54
|
-
constructor({ interval = 10000, state, messenger, getStakedBalanceForChain, includeStakedAssets = false, }) {
|
|
178
|
+
constructor({ interval = 10000, state, messenger, getStakedBalanceForChain, includeStakedAssets = false, useAccountsAPI = false, allowExternalServices = () => true, }) {
|
|
55
179
|
const { selectedNetworkClientId } = messenger.call('NetworkController:getState');
|
|
56
180
|
const { configuration: { chainId }, } = messenger.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
|
57
181
|
super({
|
|
@@ -69,8 +193,29 @@ class AccountTrackerController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
69
193
|
_AccountTrackerController_refreshMutex.set(this, new async_mutex_1.Mutex());
|
|
70
194
|
_AccountTrackerController_includeStakedAssets.set(this, void 0);
|
|
71
195
|
_AccountTrackerController_getStakedBalanceForChain.set(this, void 0);
|
|
196
|
+
_AccountTrackerController_balanceFetchers.set(this, void 0);
|
|
197
|
+
_AccountTrackerController_getProvider.set(this, (chainId) => {
|
|
198
|
+
const { networkConfigurationsByChainId } = this.messagingSystem.call('NetworkController:getState');
|
|
199
|
+
const cfg = networkConfigurationsByChainId[chainId];
|
|
200
|
+
const { networkClientId } = cfg.rpcEndpoints[cfg.defaultRpcEndpointIndex];
|
|
201
|
+
const client = this.messagingSystem.call('NetworkController:getNetworkClientById', networkClientId);
|
|
202
|
+
return new providers_1.Web3Provider(client.provider);
|
|
203
|
+
});
|
|
204
|
+
_AccountTrackerController_getNetworkClient.set(this, (chainId) => {
|
|
205
|
+
const { networkConfigurationsByChainId } = this.messagingSystem.call('NetworkController:getState');
|
|
206
|
+
const cfg = networkConfigurationsByChainId[chainId];
|
|
207
|
+
const { networkClientId } = cfg.rpcEndpoints[cfg.defaultRpcEndpointIndex];
|
|
208
|
+
return this.messagingSystem.call('NetworkController:getNetworkClientById', networkClientId);
|
|
209
|
+
});
|
|
72
210
|
__classPrivateFieldSet(this, _AccountTrackerController_getStakedBalanceForChain, getStakedBalanceForChain, "f");
|
|
73
211
|
__classPrivateFieldSet(this, _AccountTrackerController_includeStakedAssets, includeStakedAssets, "f");
|
|
212
|
+
// Initialize balance fetchers - Strategy order: API first, then RPC fallback
|
|
213
|
+
__classPrivateFieldSet(this, _AccountTrackerController_balanceFetchers, [
|
|
214
|
+
...(useAccountsAPI && allowExternalServices()
|
|
215
|
+
? [new api_balance_fetcher_1.AccountsApiBalanceFetcher('extension', __classPrivateFieldGet(this, _AccountTrackerController_getProvider, "f"))]
|
|
216
|
+
: []),
|
|
217
|
+
new AccountTrackerRpcBalanceFetcher(__classPrivateFieldGet(this, _AccountTrackerController_getProvider, "f"), __classPrivateFieldGet(this, _AccountTrackerController_getNetworkClient, "f"), includeStakedAssets, getStakedBalanceForChain),
|
|
218
|
+
], "f");
|
|
74
219
|
this.setIntervalLength(interval);
|
|
75
220
|
this.messagingSystem.subscribe('AccountsController:selectedEvmAccountChange', (newAddress, prevAddress) => {
|
|
76
221
|
if (newAddress !== prevAddress) {
|
|
@@ -140,6 +285,8 @@ class AccountTrackerController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
140
285
|
*/
|
|
141
286
|
async refresh(networkClientIds) {
|
|
142
287
|
const selectedAccount = this.messagingSystem.call('AccountsController:getSelectedAccount');
|
|
288
|
+
const allAccounts = this.messagingSystem.call('AccountsController:listAccounts');
|
|
289
|
+
const { isMultiAccountBalancesEnabled } = this.messagingSystem.call('PreferencesController:getState');
|
|
143
290
|
const releaseLock = await __classPrivateFieldGet(this, _AccountTrackerController_refreshMutex, "f").acquire();
|
|
144
291
|
try {
|
|
145
292
|
const chainIds = networkClientIds.map((networkClientId) => {
|
|
@@ -147,83 +294,79 @@ class AccountTrackerController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
147
294
|
return chainId;
|
|
148
295
|
});
|
|
149
296
|
this.syncAccounts(chainIds);
|
|
150
|
-
//
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
};
|
|
177
|
-
});
|
|
297
|
+
// Use balance fetchers with fallback strategy
|
|
298
|
+
const aggregated = [];
|
|
299
|
+
let remainingChains = [...chainIds];
|
|
300
|
+
// Try each fetcher in order, removing successfully processed chains
|
|
301
|
+
for (const fetcher of __classPrivateFieldGet(this, _AccountTrackerController_balanceFetchers, "f")) {
|
|
302
|
+
const supportedChains = remainingChains.filter((c) => fetcher.supports(c));
|
|
303
|
+
if (!supportedChains.length) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
const balances = await Promise.race([
|
|
308
|
+
fetcher.fetch({
|
|
309
|
+
chainIds: supportedChains,
|
|
310
|
+
queryAllAccounts: isMultiAccountBalancesEnabled,
|
|
311
|
+
selectedAccount: (0, controller_utils_1.toChecksumHexAddress)(selectedAccount.address),
|
|
312
|
+
allAccounts,
|
|
313
|
+
}),
|
|
314
|
+
new Promise((_resolve, reject) => setTimeout(() => {
|
|
315
|
+
reject(new Error(`Timeout after ${DEFAULT_TIMEOUT_MS}ms`));
|
|
316
|
+
}, DEFAULT_TIMEOUT_MS)),
|
|
317
|
+
]);
|
|
318
|
+
if (balances && balances.length > 0) {
|
|
319
|
+
aggregated.push(...balances);
|
|
320
|
+
// Remove chains that were successfully processed
|
|
321
|
+
const processedChains = new Set(balances.map((b) => b.chainId));
|
|
322
|
+
remainingChains = remainingChains.filter((chain) => !processedChains.has(chain));
|
|
178
323
|
}
|
|
179
324
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
values: accountsToUpdate,
|
|
184
|
-
batchSize: assetsUtil_1.TOKEN_PRICES_BATCH_SIZE,
|
|
185
|
-
initialResult: undefined,
|
|
186
|
-
eachBatch: async (workingResult, batch) => {
|
|
187
|
-
const balancePromises = batch.map(async (address) => {
|
|
188
|
-
const balanceResult = await __classPrivateFieldGet(this, _AccountTrackerController_instances, "m", _AccountTrackerController_getBalanceFromChain).call(this, address, ethQuery).catch(() => null);
|
|
189
|
-
// Update account balances
|
|
190
|
-
if (balanceResult) {
|
|
191
|
-
accountsForChain[address] = {
|
|
192
|
-
balance: balanceResult,
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
await Promise.allSettled(balancePromises);
|
|
197
|
-
return workingResult;
|
|
198
|
-
},
|
|
199
|
-
});
|
|
325
|
+
catch (error) {
|
|
326
|
+
console.warn(`Balance fetcher failed for chains ${supportedChains.join(', ')}: ${String(error)}`);
|
|
327
|
+
// Continue to next fetcher (fallback)
|
|
200
328
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
};
|
|
207
|
-
});
|
|
208
|
-
// After all batches are processed, return the updated data
|
|
209
|
-
return { chainId, accountsForChain };
|
|
210
|
-
});
|
|
211
|
-
// Wait for all networkClientId updates to settle in parallel
|
|
212
|
-
const allResults = await Promise.allSettled(updatePromises);
|
|
329
|
+
// If all chains have been processed, break early
|
|
330
|
+
if (remainingChains.length === 0) {
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
213
334
|
// Build a _copy_ of the current state and track whether anything changed
|
|
214
335
|
const nextAccountsByChainId = (0, lodash_1.cloneDeep)(this.state.accountsByChainId);
|
|
215
336
|
let hasChanges = false;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
337
|
+
// Process the aggregated balance results
|
|
338
|
+
const stakedBalancesByChainAndAddress = {};
|
|
339
|
+
aggregated.forEach(({ success, value, account, token, chainId }) => {
|
|
340
|
+
if (success && value !== undefined) {
|
|
341
|
+
const hexValue = `0x${value.toString(16)}`;
|
|
342
|
+
if (token === ZERO_ADDRESS) {
|
|
343
|
+
// Native balance
|
|
344
|
+
if (nextAccountsByChainId[chainId][account].balance !== hexValue) {
|
|
345
|
+
nextAccountsByChainId[chainId][account].balance = hexValue;
|
|
346
|
+
hasChanges = true;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
// Staked balance (from staking contract address)
|
|
351
|
+
if (!stakedBalancesByChainAndAddress[chainId]) {
|
|
352
|
+
stakedBalancesByChainAndAddress[chainId] = {};
|
|
353
|
+
}
|
|
354
|
+
stakedBalancesByChainAndAddress[chainId][account] = hexValue;
|
|
223
355
|
}
|
|
224
356
|
}
|
|
225
357
|
});
|
|
226
|
-
//
|
|
358
|
+
// Apply staked balances
|
|
359
|
+
Object.entries(stakedBalancesByChainAndAddress).forEach(([chainId, balancesByAddress]) => {
|
|
360
|
+
Object.entries(balancesByAddress).forEach(([address, stakedBalance]) => {
|
|
361
|
+
if (nextAccountsByChainId[chainId][address].stakedBalance !==
|
|
362
|
+
stakedBalance) {
|
|
363
|
+
nextAccountsByChainId[chainId][address].stakedBalance =
|
|
364
|
+
stakedBalance;
|
|
365
|
+
hasChanges = true;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
// Only update state if something changed
|
|
227
370
|
if (hasChanges) {
|
|
228
371
|
this.update((state) => {
|
|
229
372
|
state.accountsByChainId = nextAccountsByChainId;
|
|
@@ -318,7 +461,7 @@ class AccountTrackerController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
318
461
|
}
|
|
319
462
|
}
|
|
320
463
|
exports.AccountTrackerController = AccountTrackerController;
|
|
321
|
-
_AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerController_includeStakedAssets = new WeakMap(), _AccountTrackerController_getStakedBalanceForChain = new WeakMap(), _AccountTrackerController_instances = new WeakSet(), _AccountTrackerController_getCorrectNetworkClient = function _AccountTrackerController_getCorrectNetworkClient(networkClientId) {
|
|
464
|
+
_AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerController_includeStakedAssets = new WeakMap(), _AccountTrackerController_getStakedBalanceForChain = new WeakMap(), _AccountTrackerController_balanceFetchers = new WeakMap(), _AccountTrackerController_getProvider = new WeakMap(), _AccountTrackerController_getNetworkClient = new WeakMap(), _AccountTrackerController_instances = new WeakSet(), _AccountTrackerController_getCorrectNetworkClient = function _AccountTrackerController_getCorrectNetworkClient(networkClientId) {
|
|
322
465
|
const selectedNetworkClientId = networkClientId ??
|
|
323
466
|
this.messagingSystem.call('NetworkController:getState')
|
|
324
467
|
.selectedNetworkClientId;
|
|
@@ -332,19 +475,6 @@ _AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerControlle
|
|
|
332
475
|
}, _AccountTrackerController_getNetworkClientIds = function _AccountTrackerController_getNetworkClientIds() {
|
|
333
476
|
const { networkConfigurationsByChainId } = this.messagingSystem.call('NetworkController:getState');
|
|
334
477
|
return Object.values(networkConfigurationsByChainId).flatMap((networkConfiguration) => networkConfiguration.rpcEndpoints.map((rpcEndpoint) => rpcEndpoint.networkClientId));
|
|
335
|
-
}, _AccountTrackerController_getBalanceFromChain =
|
|
336
|
-
/**
|
|
337
|
-
* Fetches the balance of a given address from the blockchain.
|
|
338
|
-
*
|
|
339
|
-
* @param address - The account address to fetch the balance for.
|
|
340
|
-
* @param ethQuery - The EthQuery instance to query getBalnce with.
|
|
341
|
-
* @returns A promise that resolves to the balance in a hex string format.
|
|
342
|
-
*/
|
|
343
|
-
async function _AccountTrackerController_getBalanceFromChain(address, ethQuery) {
|
|
344
|
-
return await (0, controller_utils_1.safelyExecuteWithTimeout)(async () => {
|
|
345
|
-
(0, utils_1.assert)(ethQuery, 'Provider not set.');
|
|
346
|
-
return await (0, controller_utils_1.query)(ethQuery, 'getBalance', [address]);
|
|
347
|
-
});
|
|
348
478
|
}, _AccountTrackerController_registerMessageHandlers = function _AccountTrackerController_registerMessageHandlers() {
|
|
349
479
|
this.messagingSystem.registerActionHandler(`${controllerName}:updateNativeBalances`, this.updateNativeBalances.bind(this));
|
|
350
480
|
this.messagingSystem.registerActionHandler(`${controllerName}:updateStakedBalances`, this.updateStakedBalances.bind(this));
|