@metamask/assets-controllers 94.1.0 → 95.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -1
- package/dist/AccountTrackerController.cjs +25 -10
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts +12 -5
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts +12 -5
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +25 -10
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/CurrencyRateController.d.cts +2 -2
- package/dist/CurrencyRateController.d.mts +2 -2
- package/dist/DeFiPositionsController/DeFiPositionsController.d.cts +2 -2
- package/dist/DeFiPositionsController/DeFiPositionsController.d.mts +2 -2
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.cjs +8 -2
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.cjs.map +1 -1
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.cts +2 -2
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.cts.map +1 -1
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.mts +2 -2
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.d.mts.map +1 -1
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.mjs +8 -2
- package/dist/MultichainAssetsRatesController/MultichainAssetsRatesController.mjs.map +1 -1
- package/dist/TokenBalancesController.d.cts +2 -2
- package/dist/TokenBalancesController.d.mts +2 -2
- package/dist/TokenDetectionController.d.cts +2 -2
- package/dist/TokenDetectionController.d.mts +2 -2
- package/dist/TokenListController.d.cts +2 -2
- package/dist/TokenListController.d.mts +2 -2
- package/dist/TokenRatesController.d.cts +2 -2
- package/dist/TokenRatesController.d.mts +2 -2
- package/dist/index.cjs +2 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/multicall.cjs +5 -0
- package/dist/multicall.cjs.map +1 -1
- package/dist/multicall.d.cts.map +1 -1
- package/dist/multicall.d.mts.map +1 -1
- package/dist/multicall.mjs +5 -0
- package/dist/multicall.mjs.map +1 -1
- package/dist/selectors/token-selectors.cjs +3 -3
- package/dist/selectors/token-selectors.cjs.map +1 -1
- package/dist/selectors/token-selectors.d.cts +711 -0
- package/dist/selectors/token-selectors.d.cts.map +1 -1
- package/dist/selectors/token-selectors.d.mts +711 -0
- package/dist/selectors/token-selectors.d.mts.map +1 -1
- package/dist/selectors/token-selectors.mjs +1 -1
- package/dist/selectors/token-selectors.mjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.cjs +77 -101
- package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.cts +39 -26
- package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.mts +39 -26
- package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
- package/dist/token-prices-service/codefi-v2.mjs +77 -101
- package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
- package/dist/token-service.cjs +33 -12
- package/dist/token-service.cjs.map +1 -1
- package/dist/token-service.d.cts +37 -9
- package/dist/token-service.d.cts.map +1 -1
- package/dist/token-service.d.mts +37 -9
- package/dist/token-service.d.mts.map +1 -1
- package/dist/token-service.mjs +33 -12
- package/dist/token-service.mjs.map +1 -1
- package/package.json +10 -10
|
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
9
9
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
10
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
11
|
};
|
|
12
|
-
var _AccountTrackerController_instances, _AccountTrackerController_refreshMutex, _AccountTrackerController_includeStakedAssets, _AccountTrackerController_accountsApiChainIds, _AccountTrackerController_getStakedBalanceForChain, _AccountTrackerController_balanceFetchers, _AccountTrackerController_fetchingEnabled, _AccountTrackerController_isOnboarded, _AccountTrackerController_syncAccounts, _AccountTrackerController_getProvider, _AccountTrackerController_getNetworkClient, _AccountTrackerController_createAccountsApiFetcher, _AccountTrackerController_getCorrectNetworkClient, _AccountTrackerController_getNetworkClientIds, _AccountTrackerController_refreshAccounts, _AccountTrackerController_registerMessageHandlers;
|
|
12
|
+
var _AccountTrackerController_instances, _AccountTrackerController_refreshMutex, _AccountTrackerController_includeStakedAssets, _AccountTrackerController_accountsApiChainIds, _AccountTrackerController_getStakedBalanceForChain, _AccountTrackerController_balanceFetchers, _AccountTrackerController_fetchingEnabled, _AccountTrackerController_isOnboarded, _AccountTrackerController_isLocked, _AccountTrackerController_syncAccounts, _AccountTrackerController_getProvider, _AccountTrackerController_getNetworkClient, _AccountTrackerController_createAccountsApiFetcher, _AccountTrackerController_getCorrectNetworkClient, _AccountTrackerController_getNetworkClientIds, _AccountTrackerController_refreshAccounts, _AccountTrackerController_registerMessageHandlers;
|
|
13
13
|
function $importDefault(module) {
|
|
14
14
|
if (module?.__esModule) {
|
|
15
15
|
return module.default;
|
|
@@ -115,6 +115,8 @@ export class AccountTrackerController extends StaticIntervalPollingController()
|
|
|
115
115
|
_AccountTrackerController_balanceFetchers.set(this, void 0);
|
|
116
116
|
_AccountTrackerController_fetchingEnabled.set(this, void 0);
|
|
117
117
|
_AccountTrackerController_isOnboarded.set(this, void 0);
|
|
118
|
+
/** Track if the keyring is locked */
|
|
119
|
+
_AccountTrackerController_isLocked.set(this, true);
|
|
118
120
|
_AccountTrackerController_getProvider.set(this, (chainId) => {
|
|
119
121
|
const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
|
|
120
122
|
const networkConfig = networkConfigurationsByChainId[chainId];
|
|
@@ -158,6 +160,8 @@ export class AccountTrackerController extends StaticIntervalPollingController()
|
|
|
158
160
|
], "f");
|
|
159
161
|
__classPrivateFieldSet(this, _AccountTrackerController_fetchingEnabled, fetchingEnabled, "f");
|
|
160
162
|
__classPrivateFieldSet(this, _AccountTrackerController_isOnboarded, isOnboarded, "f");
|
|
163
|
+
const { isUnlocked } = this.messenger.call('KeyringController:getState');
|
|
164
|
+
__classPrivateFieldSet(this, _AccountTrackerController_isLocked, !isUnlocked, "f");
|
|
161
165
|
this.setIntervalLength(interval);
|
|
162
166
|
this.messenger.subscribe('AccountsController:selectedEvmAccountChange', (newAddress, prevAddress) => {
|
|
163
167
|
if (newAddress !== prevAddress) {
|
|
@@ -166,15 +170,17 @@ export class AccountTrackerController extends StaticIntervalPollingController()
|
|
|
166
170
|
this.refresh(__classPrivateFieldGet(this, _AccountTrackerController_instances, "m", _AccountTrackerController_getNetworkClientIds).call(this));
|
|
167
171
|
}
|
|
168
172
|
}, (event) => event.address);
|
|
169
|
-
this.messenger.subscribe('NetworkController:networkAdded', () => {
|
|
170
|
-
|
|
173
|
+
this.messenger.subscribe('NetworkController:networkAdded', (networkConfiguration) => {
|
|
174
|
+
const { networkClientId } = networkConfiguration.rpcEndpoints[networkConfiguration.defaultRpcEndpointIndex];
|
|
175
|
+
this.refresh([networkClientId]).catch(() => {
|
|
171
176
|
// Silently handle refresh errors
|
|
172
177
|
});
|
|
173
178
|
});
|
|
174
179
|
this.messenger.subscribe('KeyringController:unlock', () => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
180
|
+
__classPrivateFieldSet(this, _AccountTrackerController_isLocked, false, "f");
|
|
181
|
+
});
|
|
182
|
+
this.messenger.subscribe('KeyringController:lock', () => {
|
|
183
|
+
__classPrivateFieldSet(this, _AccountTrackerController_isLocked, true, "f");
|
|
178
184
|
});
|
|
179
185
|
this.messenger.subscribe('TransactionController:unapprovedTransactionAdded', (transactionMeta) => {
|
|
180
186
|
const addresses = [transactionMeta.txParams.from];
|
|
@@ -202,6 +208,15 @@ export class AccountTrackerController extends StaticIntervalPollingController()
|
|
|
202
208
|
});
|
|
203
209
|
__classPrivateFieldGet(this, _AccountTrackerController_instances, "m", _AccountTrackerController_registerMessageHandlers).call(this);
|
|
204
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Whether the controller is active (keyring is unlocked and user is onboarded).
|
|
213
|
+
* When locked or not onboarded, balance updates should be skipped.
|
|
214
|
+
*
|
|
215
|
+
* @returns Whether the controller should perform balance updates.
|
|
216
|
+
*/
|
|
217
|
+
get isActive() {
|
|
218
|
+
return !__classPrivateFieldGet(this, _AccountTrackerController_isLocked, "f") && __classPrivateFieldGet(this, _AccountTrackerController_isOnboarded, "f").call(this);
|
|
219
|
+
}
|
|
205
220
|
/**
|
|
206
221
|
* Refreshes the balances of the accounts using the networkClientId
|
|
207
222
|
*
|
|
@@ -253,8 +268,8 @@ export class AccountTrackerController extends StaticIntervalPollingController()
|
|
|
253
268
|
* @returns accounts - addresses with synced balance
|
|
254
269
|
*/
|
|
255
270
|
async syncBalanceWithAddresses(addresses, networkClientId) {
|
|
256
|
-
// Skip balance fetching if not onboarded to avoid unnecessary RPC calls
|
|
257
|
-
if (!
|
|
271
|
+
// Skip balance fetching if locked or not onboarded to avoid unnecessary RPC calls
|
|
272
|
+
if (!this.isActive) {
|
|
258
273
|
return {};
|
|
259
274
|
}
|
|
260
275
|
const { ethQuery } = __classPrivateFieldGet(this, _AccountTrackerController_instances, "m", _AccountTrackerController_getCorrectNetworkClient).call(this, networkClientId);
|
|
@@ -367,7 +382,7 @@ export class AccountTrackerController extends StaticIntervalPollingController()
|
|
|
367
382
|
}
|
|
368
383
|
}
|
|
369
384
|
}
|
|
370
|
-
_AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerController_includeStakedAssets = new WeakMap(), _AccountTrackerController_accountsApiChainIds = new WeakMap(), _AccountTrackerController_getStakedBalanceForChain = new WeakMap(), _AccountTrackerController_balanceFetchers = new WeakMap(), _AccountTrackerController_fetchingEnabled = new WeakMap(), _AccountTrackerController_isOnboarded = new WeakMap(), _AccountTrackerController_getProvider = new WeakMap(), _AccountTrackerController_getNetworkClient = new WeakMap(), _AccountTrackerController_createAccountsApiFetcher = new WeakMap(), _AccountTrackerController_instances = new WeakSet(), _AccountTrackerController_syncAccounts = function _AccountTrackerController_syncAccounts(newChainIds) {
|
|
385
|
+
_AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerController_includeStakedAssets = new WeakMap(), _AccountTrackerController_accountsApiChainIds = new WeakMap(), _AccountTrackerController_getStakedBalanceForChain = new WeakMap(), _AccountTrackerController_balanceFetchers = new WeakMap(), _AccountTrackerController_fetchingEnabled = new WeakMap(), _AccountTrackerController_isOnboarded = new WeakMap(), _AccountTrackerController_isLocked = new WeakMap(), _AccountTrackerController_getProvider = new WeakMap(), _AccountTrackerController_getNetworkClient = new WeakMap(), _AccountTrackerController_createAccountsApiFetcher = new WeakMap(), _AccountTrackerController_instances = new WeakSet(), _AccountTrackerController_syncAccounts = function _AccountTrackerController_syncAccounts(newChainIds) {
|
|
371
386
|
const accountsByChainId = cloneDeep(this.state.accountsByChainId);
|
|
372
387
|
const { selectedNetworkClientId } = this.messenger.call('NetworkController:getState');
|
|
373
388
|
const { configuration: { chainId: currentChainId }, } = this.messenger.call('NetworkController:getNetworkClientById', selectedNetworkClientId);
|
|
@@ -426,7 +441,7 @@ _AccountTrackerController_refreshMutex = new WeakMap(), _AccountTrackerControlle
|
|
|
426
441
|
return chainId;
|
|
427
442
|
});
|
|
428
443
|
__classPrivateFieldGet(this, _AccountTrackerController_instances, "m", _AccountTrackerController_syncAccounts).call(this, chainIds);
|
|
429
|
-
if (!__classPrivateFieldGet(this, _AccountTrackerController_fetchingEnabled, "f").call(this) || !
|
|
444
|
+
if (!__classPrivateFieldGet(this, _AccountTrackerController_fetchingEnabled, "f").call(this) || !this.isActive) {
|
|
430
445
|
return;
|
|
431
446
|
}
|
|
432
447
|
// Use balance fetchers with fallback strategy
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccountTrackerController.mjs","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 { KeyringControllerUnlockEvent } 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 { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n TransactionControllerTransactionConfirmedEvent,\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport { assert } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { cloneDeep, isEqual } from 'lodash';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from './AssetsContractController';\nimport type {\n AssetsContractController,\n StakedBalance,\n} from './AssetsContractController';\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 action that can be performed to update multiple native token balances in batch.\n */\nexport type AccountTrackerUpdateNativeBalancesAction = {\n type: `${typeof controllerName}:updateNativeBalances`;\n handler: AccountTrackerController['updateNativeBalances'];\n};\n\n/**\n * The action that can be performed to update multiple staked balances in batch.\n */\nexport type AccountTrackerUpdateStakedBalancesAction = {\n type: `${typeof controllerName}:updateStakedBalances`;\n handler: AccountTrackerController['updateStakedBalances'];\n};\n\n/**\n * The actions that can be performed using the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerActions =\n | AccountTrackerControllerGetStateAction\n | AccountTrackerUpdateNativeBalancesAction\n | AccountTrackerUpdateStakedBalancesAction;\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\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 | 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\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 /**\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 */\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 }: {\n interval?: number;\n state?: Partial<AccountTrackerControllerState>;\n messenger: AccountTrackerControllerMessenger;\n getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n includeStakedAssets?: boolean;\n accountsApiChainIds?: () => ChainIdHex[];\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\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 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('NetworkController:networkAdded', () => {\n this.refresh(this.#getNetworkClientIds()).catch(() => {\n // Silently handle refresh errors\n });\n });\n\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.refresh(this.#getNetworkClientIds()).catch(() => {\n // Silently handle refresh errors\n });\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 this.#registerMessageHandlers();\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 return Object.values(networkConfigurationsByChainId).flatMap(\n (networkConfiguration) =>\n networkConfiguration.rpcEndpoints.map(\n (rpcEndpoint) => rpcEndpoint.networkClientId,\n ),\n );\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.#isOnboarded()) {\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 not onboarded to avoid unnecessary RPC calls during onboarding\n if (!this.#isOnboarded()) {\n return {};\n }\n\n const { ethQuery } = this.#getCorrectNetworkClient(networkClientId);\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 #registerMessageHandlers(): void {\n this.messenger.registerActionHandler(\n `${controllerName}:updateNativeBalances` as const,\n this.updateNativeBalances.bind(this),\n );\n\n this.messenger.registerActionHandler(\n `${controllerName}:updateStakedBalances` as const,\n this.updateStakedBalances.bind(this),\n );\n }\n}\n\nexport default AccountTrackerController;\n"]}
|
|
1
|
+
{"version":3,"file":"AccountTrackerController.mjs","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 { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type {\n TransactionControllerTransactionConfirmedEvent,\n TransactionControllerUnapprovedTransactionAddedEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport { assert } from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\nimport { Mutex } from 'async-mutex';\nimport { cloneDeep, isEqual } from 'lodash';\n\nimport { STAKING_CONTRACT_ADDRESS_BY_CHAINID } from './AssetsContractController';\nimport type {\n AssetsContractController,\n StakedBalance,\n} from './AssetsContractController';\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 action that can be performed to update multiple native token balances in batch.\n */\nexport type AccountTrackerUpdateNativeBalancesAction = {\n type: `${typeof controllerName}:updateNativeBalances`;\n handler: AccountTrackerController['updateNativeBalances'];\n};\n\n/**\n * The action that can be performed to update multiple staked balances in batch.\n */\nexport type AccountTrackerUpdateStakedBalancesAction = {\n type: `${typeof controllerName}:updateStakedBalances`;\n handler: AccountTrackerController['updateStakedBalances'];\n};\n\n/**\n * The actions that can be performed using the {@link AccountTrackerController}.\n */\nexport type AccountTrackerControllerActions =\n | AccountTrackerControllerGetStateAction\n | AccountTrackerUpdateNativeBalancesAction\n | AccountTrackerUpdateStakedBalancesAction;\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 | 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\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 /** 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 */\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 }: {\n interval?: number;\n state?: Partial<AccountTrackerControllerState>;\n messenger: AccountTrackerControllerMessenger;\n getStakedBalanceForChain: AssetsContractController['getStakedBalanceForChain'];\n includeStakedAssets?: boolean;\n accountsApiChainIds?: () => ChainIdHex[];\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\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 });\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 this.#registerMessageHandlers();\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 return Object.values(networkConfigurationsByChainId).flatMap(\n (networkConfiguration) =>\n networkConfiguration.rpcEndpoints.map(\n (rpcEndpoint) => rpcEndpoint.networkClientId,\n ),\n );\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 } = this.#getCorrectNetworkClient(networkClientId);\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 #registerMessageHandlers(): void {\n this.messenger.registerActionHandler(\n `${controllerName}:updateNativeBalances` as const,\n this.updateNativeBalances.bind(this),\n );\n\n this.messenger.registerActionHandler(\n `${controllerName}:updateStakedBalances` as const,\n this.updateStakedBalances.bind(this),\n );\n }\n}\n\nexport default AccountTrackerController;\n"]}
|
|
@@ -33,8 +33,8 @@ type CurrencyRatePollingInput = {
|
|
|
33
33
|
nativeCurrencies: string[];
|
|
34
34
|
};
|
|
35
35
|
declare const CurrencyRateController_base: (abstract new (...args: any[]) => {
|
|
36
|
-
readonly "__#
|
|
37
|
-
"__#
|
|
36
|
+
readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
37
|
+
"__#14@#intervalLength": number | undefined;
|
|
38
38
|
setIntervalLength(intervalLength: number): void;
|
|
39
39
|
getIntervalLength(): number | undefined;
|
|
40
40
|
_startPolling(input: CurrencyRatePollingInput): void;
|
|
@@ -33,8 +33,8 @@ type CurrencyRatePollingInput = {
|
|
|
33
33
|
nativeCurrencies: string[];
|
|
34
34
|
};
|
|
35
35
|
declare const CurrencyRateController_base: (abstract new (...args: any[]) => {
|
|
36
|
-
readonly "__#
|
|
37
|
-
"__#
|
|
36
|
+
readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
37
|
+
"__#14@#intervalLength": number | undefined;
|
|
38
38
|
setIntervalLength(intervalLength: number): void;
|
|
39
39
|
getIntervalLength(): number | undefined;
|
|
40
40
|
_startPolling(input: CurrencyRatePollingInput): void;
|
|
@@ -57,8 +57,8 @@ export type AllowedEvents = KeyringControllerLockEvent | TransactionControllerTr
|
|
|
57
57
|
*/
|
|
58
58
|
export type DeFiPositionsControllerMessenger = Messenger<typeof controllerName, DeFiPositionsControllerActions | AllowedActions, DeFiPositionsControllerEvents | AllowedEvents>;
|
|
59
59
|
declare const DeFiPositionsController_base: (abstract new (...args: any[]) => {
|
|
60
|
-
readonly "__#
|
|
61
|
-
"__#
|
|
60
|
+
readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
61
|
+
"__#14@#intervalLength": number | undefined;
|
|
62
62
|
setIntervalLength(intervalLength: number): void;
|
|
63
63
|
getIntervalLength(): number | undefined;
|
|
64
64
|
_startPolling(input: import("@metamask/utils").Json): void;
|
|
@@ -57,8 +57,8 @@ export type AllowedEvents = KeyringControllerLockEvent | TransactionControllerTr
|
|
|
57
57
|
*/
|
|
58
58
|
export type DeFiPositionsControllerMessenger = Messenger<typeof controllerName, DeFiPositionsControllerActions | AllowedActions, DeFiPositionsControllerEvents | AllowedEvents>;
|
|
59
59
|
declare const DeFiPositionsController_base: (abstract new (...args: any[]) => {
|
|
60
|
-
readonly "__#
|
|
61
|
-
"__#
|
|
60
|
+
readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
61
|
+
"__#14@#intervalLength": number | undefined;
|
|
62
62
|
setIntervalLength(intervalLength: number): void;
|
|
63
63
|
getIntervalLength(): number | undefined;
|
|
64
64
|
_startPolling(input: import("@metamask/utils").Json): void;
|
|
@@ -291,8 +291,14 @@ async function _MultichainAssetsRatesController_getMarketData(snapId, assets, cu
|
|
|
291
291
|
}
|
|
292
292
|
const assetToMarketData = {};
|
|
293
293
|
for (const asset of assets) {
|
|
294
|
-
|
|
295
|
-
|
|
294
|
+
const assetMarketData = response.marketData?.[asset]?.[currency];
|
|
295
|
+
// We do not consider NFTs here, so `fungible` must be `true`.
|
|
296
|
+
if (assetMarketData?.fungible) {
|
|
297
|
+
assetToMarketData[asset] = assetMarketData;
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
assetToMarketData[asset] = undefined;
|
|
301
|
+
}
|
|
296
302
|
}
|
|
297
303
|
return assetToMarketData;
|
|
298
304
|
}, _MultichainAssetsRatesController_getUpdatedRatesFor =
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAssetsRatesController.cjs","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountAddedEvent,\n AccountsControllerGetSelectedMultichainAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { CaipAssetType } from '@metamask/keyring-api';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { Messenger } from '@metamask/messenger';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type {\n SnapId,\n AssetConversion,\n OnAssetsConversionArguments,\n OnAssetHistoricalPriceArguments,\n OnAssetHistoricalPriceResponse,\n HistoricalPriceIntervals,\n OnAssetsMarketDataArguments,\n OnAssetsMarketDataResponse,\n FungibleAssetMarketData,\n OnAssetsConversionResponse,\n} from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Mutex } from 'async-mutex';\nimport type { Draft } from 'immer';\n\nimport { MAP_CAIP_CURRENCIES } from './constant';\nimport type {\n CurrencyRateState,\n CurrencyRateStateChange,\n GetCurrencyRateState,\n} from '../CurrencyRateController';\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerAccountAssetListUpdatedEvent,\n} from '../MultichainAssetsController';\n\n/**\n * The name of the MultichainAssetsRatesController.\n */\nconst controllerName = 'MultichainAssetsRatesController';\n\n// This is temporary until its exported from snap\ntype HistoricalPrice = {\n intervals: HistoricalPriceIntervals;\n // The UNIX timestamp of when the historical price was last updated.\n updateTime: number;\n // The UNIX timestamp of when the historical price will expire.\n expirationTime?: number;\n};\n\n/**\n * State used by the MultichainAssetsRatesController to cache token conversion rates.\n */\nexport type MultichainAssetsRatesControllerState = {\n conversionRates: Record<CaipAssetType, UnifiedAssetConversion>;\n historicalPrices: Record<CaipAssetType, Record<string, HistoricalPrice>>; // string being the current currency we fetched historical prices for\n};\n\n/**\n * Returns the state of the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Action to update the rates of all supported tokens.\n */\nexport type MultichainAssetsRatesControllerUpdateRatesAction = {\n type: `${typeof controllerName}:updateAssetsRates`;\n handler: MultichainAssetsRatesController['updateAssetsRates'];\n};\n\ntype UnifiedAssetConversion = AssetConversion & {\n marketData?: FungibleAssetMarketData;\n};\n\n/**\n * Constructs the default {@link MultichainAssetsRatesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsRatesController} state.\n */\nexport function getDefaultMultichainAssetsRatesControllerState(): MultichainAssetsRatesControllerState {\n return { conversionRates: {}, historicalPrices: {} };\n}\n\n/**\n * Event emitted when the state of the MultichainAssetsRatesController changes.\n */\nexport type MultichainAssetsRatesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Actions exposed by the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerActions =\n | MultichainAssetsRatesControllerGetStateAction\n | MultichainAssetsRatesControllerUpdateRatesAction;\n\n/**\n * Events emitted by MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerEvents =\n MultichainAssetsRatesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\nexport type AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | GetCurrencyRateState\n | MultichainAssetsControllerGetStateAction\n | AccountsControllerGetSelectedMultichainAccountAction;\n\n/**\n * Events that this controller is allowed to subscribe to.\n */\nexport type AllowedEvents =\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | AccountsControllerAccountAddedEvent\n | CurrencyRateStateChange\n | MultichainAssetsControllerAccountAssetListUpdatedEvent;\n/**\n * Messenger type for the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerMessenger = Messenger<\n typeof controllerName,\n MultichainAssetsRatesControllerActions | AllowedActions,\n MultichainAssetsRatesControllerEvents | AllowedEvents\n>;\n\n/**\n * The input for starting polling in MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesPollingInput = {\n accountId: string;\n};\n\nconst metadata: StateMetadata<MultichainAssetsRatesControllerState> = {\n conversionRates: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n historicalPrices: {\n includeInStateLogs: false,\n persist: false,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nexport type ConversionRatesWithMarketData = {\n conversionRates: Record<\n CaipAssetType,\n Record<CaipAssetType, UnifiedAssetConversion | null>\n >;\n};\n\n/**\n * Arguments for a Snap request.\n */\ntype SnapRequestArgs<T> = {\n snapId: SnapId;\n handler: HandlerType;\n params: T;\n};\n\n/**\n * Controller that manages multichain token conversion rates.\n *\n * This controller polls for token conversion rates and updates its state.\n */\nexport class MultichainAssetsRatesController extends StaticIntervalPollingController<MultichainAssetsRatesPollingInput>()<\n typeof controllerName,\n MultichainAssetsRatesControllerState,\n MultichainAssetsRatesControllerMessenger\n> {\n readonly #mutex = new Mutex();\n\n #currentCurrency: CurrencyRateState['currentCurrency'];\n\n #isUnlocked = true;\n\n /**\n * Creates an instance of MultichainAssetsRatesController.\n *\n * @param options - Constructor options.\n * @param options.interval - The polling interval in milliseconds.\n * @param options.state - The initial state.\n * @param options.messenger - A reference to the messenger.\n */\n constructor({\n interval = 18000,\n state = {},\n messenger,\n }: {\n interval?: number;\n state?: Partial<MultichainAssetsRatesControllerState>;\n messenger: MultichainAssetsRatesControllerMessenger;\n }) {\n super({\n name: controllerName,\n messenger,\n state: {\n ...getDefaultMultichainAssetsRatesControllerState(),\n ...state,\n },\n metadata,\n });\n\n this.setIntervalLength(interval);\n\n // Subscribe to keyring lock/unlock events.\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n });\n\n ({ currentCurrency: this.#currentCurrency } = this.messenger.call(\n 'CurrencyRateController:getState',\n ));\n\n this.messenger.subscribe(\n 'CurrencyRateController:stateChange',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (currentCurrency: string) => {\n this.#currentCurrency = currentCurrency;\n await this.updateAssetsRates();\n },\n (currencyRateControllerState) =>\n currencyRateControllerState.currentCurrency,\n );\n\n this.messenger.subscribe(\n 'MultichainAssetsController:accountAssetListUpdated',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ assets }) => {\n const newAccountAssets = Object.entries(assets).map(\n ([accountId, { added }]) => ({\n accountId,\n assets: [...added],\n }),\n );\n // TODO; removed can be used in future for further cleanup\n await this.#updateAssetsRatesForNewAssets(newAccountAssets);\n },\n );\n }\n\n /**\n * Executes a poll by updating token conversion rates for the current account.\n *\n * @returns A promise that resolves when the polling completes.\n */\n async _executePoll(): Promise<void> {\n await this.updateAssetsRates();\n }\n\n /**\n * Determines whether the controller is active.\n *\n * @returns True if the keyring is unlocked; otherwise, false.\n */\n get isActive(): boolean {\n return this.#isUnlocked;\n }\n\n /**\n * Checks if an account is a non-EVM account with a Snap.\n *\n * @param account - The account to check.\n * @returns True if the account is non-EVM and has Snap metadata; otherwise, false.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) && account.metadata.snap !== undefined\n );\n }\n\n /**\n * Retrieves all multichain accounts from the AccountsController.\n *\n * @returns An array of internal accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messenger.call('AccountsController:listMultichainAccounts');\n }\n\n /**\n * Filters and returns non-EVM accounts that should have balances.\n *\n * @returns An array of non-EVM internal accounts.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Adds the assets to a map of Snap ID to assets.\n *\n * @param snapIdToAssets - The map of Snap ID to assets.\n * @param account - The account to add the assets for.\n * @param assets - The assets to add.\n */\n #addAssetsToSnapIdMap(\n snapIdToAssets: Map<SnapId, Set<CaipAssetType>>,\n account: InternalAccount,\n assets: CaipAssetType[],\n ): void {\n // Prevent creating a new set if there are no assets to add.\n if (assets.length === 0) {\n return;\n }\n\n // FIXME: Instead of using the Snap ID from the account, we should\n // select the Snap based on the supported scopes defined in the Snaps'\n // manifest.\n const snapId = account.metadata.snap?.id as SnapId | undefined;\n if (!snapId) {\n return;\n }\n\n let snapAssets = snapIdToAssets.get(snapId);\n if (!snapAssets) {\n snapAssets = new Set();\n snapIdToAssets.set(snapId, snapAssets);\n }\n\n for (const asset of assets) {\n snapAssets.add(asset);\n }\n }\n\n /**\n * Updates token conversion rates for each non-EVM account.\n *\n * @returns A promise that resolves when the rates are updated.\n */\n async updateAssetsRates(): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n\n return (async (): Promise<void> => {\n if (!this.isActive) {\n return;\n }\n\n // Compute the set of unique assets from all accounts. It's important to\n // deduplicate assets here to avoid duplicate requests to the Snap.\n const accounts = this.#listAccounts();\n const snapIdToAssets = new Map<SnapId, Set<CaipAssetType>>();\n for (const account of accounts) {\n this.#addAssetsToSnapIdMap(\n snapIdToAssets,\n account,\n this.#getAssetsForAccount(account.id),\n );\n }\n\n this.#applyUpdatedRates(await this.#getUpdatedRatesFor(snapIdToAssets));\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Returns the CAIP-19 asset type for the current selected currency. Defaults\n * to USD if the current selected currency is not supported.\n *\n * @returns The CAIP-19 asset type for the current selected currency.\n */\n #getCaipCurrentCurrency(): CaipAssetType {\n return (\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd\n );\n }\n\n /**\n * Fetches the conversion rates for the given assets from the given Snap.\n *\n * @param snapId - The ID of the Snap.\n * @param assets - The assets to fetch the conversion rates for.\n * @param currency - The currency to fetch the conversion rates for.\n * @returns A record of CAIP-19 asset types to conversion rates.\n */\n async #getConversionRates(\n snapId: SnapId,\n assets: Set<CaipAssetType>,\n currency: CaipAssetType,\n ): Promise<Record<CaipAssetType, AssetConversion | undefined>> {\n // Prevent making a Snap call if there are no assets to fetch.\n if (assets.size === 0) {\n return {};\n }\n\n const response = await this.#handleSnapRequest({\n snapId,\n handler: HandlerType.OnAssetsConversion,\n params: {\n conversions: Array.from(assets).map((asset) => ({\n from: asset,\n to: currency,\n })),\n },\n });\n\n if (!response) {\n return {};\n }\n\n const assetToConversionRate: Record<\n CaipAssetType,\n AssetConversion | undefined\n > = {};\n\n for (const asset of assets) {\n assetToConversionRate[asset] =\n response.conversionRates?.[asset]?.[currency] ?? undefined;\n }\n\n return assetToConversionRate;\n }\n\n /**\n * Fetches the market data for the given assets from the given Snap.\n *\n * @param snapId - The ID of the Snap.\n * @param assets - The assets to fetch the market data for.\n * @param currency - The currency to fetch the market data for.\n * @returns A record of CAIP-19 asset types to market data.\n */\n async #getMarketData(\n snapId: SnapId,\n assets: Set<CaipAssetType>,\n currency: CaipAssetType,\n ): Promise<Record<CaipAssetType, FungibleAssetMarketData | undefined>> {\n // Prevent making a Snap call if there are no assets to fetch.\n if (assets.size === 0) {\n return {};\n }\n\n const response = await this.#handleSnapRequest({\n snapId,\n handler: HandlerType.OnAssetsMarketData,\n params: {\n assets: Array.from(assets).map((asset) => ({\n asset,\n unit: currency,\n })),\n },\n });\n\n if (!response) {\n return {};\n }\n\n const assetToMarketData: Record<\n CaipAssetType,\n FungibleAssetMarketData | undefined\n > = {};\n\n for (const asset of assets) {\n assetToMarketData[asset] =\n response.marketData?.[asset]?.[currency] ?? undefined;\n }\n\n return assetToMarketData;\n }\n\n /**\n * Fetches the updated rates for the given assets from the given Snaps.\n *\n * @param snapIdToAssets - A map of Snap ID to CAIP-19 asset types.\n * @returns A record of CAIP-19 asset types to unified asset conversions.\n */\n async #getUpdatedRatesFor(\n snapIdToAssets: Map<SnapId, Set<CaipAssetType>>,\n ): Promise<\n Record<CaipAssetType, UnifiedAssetConversion & { currency: CaipAssetType }>\n > {\n const updatedRates: Record<\n CaipAssetType,\n UnifiedAssetConversion & { currency: CaipAssetType }\n > = {};\n\n // Keep a local copy to ensure that the currency is always the same for the\n // entire loop.\n const currency = this.#getCaipCurrentCurrency();\n\n // Note: Since the assets come from a 1-to-1 mapping with Snap IDs, we know\n // that a given asset will not appear under multiple Snap IDs.\n for (const [snapId, assets] of snapIdToAssets.entries()) {\n const [rates, marketData] = await Promise.all([\n this.#getConversionRates(snapId, assets, currency),\n this.#getMarketData(snapId, assets, currency),\n ]);\n\n for (const asset of assets) {\n const assetRate = rates[asset];\n const assetMarketData = marketData[asset];\n\n // Rates are mandatory, so skip the asset if not available.\n if (!assetRate) {\n continue;\n }\n\n updatedRates[asset] = {\n currency,\n ...assetRate,\n ...(assetMarketData && { marketData: assetMarketData }),\n };\n }\n }\n\n return updatedRates;\n }\n\n /**\n * Fetches historical prices for the current account\n *\n * @param asset - The asset to fetch historical prices for.\n * @param account - optional account to fetch historical prices for\n * @returns The historical prices.\n */\n async fetchHistoricalPricesForAsset(\n asset: CaipAssetType,\n account?: InternalAccount,\n ): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n return (async () => {\n const currentCaipCurrency =\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd;\n // Check if we already have historical prices for this asset and currency\n const historicalPriceExpirationTime =\n this.state.historicalPrices[asset]?.[this.#currentCurrency]\n ?.expirationTime;\n\n const historicalPriceHasExpired =\n historicalPriceExpirationTime &&\n historicalPriceExpirationTime < Date.now();\n\n if (historicalPriceHasExpired === false) {\n return;\n }\n\n const selectedAccount =\n account ??\n this.messenger.call('AccountsController:getSelectedMultichainAccount');\n try {\n const historicalPricesResponse = await this.messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: selectedAccount?.metadata.snap?.id as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnAssetHistoricalPrice,\n request: {\n jsonrpc: '2.0',\n method: HandlerType.OnAssetHistoricalPrice,\n params: {\n from: asset,\n to: currentCaipCurrency,\n },\n },\n },\n );\n\n // skip state update if no historical prices are returned\n if (!historicalPricesResponse) {\n return;\n }\n\n this.update((state) => {\n state.historicalPrices = {\n ...state.historicalPrices,\n [asset]: {\n ...state.historicalPrices[asset],\n [this.#currentCurrency]: (\n historicalPricesResponse as OnAssetHistoricalPriceResponse\n )?.historicalPrice,\n },\n };\n });\n } catch {\n throw new Error(\n `Failed to fetch historical prices for asset: ${asset}`,\n );\n }\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Updates the conversion rates for new assets.\n *\n * @param accounts - The accounts to update the conversion rates for.\n * @returns A promise that resolves when the rates are updated.\n */\n async #updateAssetsRatesForNewAssets(\n accounts: {\n accountId: string;\n assets: CaipAssetType[];\n }[],\n ): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n\n return (async () => {\n if (!this.isActive) {\n return;\n }\n\n // First build a map containing all assets that need to be updated per\n // Snap ID, this will be used to batch the requests.\n const snapIdToAssets = new Map<SnapId, Set<CaipAssetType>>();\n\n for (const { accountId, assets } of accounts) {\n this.#addAssetsToSnapIdMap(\n snapIdToAssets,\n this.#getAccount(accountId),\n assets,\n );\n }\n\n this.#applyUpdatedRates(await this.#getUpdatedRatesFor(snapIdToAssets));\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\n }\n\n /**\n * Returns the array of CAIP-19 assets for the given account ID.\n * If none are found, returns an empty array.\n *\n * @param accountId - The account ID to get the assets for.\n * @returns An array of CAIP-19 assets.\n */\n #getAssetsForAccount(accountId: string): CaipAssetType[] {\n // Always fetch fresh state - MultichainAssetsController uses Immer which creates\n // new object references on every update, so caching would become stale.\n const { accountsAssets } = this.messenger.call(\n 'MultichainAssetsController:getState',\n );\n return accountsAssets?.[accountId] ?? [];\n }\n\n /**\n * Merges the new rates into the controller's state.\n *\n * @param updatedRates - The new rates to merge.\n */\n #applyUpdatedRates(\n updatedRates: Record<\n CaipAssetType,\n UnifiedAssetConversion & { currency: CaipAssetType }\n >,\n ): void {\n if (Object.keys(updatedRates).length === 0) {\n return;\n }\n this.update((state: Draft<MultichainAssetsRatesControllerState>) => {\n state.conversionRates = {\n ...state.conversionRates,\n ...updatedRates,\n };\n });\n }\n\n /**\n * Forwards a Snap request to the SnapController.\n *\n * @param args - The request parameters.\n * @param args.snapId - The ID of the Snap.\n * @param args.handler - The handler type.\n * @param args.params - The asset conversions.\n * @returns A promise that resolves with the account rates.\n */\n async #handleSnapRequest(\n args: SnapRequestArgs<OnAssetsConversionArguments>,\n ): Promise<OnAssetsConversionResponse | undefined>;\n\n async #handleSnapRequest(\n args: SnapRequestArgs<OnAssetHistoricalPriceArguments>,\n ): Promise<OnAssetHistoricalPriceResponse | undefined>;\n\n async #handleSnapRequest(\n args: SnapRequestArgs<OnAssetsMarketDataArguments>,\n ): Promise<OnAssetsMarketDataResponse | undefined>;\n\n async #handleSnapRequest(args: SnapRequestArgs<unknown>): Promise<unknown> {\n const { snapId, handler, params } = args;\n try {\n return await this.messenger.call('SnapController:handleRequest', {\n snapId,\n origin: 'metamask',\n handler,\n request: {\n jsonrpc: '2.0',\n method: handler,\n params,\n },\n });\n } catch (error) {\n console.error(`Snap request failed for ${handler}:`, {\n snapId,\n handler,\n message: (error as Error).message,\n params,\n });\n return undefined;\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"MultichainAssetsRatesController.cjs","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AccountsControllerListMultichainAccountsAction,\n AccountsControllerAccountAddedEvent,\n AccountsControllerGetSelectedMultichainAccountAction,\n} from '@metamask/accounts-controller';\nimport type {\n ControllerStateChangeEvent,\n ControllerGetStateAction,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { isEvmAccountType } from '@metamask/keyring-api';\nimport type { CaipAssetType } from '@metamask/keyring-api';\nimport type {\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { Messenger } from '@metamask/messenger';\nimport { StaticIntervalPollingController } from '@metamask/polling-controller';\nimport type { HandleSnapRequest } from '@metamask/snaps-controllers';\nimport type {\n SnapId,\n AssetConversion,\n OnAssetsConversionArguments,\n OnAssetHistoricalPriceArguments,\n OnAssetHistoricalPriceResponse,\n HistoricalPriceIntervals,\n OnAssetsMarketDataArguments,\n OnAssetsMarketDataResponse,\n FungibleAssetMarketData,\n OnAssetsConversionResponse,\n} from '@metamask/snaps-sdk';\nimport { HandlerType } from '@metamask/snaps-utils';\nimport { Mutex } from 'async-mutex';\nimport type { Draft } from 'immer';\n\nimport { MAP_CAIP_CURRENCIES } from './constant';\nimport type {\n CurrencyRateState,\n CurrencyRateStateChange,\n GetCurrencyRateState,\n} from '../CurrencyRateController';\nimport type {\n MultichainAssetsControllerGetStateAction,\n MultichainAssetsControllerAccountAssetListUpdatedEvent,\n} from '../MultichainAssetsController';\n\n/**\n * The name of the MultichainAssetsRatesController.\n */\nconst controllerName = 'MultichainAssetsRatesController';\n\n// This is temporary until its exported from snap\ntype HistoricalPrice = {\n intervals: HistoricalPriceIntervals;\n // The UNIX timestamp of when the historical price was last updated.\n updateTime: number;\n // The UNIX timestamp of when the historical price will expire.\n expirationTime?: number;\n};\n\n/**\n * State used by the MultichainAssetsRatesController to cache token conversion rates.\n */\nexport type MultichainAssetsRatesControllerState = {\n conversionRates: Record<CaipAssetType, UnifiedAssetConversion>;\n historicalPrices: Record<CaipAssetType, Record<string, HistoricalPrice>>; // string being the current currency we fetched historical prices for\n};\n\n/**\n * Returns the state of the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Action to update the rates of all supported tokens.\n */\nexport type MultichainAssetsRatesControllerUpdateRatesAction = {\n type: `${typeof controllerName}:updateAssetsRates`;\n handler: MultichainAssetsRatesController['updateAssetsRates'];\n};\n\ntype UnifiedAssetConversion = AssetConversion & {\n marketData?: FungibleAssetMarketData;\n};\n\n/**\n * Constructs the default {@link MultichainAssetsRatesController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link MultichainAssetsRatesController} state.\n */\nexport function getDefaultMultichainAssetsRatesControllerState(): MultichainAssetsRatesControllerState {\n return { conversionRates: {}, historicalPrices: {} };\n}\n\n/**\n * Event emitted when the state of the MultichainAssetsRatesController changes.\n */\nexport type MultichainAssetsRatesControllerStateChange =\n ControllerStateChangeEvent<\n typeof controllerName,\n MultichainAssetsRatesControllerState\n >;\n\n/**\n * Actions exposed by the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerActions =\n | MultichainAssetsRatesControllerGetStateAction\n | MultichainAssetsRatesControllerUpdateRatesAction;\n\n/**\n * Events emitted by MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerEvents =\n MultichainAssetsRatesControllerStateChange;\n\n/**\n * Actions that this controller is allowed to call.\n */\nexport type AllowedActions =\n | HandleSnapRequest\n | AccountsControllerListMultichainAccountsAction\n | GetCurrencyRateState\n | MultichainAssetsControllerGetStateAction\n | AccountsControllerGetSelectedMultichainAccountAction;\n\n/**\n * Events that this controller is allowed to subscribe to.\n */\nexport type AllowedEvents =\n | KeyringControllerLockEvent\n | KeyringControllerUnlockEvent\n | AccountsControllerAccountAddedEvent\n | CurrencyRateStateChange\n | MultichainAssetsControllerAccountAssetListUpdatedEvent;\n/**\n * Messenger type for the MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesControllerMessenger = Messenger<\n typeof controllerName,\n MultichainAssetsRatesControllerActions | AllowedActions,\n MultichainAssetsRatesControllerEvents | AllowedEvents\n>;\n\n/**\n * The input for starting polling in MultichainAssetsRatesController.\n */\nexport type MultichainAssetsRatesPollingInput = {\n accountId: string;\n};\n\nconst metadata: StateMetadata<MultichainAssetsRatesControllerState> = {\n conversionRates: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n historicalPrices: {\n includeInStateLogs: false,\n persist: false,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n};\n\nexport type ConversionRatesWithMarketData = {\n conversionRates: Record<\n CaipAssetType,\n Record<CaipAssetType, UnifiedAssetConversion | null>\n >;\n};\n\n/**\n * Arguments for a Snap request.\n */\ntype SnapRequestArgs<T> = {\n snapId: SnapId;\n handler: HandlerType;\n params: T;\n};\n\n/**\n * Controller that manages multichain token conversion rates.\n *\n * This controller polls for token conversion rates and updates its state.\n */\nexport class MultichainAssetsRatesController extends StaticIntervalPollingController<MultichainAssetsRatesPollingInput>()<\n typeof controllerName,\n MultichainAssetsRatesControllerState,\n MultichainAssetsRatesControllerMessenger\n> {\n readonly #mutex = new Mutex();\n\n #currentCurrency: CurrencyRateState['currentCurrency'];\n\n #isUnlocked = true;\n\n /**\n * Creates an instance of MultichainAssetsRatesController.\n *\n * @param options - Constructor options.\n * @param options.interval - The polling interval in milliseconds.\n * @param options.state - The initial state.\n * @param options.messenger - A reference to the messenger.\n */\n constructor({\n interval = 18000,\n state = {},\n messenger,\n }: {\n interval?: number;\n state?: Partial<MultichainAssetsRatesControllerState>;\n messenger: MultichainAssetsRatesControllerMessenger;\n }) {\n super({\n name: controllerName,\n messenger,\n state: {\n ...getDefaultMultichainAssetsRatesControllerState(),\n ...state,\n },\n metadata,\n });\n\n this.setIntervalLength(interval);\n\n // Subscribe to keyring lock/unlock events.\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n });\n\n ({ currentCurrency: this.#currentCurrency } = this.messenger.call(\n 'CurrencyRateController:getState',\n ));\n\n this.messenger.subscribe(\n 'CurrencyRateController:stateChange',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async (currentCurrency: string) => {\n this.#currentCurrency = currentCurrency;\n await this.updateAssetsRates();\n },\n (currencyRateControllerState) =>\n currencyRateControllerState.currentCurrency,\n );\n\n this.messenger.subscribe(\n 'MultichainAssetsController:accountAssetListUpdated',\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n async ({ assets }) => {\n const newAccountAssets = Object.entries(assets).map(\n ([accountId, { added }]) => ({\n accountId,\n assets: [...added],\n }),\n );\n // TODO; removed can be used in future for further cleanup\n await this.#updateAssetsRatesForNewAssets(newAccountAssets);\n },\n );\n }\n\n /**\n * Executes a poll by updating token conversion rates for the current account.\n *\n * @returns A promise that resolves when the polling completes.\n */\n async _executePoll(): Promise<void> {\n await this.updateAssetsRates();\n }\n\n /**\n * Determines whether the controller is active.\n *\n * @returns True if the keyring is unlocked; otherwise, false.\n */\n get isActive(): boolean {\n return this.#isUnlocked;\n }\n\n /**\n * Checks if an account is a non-EVM account with a Snap.\n *\n * @param account - The account to check.\n * @returns True if the account is non-EVM and has Snap metadata; otherwise, false.\n */\n #isNonEvmAccount(account: InternalAccount): boolean {\n return (\n !isEvmAccountType(account.type) && account.metadata.snap !== undefined\n );\n }\n\n /**\n * Retrieves all multichain accounts from the AccountsController.\n *\n * @returns An array of internal accounts.\n */\n #listMultichainAccounts(): InternalAccount[] {\n return this.messenger.call('AccountsController:listMultichainAccounts');\n }\n\n /**\n * Filters and returns non-EVM accounts that should have balances.\n *\n * @returns An array of non-EVM internal accounts.\n */\n #listAccounts(): InternalAccount[] {\n const accounts = this.#listMultichainAccounts();\n return accounts.filter((account) => this.#isNonEvmAccount(account));\n }\n\n /**\n * Adds the assets to a map of Snap ID to assets.\n *\n * @param snapIdToAssets - The map of Snap ID to assets.\n * @param account - The account to add the assets for.\n * @param assets - The assets to add.\n */\n #addAssetsToSnapIdMap(\n snapIdToAssets: Map<SnapId, Set<CaipAssetType>>,\n account: InternalAccount,\n assets: CaipAssetType[],\n ): void {\n // Prevent creating a new set if there are no assets to add.\n if (assets.length === 0) {\n return;\n }\n\n // FIXME: Instead of using the Snap ID from the account, we should\n // select the Snap based on the supported scopes defined in the Snaps'\n // manifest.\n const snapId = account.metadata.snap?.id as SnapId | undefined;\n if (!snapId) {\n return;\n }\n\n let snapAssets = snapIdToAssets.get(snapId);\n if (!snapAssets) {\n snapAssets = new Set();\n snapIdToAssets.set(snapId, snapAssets);\n }\n\n for (const asset of assets) {\n snapAssets.add(asset);\n }\n }\n\n /**\n * Updates token conversion rates for each non-EVM account.\n *\n * @returns A promise that resolves when the rates are updated.\n */\n async updateAssetsRates(): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n\n return (async (): Promise<void> => {\n if (!this.isActive) {\n return;\n }\n\n // Compute the set of unique assets from all accounts. It's important to\n // deduplicate assets here to avoid duplicate requests to the Snap.\n const accounts = this.#listAccounts();\n const snapIdToAssets = new Map<SnapId, Set<CaipAssetType>>();\n for (const account of accounts) {\n this.#addAssetsToSnapIdMap(\n snapIdToAssets,\n account,\n this.#getAssetsForAccount(account.id),\n );\n }\n\n this.#applyUpdatedRates(await this.#getUpdatedRatesFor(snapIdToAssets));\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Returns the CAIP-19 asset type for the current selected currency. Defaults\n * to USD if the current selected currency is not supported.\n *\n * @returns The CAIP-19 asset type for the current selected currency.\n */\n #getCaipCurrentCurrency(): CaipAssetType {\n return (\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd\n );\n }\n\n /**\n * Fetches the conversion rates for the given assets from the given Snap.\n *\n * @param snapId - The ID of the Snap.\n * @param assets - The assets to fetch the conversion rates for.\n * @param currency - The currency to fetch the conversion rates for.\n * @returns A record of CAIP-19 asset types to conversion rates.\n */\n async #getConversionRates(\n snapId: SnapId,\n assets: Set<CaipAssetType>,\n currency: CaipAssetType,\n ): Promise<Record<CaipAssetType, AssetConversion | undefined>> {\n // Prevent making a Snap call if there are no assets to fetch.\n if (assets.size === 0) {\n return {};\n }\n\n const response = await this.#handleSnapRequest({\n snapId,\n handler: HandlerType.OnAssetsConversion,\n params: {\n conversions: Array.from(assets).map((asset) => ({\n from: asset,\n to: currency,\n })),\n },\n });\n\n if (!response) {\n return {};\n }\n\n const assetToConversionRate: Record<\n CaipAssetType,\n AssetConversion | undefined\n > = {};\n\n for (const asset of assets) {\n assetToConversionRate[asset] =\n response.conversionRates?.[asset]?.[currency] ?? undefined;\n }\n\n return assetToConversionRate;\n }\n\n /**\n * Fetches the market data for the given assets from the given Snap.\n *\n * @param snapId - The ID of the Snap.\n * @param assets - The assets to fetch the market data for.\n * @param currency - The currency to fetch the market data for.\n * @returns A record of CAIP-19 asset types to market data.\n */\n async #getMarketData(\n snapId: SnapId,\n assets: Set<CaipAssetType>,\n currency: CaipAssetType,\n ): Promise<Record<CaipAssetType, FungibleAssetMarketData | undefined>> {\n // Prevent making a Snap call if there are no assets to fetch.\n if (assets.size === 0) {\n return {};\n }\n\n const response = await this.#handleSnapRequest({\n snapId,\n handler: HandlerType.OnAssetsMarketData,\n params: {\n assets: Array.from(assets).map((asset) => ({\n asset,\n unit: currency,\n })),\n },\n });\n\n if (!response) {\n return {};\n }\n\n const assetToMarketData: Record<\n CaipAssetType,\n FungibleAssetMarketData | undefined\n > = {};\n\n for (const asset of assets) {\n const assetMarketData = response.marketData?.[asset]?.[currency];\n\n // We do not consider NFTs here, so `fungible` must be `true`.\n if (assetMarketData?.fungible) {\n assetToMarketData[asset] = assetMarketData;\n } else {\n assetToMarketData[asset] = undefined;\n }\n }\n\n return assetToMarketData;\n }\n\n /**\n * Fetches the updated rates for the given assets from the given Snaps.\n *\n * @param snapIdToAssets - A map of Snap ID to CAIP-19 asset types.\n * @returns A record of CAIP-19 asset types to unified asset conversions.\n */\n async #getUpdatedRatesFor(\n snapIdToAssets: Map<SnapId, Set<CaipAssetType>>,\n ): Promise<\n Record<CaipAssetType, UnifiedAssetConversion & { currency: CaipAssetType }>\n > {\n const updatedRates: Record<\n CaipAssetType,\n UnifiedAssetConversion & { currency: CaipAssetType }\n > = {};\n\n // Keep a local copy to ensure that the currency is always the same for the\n // entire loop.\n const currency = this.#getCaipCurrentCurrency();\n\n // Note: Since the assets come from a 1-to-1 mapping with Snap IDs, we know\n // that a given asset will not appear under multiple Snap IDs.\n for (const [snapId, assets] of snapIdToAssets.entries()) {\n const [rates, marketData] = await Promise.all([\n this.#getConversionRates(snapId, assets, currency),\n this.#getMarketData(snapId, assets, currency),\n ]);\n\n for (const asset of assets) {\n const assetRate = rates[asset];\n const assetMarketData = marketData[asset];\n\n // Rates are mandatory, so skip the asset if not available.\n if (!assetRate) {\n continue;\n }\n\n updatedRates[asset] = {\n currency,\n ...assetRate,\n ...(assetMarketData && { marketData: assetMarketData }),\n };\n }\n }\n\n return updatedRates;\n }\n\n /**\n * Fetches historical prices for the current account\n *\n * @param asset - The asset to fetch historical prices for.\n * @param account - optional account to fetch historical prices for\n * @returns The historical prices.\n */\n async fetchHistoricalPricesForAsset(\n asset: CaipAssetType,\n account?: InternalAccount,\n ): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n return (async () => {\n const currentCaipCurrency =\n MAP_CAIP_CURRENCIES[this.#currentCurrency] ?? MAP_CAIP_CURRENCIES.usd;\n // Check if we already have historical prices for this asset and currency\n const historicalPriceExpirationTime =\n this.state.historicalPrices[asset]?.[this.#currentCurrency]\n ?.expirationTime;\n\n const historicalPriceHasExpired =\n historicalPriceExpirationTime &&\n historicalPriceExpirationTime < Date.now();\n\n if (historicalPriceHasExpired === false) {\n return;\n }\n\n const selectedAccount =\n account ??\n this.messenger.call('AccountsController:getSelectedMultichainAccount');\n try {\n const historicalPricesResponse = await this.messenger.call(\n 'SnapController:handleRequest',\n {\n snapId: selectedAccount?.metadata.snap?.id as SnapId,\n origin: 'metamask',\n handler: HandlerType.OnAssetHistoricalPrice,\n request: {\n jsonrpc: '2.0',\n method: HandlerType.OnAssetHistoricalPrice,\n params: {\n from: asset,\n to: currentCaipCurrency,\n },\n },\n },\n );\n\n // skip state update if no historical prices are returned\n if (!historicalPricesResponse) {\n return;\n }\n\n this.update((state) => {\n state.historicalPrices = {\n ...state.historicalPrices,\n [asset]: {\n ...state.historicalPrices[asset],\n [this.#currentCurrency]: (\n historicalPricesResponse as OnAssetHistoricalPriceResponse\n )?.historicalPrice,\n },\n };\n });\n } catch {\n throw new Error(\n `Failed to fetch historical prices for asset: ${asset}`,\n );\n }\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Updates the conversion rates for new assets.\n *\n * @param accounts - The accounts to update the conversion rates for.\n * @returns A promise that resolves when the rates are updated.\n */\n async #updateAssetsRatesForNewAssets(\n accounts: {\n accountId: string;\n assets: CaipAssetType[];\n }[],\n ): Promise<void> {\n const releaseLock = await this.#mutex.acquire();\n\n return (async () => {\n if (!this.isActive) {\n return;\n }\n\n // First build a map containing all assets that need to be updated per\n // Snap ID, this will be used to batch the requests.\n const snapIdToAssets = new Map<SnapId, Set<CaipAssetType>>();\n\n for (const { accountId, assets } of accounts) {\n this.#addAssetsToSnapIdMap(\n snapIdToAssets,\n this.#getAccount(accountId),\n assets,\n );\n }\n\n this.#applyUpdatedRates(await this.#getUpdatedRatesFor(snapIdToAssets));\n })().finally(() => {\n releaseLock();\n });\n }\n\n /**\n * Get a non-EVM account from its ID.\n *\n * @param accountId - The account ID.\n * @returns The non-EVM account.\n */\n #getAccount(accountId: string): InternalAccount {\n const account: InternalAccount | undefined = this.#listAccounts().find(\n (multichainAccount) => multichainAccount.id === accountId,\n );\n\n if (!account) {\n throw new Error(`Unknown account: ${accountId}`);\n }\n\n return account;\n }\n\n /**\n * Returns the array of CAIP-19 assets for the given account ID.\n * If none are found, returns an empty array.\n *\n * @param accountId - The account ID to get the assets for.\n * @returns An array of CAIP-19 assets.\n */\n #getAssetsForAccount(accountId: string): CaipAssetType[] {\n // Always fetch fresh state - MultichainAssetsController uses Immer which creates\n // new object references on every update, so caching would become stale.\n const { accountsAssets } = this.messenger.call(\n 'MultichainAssetsController:getState',\n );\n return accountsAssets?.[accountId] ?? [];\n }\n\n /**\n * Merges the new rates into the controller's state.\n *\n * @param updatedRates - The new rates to merge.\n */\n #applyUpdatedRates(\n updatedRates: Record<\n CaipAssetType,\n UnifiedAssetConversion & { currency: CaipAssetType }\n >,\n ): void {\n if (Object.keys(updatedRates).length === 0) {\n return;\n }\n this.update((state: Draft<MultichainAssetsRatesControllerState>) => {\n state.conversionRates = {\n ...state.conversionRates,\n ...updatedRates,\n };\n });\n }\n\n /**\n * Forwards a Snap request to the SnapController.\n *\n * @param args - The request parameters.\n * @param args.snapId - The ID of the Snap.\n * @param args.handler - The handler type.\n * @param args.params - The asset conversions.\n * @returns A promise that resolves with the account rates.\n */\n async #handleSnapRequest(\n args: SnapRequestArgs<OnAssetsConversionArguments>,\n ): Promise<OnAssetsConversionResponse | undefined>;\n\n async #handleSnapRequest(\n args: SnapRequestArgs<OnAssetHistoricalPriceArguments>,\n ): Promise<OnAssetHistoricalPriceResponse | undefined>;\n\n async #handleSnapRequest(\n args: SnapRequestArgs<OnAssetsMarketDataArguments>,\n ): Promise<OnAssetsMarketDataResponse | undefined>;\n\n async #handleSnapRequest(args: SnapRequestArgs<unknown>): Promise<unknown> {\n const { snapId, handler, params } = args;\n try {\n return await this.messenger.call('SnapController:handleRequest', {\n snapId,\n origin: 'metamask',\n handler,\n request: {\n jsonrpc: '2.0',\n method: handler,\n params,\n },\n });\n } catch (error) {\n console.error(`Snap request failed for ${handler}:`, {\n snapId,\n handler,\n message: (error as Error).message,\n params,\n });\n return undefined;\n }\n }\n}\n"]}
|
|
@@ -81,8 +81,8 @@ export type ConversionRatesWithMarketData = {
|
|
|
81
81
|
conversionRates: Record<CaipAssetType, Record<CaipAssetType, UnifiedAssetConversion | null>>;
|
|
82
82
|
};
|
|
83
83
|
declare const MultichainAssetsRatesController_base: (abstract new (...args: any[]) => {
|
|
84
|
-
readonly "__#
|
|
85
|
-
"__#
|
|
84
|
+
readonly "__#14@#intervalIds": Record<string, NodeJS.Timeout>;
|
|
85
|
+
"__#14@#intervalLength": number | undefined;
|
|
86
86
|
setIntervalLength(intervalLength: number): void;
|
|
87
87
|
getIntervalLength(): number | undefined;
|
|
88
88
|
_startPolling(input: MultichainAssetsRatesPollingInput): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultichainAssetsRatesController.d.cts","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"MultichainAssetsRatesController.d.cts","sourceRoot":"","sources":["../../src/MultichainAssetsRatesController/MultichainAssetsRatesController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8CAA8C,EAC9C,mCAAmC,EACnC,oDAAoD,EACrD,sCAAsC;AACvC,OAAO,KAAK,EACV,0BAA0B,EAC1B,wBAAwB,EAEzB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,aAAa,EAAE,8BAA8B;AAC3D,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,qCAAqC;AACtC,OAAO,KAAK,EAAE,eAAe,EAAE,uCAAuC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,oCAAoC;AACrE,OAAO,KAAK,EAEV,eAAe,EAIf,wBAAwB,EAGxB,uBAAuB,EAExB,4BAA4B;AAM7B,OAAO,KAAK,EAEV,uBAAuB,EACvB,oBAAoB,EACrB,sCAAkC;AACnC,OAAO,KAAK,EACV,wCAAwC,EACxC,sDAAsD,EACvD,gDAAsC;AAEvC;;GAEG;AACH,QAAA,MAAM,cAAc,oCAAoC,CAAC;AAGzD,KAAK,eAAe,GAAG;IACrB,SAAS,EAAE,wBAAwB,CAAC;IAEpC,UAAU,EAAE,MAAM,CAAC;IAEnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD,eAAe,EAAE,MAAM,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;IAC/D,gBAAgB,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;CAC1E,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,6CAA6C,GACvD,wBAAwB,CACtB,OAAO,cAAc,EACrB,oCAAoC,CACrC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,gDAAgD,GAAG;IAC7D,IAAI,EAAE,GAAG,OAAO,cAAc,oBAAoB,CAAC;IACnD,OAAO,EAAE,+BAA+B,CAAC,mBAAmB,CAAC,CAAC;CAC/D,CAAC;AAEF,KAAK,sBAAsB,GAAG,eAAe,GAAG;IAC9C,UAAU,CAAC,EAAE,uBAAuB,CAAC;CACtC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,8CAA8C,IAAI,oCAAoC,CAErG;AAED;;GAEG;AACH,MAAM,MAAM,0CAA0C,GACpD,0BAA0B,CACxB,OAAO,cAAc,EACrB,oCAAoC,CACrC,CAAC;AAEJ;;GAEG;AACH,MAAM,MAAM,sCAAsC,GAC9C,6CAA6C,GAC7C,gDAAgD,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAC/C,0CAA0C,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,iBAAiB,GACjB,8CAA8C,GAC9C,oBAAoB,GACpB,wCAAwC,GACxC,oDAAoD,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,0BAA0B,GAC1B,4BAA4B,GAC5B,mCAAmC,GACnC,uBAAuB,GACvB,sDAAsD,CAAC;AAC3D;;GAEG;AACH,MAAM,MAAM,wCAAwC,GAAG,SAAS,CAC9D,OAAO,cAAc,EACrB,sCAAsC,GAAG,cAAc,EACvD,qCAAqC,GAAG,aAAa,CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAiBF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,eAAe,EAAE,MAAM,CACrB,aAAa,EACb,MAAM,CAAC,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAC,CACrD,CAAC;CACH,CAAC;;;;;;;;;;;;;;;;AAWF;;;;GAIG;AACH,qBAAa,+BAAgC,SAAQ,qCACnD,OAAO,cAAc,EACrB,oCAAoC,EACpC,wCAAwC,CACzC;;IAOC;;;;;;;OAOG;gBACS,EACV,QAAgB,EAChB,KAAU,EACV,SAAS,GACV,EAAE;QACD,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC,oCAAoC,CAAC,CAAC;QACtD,SAAS,EAAE,wCAAwC,CAAC;KACrD;IAoDD;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAInC;;;;OAIG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAqED;;;;OAIG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwLxC;;;;;;OAMG;IACG,6BAA6B,CACjC,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC;CA0MjB"}
|