@metamask-previews/assets-controller 1.0.0-preview-1ad6631 → 1.0.0-preview-e7b1aa6
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 +0 -1
- package/dist/AssetsController-method-action-types.cjs.map +1 -1
- package/dist/AssetsController-method-action-types.d.cts +1 -26
- package/dist/AssetsController-method-action-types.d.cts.map +1 -1
- package/dist/AssetsController-method-action-types.d.mts +1 -26
- package/dist/AssetsController-method-action-types.d.mts.map +1 -1
- package/dist/AssetsController-method-action-types.mjs.map +1 -1
- package/dist/AssetsController.cjs +9 -84
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +2 -47
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +2 -47
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +9 -84
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/RpcDataSource.cjs +4 -117
- package/dist/data-sources/RpcDataSource.cjs.map +1 -1
- package/dist/data-sources/RpcDataSource.d.cts +0 -14
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
- package/dist/data-sources/RpcDataSource.d.mts +0 -14
- package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
- package/dist/data-sources/RpcDataSource.mjs +4 -117
- package/dist/data-sources/RpcDataSource.mjs.map +1 -1
- package/dist/data-sources/TokenDataSource.cjs +0 -5
- package/dist/data-sources/TokenDataSource.cjs.map +1 -1
- package/dist/data-sources/TokenDataSource.d.cts.map +1 -1
- package/dist/data-sources/TokenDataSource.d.mts.map +1 -1
- package/dist/data-sources/TokenDataSource.mjs +0 -5
- package/dist/data-sources/TokenDataSource.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/index.cjs +1 -5
- package/dist/data-sources/evm-rpc-services/index.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/index.d.cts +1 -1
- package/dist/data-sources/evm-rpc-services/index.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/index.d.mts +1 -1
- package/dist/data-sources/evm-rpc-services/index.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/index.mjs +1 -1
- package/dist/data-sources/evm-rpc-services/index.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.cjs +1 -6
- package/dist/data-sources/evm-rpc-services/services/index.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.d.cts +0 -1
- package/dist/data-sources/evm-rpc-services/services/index.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.d.mts +0 -1
- package/dist/data-sources/evm-rpc-services/services/index.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.mjs +0 -1
- package/dist/data-sources/evm-rpc-services/services/index.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/utils/index.cjs +1 -9
- package/dist/data-sources/evm-rpc-services/utils/index.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/utils/index.d.cts +0 -2
- package/dist/data-sources/evm-rpc-services/utils/index.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/utils/index.d.mts +0 -2
- package/dist/data-sources/evm-rpc-services/utils/index.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/utils/index.mjs +0 -2
- package/dist/data-sources/evm-rpc-services/utils/index.mjs.map +1 -1
- package/dist/data-sources/index.cjs +1 -3
- package/dist/data-sources/index.cjs.map +1 -1
- package/dist/data-sources/index.d.cts +0 -1
- package/dist/data-sources/index.d.cts.map +1 -1
- package/dist/data-sources/index.d.mts +0 -1
- package/dist/data-sources/index.d.mts.map +1 -1
- package/dist/data-sources/index.mjs +0 -1
- package/dist/data-sources/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/data-sources/StakedBalanceDataSource.cjs +0 -536
- package/dist/data-sources/StakedBalanceDataSource.cjs.map +0 -1
- package/dist/data-sources/StakedBalanceDataSource.d.cts +0 -72
- package/dist/data-sources/StakedBalanceDataSource.d.cts.map +0 -1
- package/dist/data-sources/StakedBalanceDataSource.d.mts +0 -72
- package/dist/data-sources/StakedBalanceDataSource.d.mts.map +0 -1
- package/dist/data-sources/StakedBalanceDataSource.mjs +0 -532
- package/dist/data-sources/StakedBalanceDataSource.mjs.map +0 -1
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.cjs +0 -133
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.cjs.map +0 -1
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.cts +0 -78
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.cts.map +0 -1
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.mts +0 -78
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.d.mts.map +0 -1
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.mjs +0 -127
- package/dist/data-sources/evm-rpc-services/services/StakedBalanceFetcher.mjs.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/parsing.cjs +0 -34
- package/dist/data-sources/evm-rpc-services/utils/parsing.cjs.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/parsing.d.cts +0 -18
- package/dist/data-sources/evm-rpc-services/utils/parsing.d.cts.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/parsing.d.mts +0 -18
- package/dist/data-sources/evm-rpc-services/utils/parsing.d.mts.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/parsing.mjs +0 -29
- package/dist/data-sources/evm-rpc-services/utils/parsing.mjs.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.cjs +0 -50
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.cjs.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.cts +0 -24
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.cts.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.mts +0 -24
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.d.mts.map +0 -1
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.mjs +0 -44
- package/dist/data-sources/evm-rpc-services/utils/staking-contracts.mjs.map +0 -1
|
@@ -1,532 +0,0 @@
|
|
|
1
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
-
};
|
|
7
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
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
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
-
};
|
|
12
|
-
var _StakedBalanceDataSource_instances, _StakedBalanceDataSource_messenger, _StakedBalanceDataSource_onActiveChainsUpdated, _StakedBalanceDataSource_pollInterval, _StakedBalanceDataSource_enabled, _StakedBalanceDataSource_stakedBalanceFetcher, _StakedBalanceDataSource_activeSubscriptions, _StakedBalanceDataSource_providerCache, _StakedBalanceDataSource_supportedHexChains, _StakedBalanceDataSource_unsubscribeTransactionConfirmed, _StakedBalanceDataSource_unsubscribeIncomingTransactions, _StakedBalanceDataSource_unsubscribeNetworkStateChange, _StakedBalanceDataSource_onNetworkStateChange, _StakedBalanceDataSource_onTransactionConfirmed, _StakedBalanceDataSource_onIncomingTransactions, _StakedBalanceDataSource_getToRefreshForChains, _StakedBalanceDataSource_getToRefreshAll, _StakedBalanceDataSource_refreshStakedBalanceAfterTransaction, _StakedBalanceDataSource_initializeActiveChains, _StakedBalanceDataSource_getSupportedChains, _StakedBalanceDataSource_getProvider, _StakedBalanceDataSource_handleStakedBalanceUpdate;
|
|
13
|
-
import { toChecksumAddress } from "@ethereumjs/util";
|
|
14
|
-
import { Web3Provider } from "@ethersproject/providers";
|
|
15
|
-
import { isStrictHexString, isCaipChainId, parseCaipChainId } from "@metamask/utils";
|
|
16
|
-
import { AbstractDataSource } from "./AbstractDataSource.mjs";
|
|
17
|
-
import { StakedBalanceFetcher, getStakingContractAddress, getSupportedStakingChainIds } from "./evm-rpc-services/index.mjs";
|
|
18
|
-
import { projectLogger, createModuleLogger } from "../logger.mjs";
|
|
19
|
-
const CONTROLLER_NAME = 'StakedBalanceDataSource';
|
|
20
|
-
const DEFAULT_POLL_INTERVAL = 180000; // 3 minutes
|
|
21
|
-
/** Metadata for staked ETH (same symbol and decimals as native ETH). */
|
|
22
|
-
const STAKED_ETH_METADATA = {
|
|
23
|
-
type: 'erc20',
|
|
24
|
-
name: 'staked ethereum',
|
|
25
|
-
symbol: 'ETH',
|
|
26
|
-
decimals: 18,
|
|
27
|
-
};
|
|
28
|
-
const log = createModuleLogger(projectLogger, CONTROLLER_NAME);
|
|
29
|
-
/**
|
|
30
|
-
* Convert CAIP chain ID or hex chain ID to hex chain ID.
|
|
31
|
-
*
|
|
32
|
-
* @param chainId - CAIP chain ID or hex chain ID.
|
|
33
|
-
* @returns Hex chain ID.
|
|
34
|
-
*/
|
|
35
|
-
function caipChainIdToHex(chainId) {
|
|
36
|
-
if (isStrictHexString(chainId)) {
|
|
37
|
-
return chainId;
|
|
38
|
-
}
|
|
39
|
-
if (isCaipChainId(chainId)) {
|
|
40
|
-
const ref = parseCaipChainId(chainId).reference;
|
|
41
|
-
return `0x${parseInt(ref, 10).toString(16)}`;
|
|
42
|
-
}
|
|
43
|
-
throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Build the CAIP-19 asset ID for staked balance (same format as ERC20).
|
|
47
|
-
* Uses the staking contract address (checksummed) so it is consistent with
|
|
48
|
-
* other token assets.
|
|
49
|
-
* Example: "eip155:1/erc20:0x4fef9d741011476750a243ac70b9789a63dd47df"
|
|
50
|
-
*
|
|
51
|
-
* @param chainId - CAIP-2 chain ID (e.g. "eip155:1").
|
|
52
|
-
* @param contractAddress - Staking contract address (hex).
|
|
53
|
-
* @returns The staked asset CAIP-19 ID with checksummed address.
|
|
54
|
-
*/
|
|
55
|
-
function stakedAssetId(chainId, contractAddress) {
|
|
56
|
-
const checksummed = toChecksumAddress(contractAddress);
|
|
57
|
-
return `${chainId}/erc20:${checksummed}`;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Data source for fetching staked ETH balances via on-chain staking contracts.
|
|
61
|
-
*
|
|
62
|
-
* Delegates to {@link StakedBalanceFetcher} for the actual RPC calls
|
|
63
|
-
* (getShares + convertToAssets on ERC-4626-style staking contracts).
|
|
64
|
-
* Reports balances as CAIP-19 asset IDs using the ERC20 format with the
|
|
65
|
-
* staking contract address (e.g. "eip155:1/erc20:0x4fef9d741011476750a243ac70b9789a63dd47df").
|
|
66
|
-
*
|
|
67
|
-
* Only supports chains with known staking contracts (mainnet, Hoodi).
|
|
68
|
-
* Polling is managed by StakedBalanceFetcher via startPolling/stopPollingByPollingToken.
|
|
69
|
-
*/
|
|
70
|
-
export class StakedBalanceDataSource extends AbstractDataSource {
|
|
71
|
-
constructor(options) {
|
|
72
|
-
super(CONTROLLER_NAME, { activeChains: [] });
|
|
73
|
-
_StakedBalanceDataSource_instances.add(this);
|
|
74
|
-
_StakedBalanceDataSource_messenger.set(this, void 0);
|
|
75
|
-
_StakedBalanceDataSource_onActiveChainsUpdated.set(this, void 0);
|
|
76
|
-
_StakedBalanceDataSource_pollInterval.set(this, void 0);
|
|
77
|
-
_StakedBalanceDataSource_enabled.set(this, void 0);
|
|
78
|
-
/** The StakedBalanceFetcher that handles polling and RPC calls. */
|
|
79
|
-
_StakedBalanceDataSource_stakedBalanceFetcher.set(this, void 0);
|
|
80
|
-
/** Active subscriptions by ID. */
|
|
81
|
-
_StakedBalanceDataSource_activeSubscriptions.set(this, new Map());
|
|
82
|
-
/** Cache of Web3Provider instances by hex chain ID. */
|
|
83
|
-
_StakedBalanceDataSource_providerCache.set(this, new Map());
|
|
84
|
-
/** Hex chain IDs that have known staking contracts. */
|
|
85
|
-
_StakedBalanceDataSource_supportedHexChains.set(this, void 0);
|
|
86
|
-
_StakedBalanceDataSource_unsubscribeTransactionConfirmed.set(this, undefined);
|
|
87
|
-
_StakedBalanceDataSource_unsubscribeIncomingTransactions.set(this, undefined);
|
|
88
|
-
_StakedBalanceDataSource_unsubscribeNetworkStateChange.set(this, undefined);
|
|
89
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_messenger, options.messenger, "f");
|
|
90
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_onActiveChainsUpdated, options.onActiveChainsUpdated, "f");
|
|
91
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_pollInterval, options.pollInterval ?? DEFAULT_POLL_INTERVAL, "f");
|
|
92
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_enabled, options.enabled !== false, "f");
|
|
93
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_supportedHexChains, getSupportedStakingChainIds(), "f");
|
|
94
|
-
log('Initializing StakedBalanceDataSource', {
|
|
95
|
-
enabled: __classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f"),
|
|
96
|
-
pollInterval: __classPrivateFieldGet(this, _StakedBalanceDataSource_pollInterval, "f"),
|
|
97
|
-
});
|
|
98
|
-
// Create StakedBalanceFetcher with provider getter
|
|
99
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_stakedBalanceFetcher, new StakedBalanceFetcher({
|
|
100
|
-
pollingInterval: __classPrivateFieldGet(this, _StakedBalanceDataSource_pollInterval, "f"),
|
|
101
|
-
getNetworkProvider: (hexChainId) => __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_getProvider).call(this, hexChainId),
|
|
102
|
-
}), "f");
|
|
103
|
-
// Wire the callback so polling results flow back to subscriptions
|
|
104
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").setOnStakedBalanceUpdate(__classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_handleStakedBalanceUpdate).bind(this));
|
|
105
|
-
const unsubConfirmed = __classPrivateFieldGet(this, _StakedBalanceDataSource_messenger, "f").subscribe('TransactionController:transactionConfirmed', __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_onTransactionConfirmed).bind(this));
|
|
106
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_unsubscribeTransactionConfirmed, typeof unsubConfirmed === 'function' ? unsubConfirmed : undefined, "f");
|
|
107
|
-
const unsubIncoming = __classPrivateFieldGet(this, _StakedBalanceDataSource_messenger, "f").subscribe('TransactionController:incomingTransactionsReceived', __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_onIncomingTransactions).bind(this));
|
|
108
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_unsubscribeIncomingTransactions, typeof unsubIncoming === 'function' ? unsubIncoming : undefined, "f");
|
|
109
|
-
const unsubNetwork = __classPrivateFieldGet(this, _StakedBalanceDataSource_messenger, "f").subscribe('NetworkController:stateChange', __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_onNetworkStateChange).bind(this));
|
|
110
|
-
__classPrivateFieldSet(this, _StakedBalanceDataSource_unsubscribeNetworkStateChange, typeof unsubNetwork === 'function'
|
|
111
|
-
? unsubNetwork
|
|
112
|
-
: undefined, "f");
|
|
113
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_initializeActiveChains).call(this);
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Refresh staked balance for all currently subscribed accounts and chains, then
|
|
117
|
-
* push updates to the controller. Can be called from UI or after transaction events.
|
|
118
|
-
*/
|
|
119
|
-
async refreshStakedBalance() {
|
|
120
|
-
if (!__classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f")) {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const toRefresh = __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_getToRefreshAll).call(this);
|
|
124
|
-
if (toRefresh.length > 0) {
|
|
125
|
-
await __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_refreshStakedBalanceAfterTransaction).call(this, toRefresh);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Fetch staked balances for all accounts on supported chains.
|
|
130
|
-
*
|
|
131
|
-
* @param request - The data request with accounts and chains.
|
|
132
|
-
* @returns DataResponse with staked balance data.
|
|
133
|
-
*/
|
|
134
|
-
async fetch(request) {
|
|
135
|
-
var _a;
|
|
136
|
-
if (!__classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f")) {
|
|
137
|
-
return {};
|
|
138
|
-
}
|
|
139
|
-
const response = {};
|
|
140
|
-
const activeChainsSet = new Set(this.state.activeChains);
|
|
141
|
-
const chainsToFetch = request.chainIds.filter((chainId) => activeChainsSet.has(chainId));
|
|
142
|
-
if (chainsToFetch.length === 0) {
|
|
143
|
-
return response;
|
|
144
|
-
}
|
|
145
|
-
const balances = {};
|
|
146
|
-
for (const { account, supportedChains: accountChains, } of request.accountsWithSupportedChains) {
|
|
147
|
-
const chains = chainsToFetch.filter((chain) => accountChains.includes(chain));
|
|
148
|
-
for (const chainId of chains) {
|
|
149
|
-
try {
|
|
150
|
-
const hexChainId = caipChainIdToHex(chainId);
|
|
151
|
-
const contractAddress = getStakingContractAddress(hexChainId);
|
|
152
|
-
if (!contractAddress) {
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
const input = {
|
|
156
|
-
chainId: hexChainId,
|
|
157
|
-
accountId: account.id,
|
|
158
|
-
accountAddress: account.address,
|
|
159
|
-
};
|
|
160
|
-
const result = await __classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").fetchStakedBalance(input);
|
|
161
|
-
// Include zero amounts so merged updates clear prior non-zero state.
|
|
162
|
-
balances[_a = account.id] ?? (balances[_a] = {});
|
|
163
|
-
const assetId = stakedAssetId(chainId, contractAddress);
|
|
164
|
-
balances[account.id][assetId] = { amount: result.amount };
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
log('Failed to fetch staked balance', {
|
|
168
|
-
chainId,
|
|
169
|
-
accountId: account.id,
|
|
170
|
-
error,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (Object.keys(balances).length > 0) {
|
|
176
|
-
response.assetsBalance = balances;
|
|
177
|
-
// Add metadata for each staked asset ID present in balances
|
|
178
|
-
const assetIds = new Set();
|
|
179
|
-
for (const accountBalances of Object.values(balances)) {
|
|
180
|
-
for (const assetId of Object.keys(accountBalances)) {
|
|
181
|
-
assetIds.add(assetId);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
response.assetsInfo = {};
|
|
185
|
-
for (const assetId of assetIds) {
|
|
186
|
-
response.assetsInfo[assetId] = STAKED_ETH_METADATA;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return response;
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Assets middleware for the fetch pipeline.
|
|
193
|
-
* Fetches staked balances and merges them into the response, then passes
|
|
194
|
-
* all chains to the next middleware (staked balance doesn't claim chains).
|
|
195
|
-
*
|
|
196
|
-
* @returns The middleware function for the assets pipeline.
|
|
197
|
-
*/
|
|
198
|
-
get assetsMiddleware() {
|
|
199
|
-
return async (context, next) => {
|
|
200
|
-
var _a, _b;
|
|
201
|
-
if (!__classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f")) {
|
|
202
|
-
return next(context);
|
|
203
|
-
}
|
|
204
|
-
const { request } = context;
|
|
205
|
-
if (!request.dataTypes.includes('balance')) {
|
|
206
|
-
return next(context);
|
|
207
|
-
}
|
|
208
|
-
if (request.chainIds.length === 0) {
|
|
209
|
-
return next(context);
|
|
210
|
-
}
|
|
211
|
-
try {
|
|
212
|
-
const fetchResponse = await this.fetch(request);
|
|
213
|
-
if (fetchResponse.assetsInfo) {
|
|
214
|
-
(_a = context.response).assetsInfo ?? (_a.assetsInfo = {});
|
|
215
|
-
Object.assign(context.response.assetsInfo, fetchResponse.assetsInfo);
|
|
216
|
-
}
|
|
217
|
-
if (fetchResponse.assetsBalance) {
|
|
218
|
-
(_b = context.response).assetsBalance ?? (_b.assetsBalance = {});
|
|
219
|
-
for (const [accountId, accountBalances] of Object.entries(fetchResponse.assetsBalance)) {
|
|
220
|
-
context.response.assetsBalance[accountId] = {
|
|
221
|
-
...context.response.assetsBalance[accountId],
|
|
222
|
-
...accountBalances,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
catch (error) {
|
|
228
|
-
log('Middleware fetch failed', { error });
|
|
229
|
-
}
|
|
230
|
-
// Pass all chains through (staked balance doesn't claim chains)
|
|
231
|
-
return next(context);
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Subscribe to staked balance updates with polling.
|
|
236
|
-
* Starts polling via StakedBalanceFetcher for each account/chain combination.
|
|
237
|
-
*
|
|
238
|
-
* @param subscriptionRequest - The subscription request details.
|
|
239
|
-
*/
|
|
240
|
-
async subscribe(subscriptionRequest) {
|
|
241
|
-
const { request, subscriptionId, isUpdate } = subscriptionRequest;
|
|
242
|
-
const activeChainsSet = new Set(this.state.activeChains);
|
|
243
|
-
const chainsToSubscribe = request.chainIds.filter((chainId) => activeChainsSet.has(chainId));
|
|
244
|
-
log('Subscribe requested', {
|
|
245
|
-
subscriptionId,
|
|
246
|
-
isUpdate,
|
|
247
|
-
chainsToSubscribe,
|
|
248
|
-
});
|
|
249
|
-
if (chainsToSubscribe.length === 0) {
|
|
250
|
-
log('No staking chains to subscribe');
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
// Handle subscription update - restart polling for new chains
|
|
254
|
-
if (isUpdate) {
|
|
255
|
-
const existing = __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").get(subscriptionId);
|
|
256
|
-
if (existing) {
|
|
257
|
-
log('Updating existing subscription - restarting polling', {
|
|
258
|
-
subscriptionId,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
// Clean up existing subscription (stops old polling)
|
|
263
|
-
await this.unsubscribe(subscriptionId);
|
|
264
|
-
// Start polling through StakedBalanceFetcher for each account/chain
|
|
265
|
-
const pollingTokens = [];
|
|
266
|
-
for (const { account, supportedChains: accountChains, } of request.accountsWithSupportedChains) {
|
|
267
|
-
const chainsForAccount = chainsToSubscribe.filter((chain) => accountChains.includes(chain));
|
|
268
|
-
for (const chainId of chainsForAccount) {
|
|
269
|
-
const hexChainId = caipChainIdToHex(chainId);
|
|
270
|
-
const input = {
|
|
271
|
-
chainId: hexChainId,
|
|
272
|
-
accountId: account.id,
|
|
273
|
-
accountAddress: account.address,
|
|
274
|
-
};
|
|
275
|
-
const pollingToken = __classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").startPolling(input);
|
|
276
|
-
pollingTokens.push(pollingToken);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
// Store subscription data (preserve per-account scope for refresh paths)
|
|
280
|
-
const accountsWithSupportedChains = request.accountsWithSupportedChains
|
|
281
|
-
.map(({ account, supportedChains }) => ({
|
|
282
|
-
account,
|
|
283
|
-
supportedChains: chainsToSubscribe.filter((chain) => supportedChains.includes(chain)),
|
|
284
|
-
}))
|
|
285
|
-
.filter(({ supportedChains }) => supportedChains.length > 0);
|
|
286
|
-
const accounts = accountsWithSupportedChains.map((entry) => entry.account);
|
|
287
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").set(subscriptionId, {
|
|
288
|
-
pollingTokens,
|
|
289
|
-
chains: chainsToSubscribe,
|
|
290
|
-
accounts,
|
|
291
|
-
accountsWithSupportedChains,
|
|
292
|
-
onAssetsUpdate: subscriptionRequest.onAssetsUpdate,
|
|
293
|
-
});
|
|
294
|
-
// Also store in parent activeSubscriptions for cleanup
|
|
295
|
-
this.activeSubscriptions.set(subscriptionId, {
|
|
296
|
-
cleanup: () => {
|
|
297
|
-
for (const token of pollingTokens) {
|
|
298
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").stopPollingByPollingToken(token);
|
|
299
|
-
}
|
|
300
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").delete(subscriptionId);
|
|
301
|
-
},
|
|
302
|
-
chains: chainsToSubscribe,
|
|
303
|
-
request,
|
|
304
|
-
onAssetsUpdate: subscriptionRequest.onAssetsUpdate,
|
|
305
|
-
});
|
|
306
|
-
log('Subscription SUCCESS', {
|
|
307
|
-
subscriptionId,
|
|
308
|
-
chains: chainsToSubscribe,
|
|
309
|
-
pollingCount: pollingTokens.length,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* Unsubscribe from staked balance updates and stop polling.
|
|
314
|
-
*
|
|
315
|
-
* @param subscriptionId - The subscription ID to unsubscribe.
|
|
316
|
-
*/
|
|
317
|
-
async unsubscribe(subscriptionId) {
|
|
318
|
-
const subscription = __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").get(subscriptionId);
|
|
319
|
-
if (subscription) {
|
|
320
|
-
for (const token of subscription.pollingTokens) {
|
|
321
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").stopPollingByPollingToken(token);
|
|
322
|
-
}
|
|
323
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").delete(subscriptionId);
|
|
324
|
-
}
|
|
325
|
-
await super.unsubscribe(subscriptionId);
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Destroy the data source and clean up all resources.
|
|
329
|
-
*/
|
|
330
|
-
destroy() {
|
|
331
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_unsubscribeTransactionConfirmed, "f")?.call(this);
|
|
332
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_unsubscribeIncomingTransactions, "f")?.call(this);
|
|
333
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_unsubscribeNetworkStateChange, "f")?.call(this);
|
|
334
|
-
for (const subscription of __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").values()) {
|
|
335
|
-
for (const token of subscription.pollingTokens) {
|
|
336
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").stopPollingByPollingToken(token);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").clear();
|
|
340
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_providerCache, "f").clear();
|
|
341
|
-
super.destroy();
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
_StakedBalanceDataSource_messenger = new WeakMap(), _StakedBalanceDataSource_onActiveChainsUpdated = new WeakMap(), _StakedBalanceDataSource_pollInterval = new WeakMap(), _StakedBalanceDataSource_enabled = new WeakMap(), _StakedBalanceDataSource_stakedBalanceFetcher = new WeakMap(), _StakedBalanceDataSource_activeSubscriptions = new WeakMap(), _StakedBalanceDataSource_providerCache = new WeakMap(), _StakedBalanceDataSource_supportedHexChains = new WeakMap(), _StakedBalanceDataSource_unsubscribeTransactionConfirmed = new WeakMap(), _StakedBalanceDataSource_unsubscribeIncomingTransactions = new WeakMap(), _StakedBalanceDataSource_unsubscribeNetworkStateChange = new WeakMap(), _StakedBalanceDataSource_instances = new WeakSet(), _StakedBalanceDataSource_onNetworkStateChange = function _StakedBalanceDataSource_onNetworkStateChange() {
|
|
345
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_providerCache, "f").clear();
|
|
346
|
-
log('Provider cache cleared after network state change');
|
|
347
|
-
}, _StakedBalanceDataSource_onTransactionConfirmed = function _StakedBalanceDataSource_onTransactionConfirmed(payload) {
|
|
348
|
-
if (!__classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f")) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
const hexChainId = payload?.chainId;
|
|
352
|
-
if (!hexChainId) {
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
const caipChainId = `eip155:${parseInt(hexChainId, 16)}`;
|
|
356
|
-
const toRefresh = __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_getToRefreshForChains).call(this, [caipChainId]);
|
|
357
|
-
if (toRefresh.length > 0) {
|
|
358
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_refreshStakedBalanceAfterTransaction).call(this, toRefresh).catch((error) => {
|
|
359
|
-
log('Failed to refresh staked balance after transaction', { error });
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
}, _StakedBalanceDataSource_onIncomingTransactions = function _StakedBalanceDataSource_onIncomingTransactions(payload) {
|
|
363
|
-
if (!__classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f")) {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
const chainIds = Array.from(new Set((payload ?? [])
|
|
367
|
-
.map((item) => item?.chainId)
|
|
368
|
-
.filter((id) => Boolean(id))));
|
|
369
|
-
const caipChainIds = chainIds.map((hexChainId) => `eip155:${parseInt(hexChainId, 16)}`);
|
|
370
|
-
const toRefresh = caipChainIds.length > 0
|
|
371
|
-
? __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_getToRefreshForChains).call(this, caipChainIds)
|
|
372
|
-
: __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_getToRefreshAll).call(this);
|
|
373
|
-
if (toRefresh.length > 0) {
|
|
374
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_refreshStakedBalanceAfterTransaction).call(this, toRefresh).catch((error) => {
|
|
375
|
-
log('Failed to refresh staked balance after incoming transactions', {
|
|
376
|
-
error,
|
|
377
|
-
});
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
}, _StakedBalanceDataSource_getToRefreshForChains = function _StakedBalanceDataSource_getToRefreshForChains(chainIds) {
|
|
381
|
-
const toRefresh = [];
|
|
382
|
-
const chainSet = new Set(chainIds);
|
|
383
|
-
for (const subscription of __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").values()) {
|
|
384
|
-
for (const { account, supportedChains, } of subscription.accountsWithSupportedChains) {
|
|
385
|
-
for (const chainId of supportedChains) {
|
|
386
|
-
if (chainSet.has(chainId)) {
|
|
387
|
-
toRefresh.push({ account, chainId });
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return toRefresh;
|
|
393
|
-
}, _StakedBalanceDataSource_getToRefreshAll = function _StakedBalanceDataSource_getToRefreshAll() {
|
|
394
|
-
const toRefresh = [];
|
|
395
|
-
for (const subscription of __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").values()) {
|
|
396
|
-
for (const { account, supportedChains, } of subscription.accountsWithSupportedChains) {
|
|
397
|
-
for (const chainId of supportedChains) {
|
|
398
|
-
toRefresh.push({ account, chainId });
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
return toRefresh;
|
|
403
|
-
}, _StakedBalanceDataSource_refreshStakedBalanceAfterTransaction =
|
|
404
|
-
/**
|
|
405
|
-
* Fetch staked balance for the given account/chain pairs and push a single
|
|
406
|
-
* DataResponse to all active subscriptions.
|
|
407
|
-
*
|
|
408
|
-
* @param toRefresh - List of { account, chainId } to refresh.
|
|
409
|
-
*/
|
|
410
|
-
async function _StakedBalanceDataSource_refreshStakedBalanceAfterTransaction(toRefresh) {
|
|
411
|
-
const assetsInfo = {};
|
|
412
|
-
const assetsBalance = {};
|
|
413
|
-
for (const { account, chainId } of toRefresh) {
|
|
414
|
-
try {
|
|
415
|
-
const hexChainId = caipChainIdToHex(chainId);
|
|
416
|
-
const contractAddress = getStakingContractAddress(hexChainId);
|
|
417
|
-
if (!contractAddress) {
|
|
418
|
-
continue;
|
|
419
|
-
}
|
|
420
|
-
const input = {
|
|
421
|
-
chainId: hexChainId,
|
|
422
|
-
accountId: account.id,
|
|
423
|
-
accountAddress: account.address,
|
|
424
|
-
};
|
|
425
|
-
const result = await __classPrivateFieldGet(this, _StakedBalanceDataSource_stakedBalanceFetcher, "f").fetchStakedBalance(input);
|
|
426
|
-
const assetId = stakedAssetId(chainId, contractAddress);
|
|
427
|
-
assetsInfo[assetId] = STAKED_ETH_METADATA;
|
|
428
|
-
const existing = assetsBalance[account.id];
|
|
429
|
-
assetsBalance[account.id] = {
|
|
430
|
-
...existing,
|
|
431
|
-
[assetId]: { amount: result.amount },
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
log('Failed to fetch staked balance in transaction refresh', {
|
|
436
|
-
chainId,
|
|
437
|
-
accountId: account.id,
|
|
438
|
-
error,
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (Object.keys(assetsBalance).length > 0) {
|
|
443
|
-
const response = { assetsInfo, assetsBalance };
|
|
444
|
-
for (const subscription of __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").values()) {
|
|
445
|
-
subscription.onAssetsUpdate(response)?.catch((error) => {
|
|
446
|
-
log('Failed to report staked balance update after transaction', {
|
|
447
|
-
error,
|
|
448
|
-
});
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}, _StakedBalanceDataSource_initializeActiveChains = function _StakedBalanceDataSource_initializeActiveChains() {
|
|
453
|
-
const supportedChains = __classPrivateFieldGet(this, _StakedBalanceDataSource_enabled, "f") ? __classPrivateFieldGet(this, _StakedBalanceDataSource_instances, "m", _StakedBalanceDataSource_getSupportedChains).call(this) : [];
|
|
454
|
-
const previous = [...this.state.activeChains];
|
|
455
|
-
this.updateActiveChains(supportedChains, (updatedChains) => __classPrivateFieldGet(this, _StakedBalanceDataSource_onActiveChainsUpdated, "f").call(this, this.getName(), updatedChains, previous));
|
|
456
|
-
}, _StakedBalanceDataSource_getSupportedChains = function _StakedBalanceDataSource_getSupportedChains() {
|
|
457
|
-
return __classPrivateFieldGet(this, _StakedBalanceDataSource_supportedHexChains, "f").map((hexChainId) => {
|
|
458
|
-
const decimal = parseInt(hexChainId, 16).toString();
|
|
459
|
-
return `eip155:${decimal}`;
|
|
460
|
-
});
|
|
461
|
-
}, _StakedBalanceDataSource_getProvider = function _StakedBalanceDataSource_getProvider(hexChainId) {
|
|
462
|
-
const cached = __classPrivateFieldGet(this, _StakedBalanceDataSource_providerCache, "f").get(hexChainId);
|
|
463
|
-
if (cached) {
|
|
464
|
-
return cached;
|
|
465
|
-
}
|
|
466
|
-
try {
|
|
467
|
-
const networkState = __classPrivateFieldGet(this, _StakedBalanceDataSource_messenger, "f").call('NetworkController:getState');
|
|
468
|
-
const { networkConfigurationsByChainId } = networkState;
|
|
469
|
-
if (!networkConfigurationsByChainId) {
|
|
470
|
-
return undefined;
|
|
471
|
-
}
|
|
472
|
-
const chainConfig = networkConfigurationsByChainId[hexChainId];
|
|
473
|
-
if (!chainConfig) {
|
|
474
|
-
return undefined;
|
|
475
|
-
}
|
|
476
|
-
// Use the network's configured default RPC endpoint (same as RpcDataSource).
|
|
477
|
-
const { rpcEndpoints, defaultRpcEndpointIndex } = chainConfig;
|
|
478
|
-
if (!rpcEndpoints || rpcEndpoints.length === 0) {
|
|
479
|
-
return undefined;
|
|
480
|
-
}
|
|
481
|
-
const index = typeof defaultRpcEndpointIndex === 'number' &&
|
|
482
|
-
defaultRpcEndpointIndex >= 0 &&
|
|
483
|
-
defaultRpcEndpointIndex < rpcEndpoints.length
|
|
484
|
-
? defaultRpcEndpointIndex
|
|
485
|
-
: 0;
|
|
486
|
-
const defaultEndpoint = rpcEndpoints[index];
|
|
487
|
-
const networkClientId = defaultEndpoint?.networkClientId;
|
|
488
|
-
if (!networkClientId) {
|
|
489
|
-
return undefined;
|
|
490
|
-
}
|
|
491
|
-
const networkClient = __classPrivateFieldGet(this, _StakedBalanceDataSource_messenger, "f").call('NetworkController:getNetworkClientById', networkClientId);
|
|
492
|
-
if (!networkClient?.provider) {
|
|
493
|
-
return undefined;
|
|
494
|
-
}
|
|
495
|
-
const provider = new Web3Provider(networkClient.provider);
|
|
496
|
-
__classPrivateFieldGet(this, _StakedBalanceDataSource_providerCache, "f").set(hexChainId, provider);
|
|
497
|
-
return provider;
|
|
498
|
-
}
|
|
499
|
-
catch (error) {
|
|
500
|
-
log('Failed to get provider for chain', { hexChainId, error });
|
|
501
|
-
return undefined;
|
|
502
|
-
}
|
|
503
|
-
}, _StakedBalanceDataSource_handleStakedBalanceUpdate = function _StakedBalanceDataSource_handleStakedBalanceUpdate(result) {
|
|
504
|
-
const contractAddress = getStakingContractAddress(result.chainId);
|
|
505
|
-
if (!contractAddress) {
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
const chainIdDecimal = parseInt(result.chainId, 16);
|
|
509
|
-
const caipChainId = `eip155:${chainIdDecimal}`;
|
|
510
|
-
const assetId = stakedAssetId(caipChainId, contractAddress);
|
|
511
|
-
const response = {
|
|
512
|
-
assetsInfo: {
|
|
513
|
-
[assetId]: STAKED_ETH_METADATA,
|
|
514
|
-
},
|
|
515
|
-
assetsBalance: {
|
|
516
|
-
[result.accountId]: {
|
|
517
|
-
[assetId]: { amount: result.balance.amount },
|
|
518
|
-
},
|
|
519
|
-
},
|
|
520
|
-
};
|
|
521
|
-
log('Staked balance update', {
|
|
522
|
-
accountId: result.accountId,
|
|
523
|
-
chainId: caipChainId,
|
|
524
|
-
amount: result.balance.amount,
|
|
525
|
-
});
|
|
526
|
-
for (const subscription of __classPrivateFieldGet(this, _StakedBalanceDataSource_activeSubscriptions, "f").values()) {
|
|
527
|
-
subscription.onAssetsUpdate(response)?.catch((error) => {
|
|
528
|
-
log('Failed to report staked balance update', { error });
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
};
|
|
532
|
-
//# sourceMappingURL=StakedBalanceDataSource.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StakedBalanceDataSource.mjs","sourceRoot":"","sources":["../../src/data-sources/StakedBalanceDataSource.ts"],"names":[],"mappings":"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","sourcesContent":["import { toChecksumAddress } from '@ethereumjs/util';\nimport { Web3Provider } from '@ethersproject/providers';\nimport type { InternalAccount } from '@metamask/keyring-internal-api';\nimport type { NetworkState } from '@metamask/network-controller';\nimport {\n isStrictHexString,\n isCaipChainId,\n parseCaipChainId,\n} from '@metamask/utils';\nimport type { Hex } from '@metamask/utils';\n\nimport type {\n DataSourceState,\n SubscriptionRequest,\n} from './AbstractDataSource';\nimport { AbstractDataSource } from './AbstractDataSource';\nimport type {\n StakedBalancePollingInput,\n StakedBalanceFetchResult,\n} from './evm-rpc-services';\nimport {\n StakedBalanceFetcher,\n getStakingContractAddress,\n getSupportedStakingChainIds,\n} from './evm-rpc-services';\nimport type { AssetsControllerMessenger } from '../AssetsController';\nimport { projectLogger, createModuleLogger } from '../logger';\nimport type {\n AccountId,\n ChainId,\n Caip19AssetId,\n AssetBalance,\n AssetMetadata,\n DataRequest,\n DataResponse,\n Middleware,\n} from '../types';\n\nconst CONTROLLER_NAME = 'StakedBalanceDataSource';\nconst DEFAULT_POLL_INTERVAL = 180_000; // 3 minutes\n\n/** Metadata for staked ETH (same symbol and decimals as native ETH). */\nconst STAKED_ETH_METADATA: AssetMetadata = {\n type: 'erc20',\n name: 'staked ethereum',\n symbol: 'ETH',\n decimals: 18,\n};\n\nconst log = createModuleLogger(projectLogger, CONTROLLER_NAME);\n\n// Network client returned by NetworkController\ntype NetworkClient = {\n provider: EthereumProvider;\n configuration: { chainId: string };\n};\n\n// Ethereum provider interface\ntype EthereumProvider = {\n request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;\n};\n\n/** Optional configuration for StakedBalanceDataSource. */\nexport type StakedBalanceDataSourceConfig = {\n /** Whether staked balance fetching is enabled (default: true). */\n enabled?: boolean;\n /** Polling interval in ms (default: 180s / 3 min). */\n pollInterval?: number;\n};\n\nexport type StakedBalanceDataSourceOptions = StakedBalanceDataSourceConfig & {\n /** The AssetsController messenger (for accessing NetworkController). */\n messenger: AssetsControllerMessenger;\n /** Called when active chains are updated. */\n onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n};\n\n/** Per-account supported chains (same shape as in DataRequest). */\ntype AccountWithSupportedChains = {\n account: InternalAccount;\n supportedChains: ChainId[];\n};\n\n/**\n * Subscription data stored for each active subscription.\n * Stores accountsWithSupportedChains so refresh paths use the same per-account\n * scope as normal subscription setup (avoids querying unsupported chains/accounts).\n */\ntype SubscriptionData = {\n /** Polling tokens from StakedBalanceFetcher. */\n pollingTokens: string[];\n /** Chain IDs being polled (union of all account chains). */\n chains: ChainId[];\n /** Accounts being polled. */\n accounts: InternalAccount[];\n /** Per-account supported chains; used by refreshStakedBalance and transaction handlers. */\n accountsWithSupportedChains: AccountWithSupportedChains[];\n /** Callback to report asset updates. */\n onAssetsUpdate: (response: DataResponse) => void | Promise<void>;\n};\n\n/**\n * Convert CAIP chain ID or hex chain ID to hex chain ID.\n *\n * @param chainId - CAIP chain ID or hex chain ID.\n * @returns Hex chain ID.\n */\nfunction caipChainIdToHex(chainId: string): Hex {\n if (isStrictHexString(chainId)) {\n return chainId;\n }\n\n if (isCaipChainId(chainId)) {\n const ref = parseCaipChainId(chainId).reference;\n return `0x${parseInt(ref, 10).toString(16)}`;\n }\n\n throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');\n}\n\n/**\n * Build the CAIP-19 asset ID for staked balance (same format as ERC20).\n * Uses the staking contract address (checksummed) so it is consistent with\n * other token assets.\n * Example: \"eip155:1/erc20:0x4fef9d741011476750a243ac70b9789a63dd47df\"\n *\n * @param chainId - CAIP-2 chain ID (e.g. \"eip155:1\").\n * @param contractAddress - Staking contract address (hex).\n * @returns The staked asset CAIP-19 ID with checksummed address.\n */\nfunction stakedAssetId(\n chainId: ChainId,\n contractAddress: string,\n): Caip19AssetId {\n const checksummed = toChecksumAddress(contractAddress);\n return `${chainId}/erc20:${checksummed}` as Caip19AssetId;\n}\n\n/**\n * Data source for fetching staked ETH balances via on-chain staking contracts.\n *\n * Delegates to {@link StakedBalanceFetcher} for the actual RPC calls\n * (getShares + convertToAssets on ERC-4626-style staking contracts).\n * Reports balances as CAIP-19 asset IDs using the ERC20 format with the\n * staking contract address (e.g. \"eip155:1/erc20:0x4fef9d741011476750a243ac70b9789a63dd47df\").\n *\n * Only supports chains with known staking contracts (mainnet, Hoodi).\n * Polling is managed by StakedBalanceFetcher via startPolling/stopPollingByPollingToken.\n */\nexport class StakedBalanceDataSource extends AbstractDataSource<\n typeof CONTROLLER_NAME,\n DataSourceState\n> {\n readonly #messenger: AssetsControllerMessenger;\n\n readonly #onActiveChainsUpdated: (\n dataSourceName: string,\n chains: ChainId[],\n previousChains: ChainId[],\n ) => void;\n\n readonly #pollInterval: number;\n\n readonly #enabled: boolean;\n\n /** The StakedBalanceFetcher that handles polling and RPC calls. */\n readonly #stakedBalanceFetcher: StakedBalanceFetcher;\n\n /** Active subscriptions by ID. */\n readonly #activeSubscriptions: Map<string, SubscriptionData> = new Map();\n\n /** Cache of Web3Provider instances by hex chain ID. */\n readonly #providerCache: Map<Hex, Web3Provider> = new Map();\n\n /** Hex chain IDs that have known staking contracts. */\n readonly #supportedHexChains: string[];\n\n constructor(options: StakedBalanceDataSourceOptions) {\n super(CONTROLLER_NAME, { activeChains: [] });\n this.#messenger = options.messenger;\n this.#onActiveChainsUpdated = options.onActiveChainsUpdated;\n this.#pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n this.#enabled = options.enabled !== false;\n this.#supportedHexChains = getSupportedStakingChainIds();\n\n log('Initializing StakedBalanceDataSource', {\n enabled: this.#enabled,\n pollInterval: this.#pollInterval,\n });\n\n // Create StakedBalanceFetcher with provider getter\n this.#stakedBalanceFetcher = new StakedBalanceFetcher({\n pollingInterval: this.#pollInterval,\n getNetworkProvider: (hexChainId): Web3Provider | undefined =>\n this.#getProvider(hexChainId),\n });\n\n // Wire the callback so polling results flow back to subscriptions\n this.#stakedBalanceFetcher.setOnStakedBalanceUpdate(\n this.#handleStakedBalanceUpdate.bind(this),\n );\n\n const unsubConfirmed = this.#messenger.subscribe(\n 'TransactionController:transactionConfirmed',\n this.#onTransactionConfirmed.bind(this),\n );\n this.#unsubscribeTransactionConfirmed =\n typeof unsubConfirmed === 'function' ? unsubConfirmed : undefined;\n\n const unsubIncoming = this.#messenger.subscribe(\n 'TransactionController:incomingTransactionsReceived',\n this.#onIncomingTransactions.bind(this),\n );\n this.#unsubscribeIncomingTransactions =\n typeof unsubIncoming === 'function' ? unsubIncoming : undefined;\n\n const unsubNetwork = (\n this.#messenger as unknown as {\n subscribe: (e: string, h: (state: NetworkState) => void) => unknown;\n }\n ).subscribe(\n 'NetworkController:stateChange',\n this.#onNetworkStateChange.bind(this),\n );\n this.#unsubscribeNetworkStateChange =\n typeof unsubNetwork === 'function'\n ? (unsubNetwork as () => void)\n : undefined;\n\n this.#initializeActiveChains();\n }\n\n readonly #unsubscribeTransactionConfirmed: (() => void) | undefined =\n undefined;\n\n readonly #unsubscribeIncomingTransactions: (() => void) | undefined =\n undefined;\n\n readonly #unsubscribeNetworkStateChange: (() => void) | undefined = undefined;\n\n /**\n * When NetworkController state changes (e.g. RPC endpoints or network clients\n * reconfigured), clear the provider cache so subsequent fetches use fresh\n * providers.\n */\n #onNetworkStateChange(): void {\n this.#providerCache.clear();\n log('Provider cache cleared after network state change');\n }\n\n /**\n * When a transaction is confirmed, refresh staked balance for the chain from the payload.\n *\n * @param payload - From TransactionController:transactionConfirmed.\n * @param payload.chainId - Hex chain ID of the transaction.\n */\n #onTransactionConfirmed(payload: { chainId?: string }): void {\n if (!this.#enabled) {\n return;\n }\n const hexChainId = payload?.chainId;\n if (!hexChainId) {\n return;\n }\n const caipChainId = `eip155:${parseInt(hexChainId, 16)}` as ChainId;\n const toRefresh = this.#getToRefreshForChains([caipChainId]);\n if (toRefresh.length > 0) {\n this.#refreshStakedBalanceAfterTransaction(toRefresh).catch((error) => {\n log('Failed to refresh staked balance after transaction', { error });\n });\n }\n }\n\n /**\n * When incoming transactions are received, refresh staked balance for chains in the payload.\n *\n * @param payload - From TransactionController:incomingTransactionsReceived (array of { chainId? }).\n */\n #onIncomingTransactions(payload: { chainId?: string }[]): void {\n if (!this.#enabled) {\n return;\n }\n const chainIds = Array.from(\n new Set(\n (payload ?? [])\n .map((item) => item?.chainId)\n .filter((id): id is string => Boolean(id)),\n ),\n );\n const caipChainIds = chainIds.map(\n (hexChainId) => `eip155:${parseInt(hexChainId, 16)}` as ChainId,\n );\n const toRefresh =\n caipChainIds.length > 0\n ? this.#getToRefreshForChains(caipChainIds)\n : this.#getToRefreshAll();\n if (toRefresh.length > 0) {\n this.#refreshStakedBalanceAfterTransaction(toRefresh).catch((error) => {\n log('Failed to refresh staked balance after incoming transactions', {\n error,\n });\n });\n }\n }\n\n /**\n * Build toRefresh list for subscribed (account, chainId) pairs for the given chains.\n *\n * @param chainIds - CAIP-2 chain IDs to target.\n * @returns Pairs of account and chainId to refresh.\n */\n #getToRefreshForChains(\n chainIds: ChainId[],\n ): { account: InternalAccount; chainId: ChainId }[] {\n const toRefresh: { account: InternalAccount; chainId: ChainId }[] = [];\n const chainSet = new Set(chainIds);\n for (const subscription of this.#activeSubscriptions.values()) {\n for (const {\n account,\n supportedChains,\n } of subscription.accountsWithSupportedChains) {\n for (const chainId of supportedChains) {\n if (chainSet.has(chainId)) {\n toRefresh.push({ account, chainId });\n }\n }\n }\n }\n return toRefresh;\n }\n\n /**\n * Build toRefresh list for all subscribed (account, chainId) pairs.\n *\n * @returns Pairs of account and chainId to refresh.\n */\n #getToRefreshAll(): { account: InternalAccount; chainId: ChainId }[] {\n const toRefresh: { account: InternalAccount; chainId: ChainId }[] = [];\n for (const subscription of this.#activeSubscriptions.values()) {\n for (const {\n account,\n supportedChains,\n } of subscription.accountsWithSupportedChains) {\n for (const chainId of supportedChains) {\n toRefresh.push({ account, chainId });\n }\n }\n }\n return toRefresh;\n }\n\n /**\n * Refresh staked balance for all currently subscribed accounts and chains, then\n * push updates to the controller. Can be called from UI or after transaction events.\n */\n async refreshStakedBalance(): Promise<void> {\n if (!this.#enabled) {\n return;\n }\n const toRefresh = this.#getToRefreshAll();\n if (toRefresh.length > 0) {\n await this.#refreshStakedBalanceAfterTransaction(toRefresh);\n }\n }\n\n /**\n * Fetch staked balance for the given account/chain pairs and push a single\n * DataResponse to all active subscriptions.\n *\n * @param toRefresh - List of { account, chainId } to refresh.\n */\n async #refreshStakedBalanceAfterTransaction(\n toRefresh: { account: InternalAccount; chainId: ChainId }[],\n ): Promise<void> {\n const assetsInfo: Record<Caip19AssetId, AssetMetadata> = {};\n const assetsBalance: Record<\n AccountId,\n Record<Caip19AssetId, AssetBalance>\n > = {};\n\n for (const { account, chainId } of toRefresh) {\n try {\n const hexChainId = caipChainIdToHex(chainId);\n const contractAddress = getStakingContractAddress(hexChainId);\n if (!contractAddress) {\n continue;\n }\n\n const input: StakedBalancePollingInput = {\n chainId: hexChainId,\n accountId: account.id,\n accountAddress: account.address as Hex,\n };\n\n const result =\n await this.#stakedBalanceFetcher.fetchStakedBalance(input);\n const assetId = stakedAssetId(chainId, contractAddress);\n\n assetsInfo[assetId] = STAKED_ETH_METADATA;\n const existing = assetsBalance[account.id];\n assetsBalance[account.id] = {\n ...existing,\n [assetId]: { amount: result.amount },\n };\n } catch (error) {\n log('Failed to fetch staked balance in transaction refresh', {\n chainId,\n accountId: account.id,\n error,\n });\n }\n }\n\n if (Object.keys(assetsBalance).length > 0) {\n const response: DataResponse = { assetsInfo, assetsBalance };\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response)?.catch((error: unknown) => {\n log('Failed to report staked balance update after transaction', {\n error,\n });\n });\n }\n }\n }\n\n /**\n * Set active chains to those with known staking contracts when enabled; otherwise [].\n */\n #initializeActiveChains(): void {\n const supportedChains = this.#enabled ? this.#getSupportedChains() : [];\n const previous = [...this.state.activeChains];\n this.updateActiveChains(supportedChains, (updatedChains) =>\n this.#onActiveChainsUpdated(this.getName(), updatedChains, previous),\n );\n }\n\n /**\n * Determine which staking chains are currently supported.\n *\n * @returns CAIP-2 chain IDs for supported staking chains.\n */\n #getSupportedChains(): ChainId[] {\n return this.#supportedHexChains.map((hexChainId) => {\n const decimal = parseInt(hexChainId, 16).toString();\n return `eip155:${decimal}` as ChainId;\n });\n }\n\n /**\n * Get or create a Web3Provider for the given hex chain ID.\n * Uses the same messenger-cast pattern as RpcDataSource.\n *\n * @param hexChainId - The hex chain ID.\n * @returns Web3Provider instance, or undefined if not available.\n */\n #getProvider(hexChainId: Hex): Web3Provider | undefined {\n const cached = this.#providerCache.get(hexChainId);\n if (cached) {\n return cached;\n }\n\n try {\n const networkState = (\n this.#messenger as unknown as {\n call: (action: string) => NetworkState;\n }\n ).call('NetworkController:getState');\n\n const { networkConfigurationsByChainId } = networkState;\n if (!networkConfigurationsByChainId) {\n return undefined;\n }\n\n const chainConfig = networkConfigurationsByChainId[hexChainId];\n if (!chainConfig) {\n return undefined;\n }\n\n // Use the network's configured default RPC endpoint (same as RpcDataSource).\n const { rpcEndpoints, defaultRpcEndpointIndex } = chainConfig;\n if (!rpcEndpoints || rpcEndpoints.length === 0) {\n return undefined;\n }\n\n const index =\n typeof defaultRpcEndpointIndex === 'number' &&\n defaultRpcEndpointIndex >= 0 &&\n defaultRpcEndpointIndex < rpcEndpoints.length\n ? defaultRpcEndpointIndex\n : 0;\n const defaultEndpoint = rpcEndpoints[index] as {\n networkClientId?: string;\n };\n const networkClientId = defaultEndpoint?.networkClientId;\n if (!networkClientId) {\n return undefined;\n }\n\n const networkClient = (\n this.#messenger as unknown as {\n call: (action: string, id: string) => NetworkClient;\n }\n ).call('NetworkController:getNetworkClientById', networkClientId);\n\n if (!networkClient?.provider) {\n return undefined;\n }\n\n const provider = new Web3Provider(networkClient.provider);\n this.#providerCache.set(hexChainId, provider);\n return provider;\n } catch (error) {\n log('Failed to get provider for chain', { hexChainId, error });\n return undefined;\n }\n }\n\n /**\n * Handle a staked balance update from StakedBalanceFetcher.\n * Converts the result into a DataResponse and forwards it to all active\n * subscriptions.\n *\n * @param result - The staked balance fetch result.\n */\n #handleStakedBalanceUpdate(result: StakedBalanceFetchResult): void {\n const contractAddress = getStakingContractAddress(result.chainId);\n if (!contractAddress) {\n return;\n }\n const chainIdDecimal = parseInt(result.chainId, 16);\n const caipChainId = `eip155:${chainIdDecimal}` as ChainId;\n const assetId = stakedAssetId(caipChainId, contractAddress);\n\n const response: DataResponse = {\n assetsInfo: {\n [assetId]: STAKED_ETH_METADATA,\n },\n assetsBalance: {\n [result.accountId]: {\n [assetId]: { amount: result.balance.amount },\n },\n },\n };\n\n log('Staked balance update', {\n accountId: result.accountId,\n chainId: caipChainId,\n amount: result.balance.amount,\n });\n\n for (const subscription of this.#activeSubscriptions.values()) {\n subscription.onAssetsUpdate(response)?.catch((error: unknown) => {\n log('Failed to report staked balance update', { error });\n });\n }\n }\n\n /**\n * Fetch staked balances for all accounts on supported chains.\n *\n * @param request - The data request with accounts and chains.\n * @returns DataResponse with staked balance data.\n */\n async fetch(request: DataRequest): Promise<DataResponse> {\n if (!this.#enabled) {\n return {};\n }\n const response: DataResponse = {};\n const activeChainsSet = new Set(this.state.activeChains);\n\n const chainsToFetch = request.chainIds.filter((chainId) =>\n activeChainsSet.has(chainId),\n );\n\n if (chainsToFetch.length === 0) {\n return response;\n }\n\n const balances: Record<AccountId, Record<Caip19AssetId, AssetBalance>> = {};\n\n for (const {\n account,\n supportedChains: accountChains,\n } of request.accountsWithSupportedChains) {\n const chains = chainsToFetch.filter((chain) =>\n accountChains.includes(chain),\n );\n\n for (const chainId of chains) {\n try {\n const hexChainId = caipChainIdToHex(chainId);\n const contractAddress = getStakingContractAddress(hexChainId);\n if (!contractAddress) {\n continue;\n }\n\n const input: StakedBalancePollingInput = {\n chainId: hexChainId,\n accountId: account.id,\n accountAddress: account.address as Hex,\n };\n\n const result =\n await this.#stakedBalanceFetcher.fetchStakedBalance(input);\n\n // Include zero amounts so merged updates clear prior non-zero state.\n balances[account.id] ??= {};\n const assetId = stakedAssetId(chainId, contractAddress);\n balances[account.id][assetId] = { amount: result.amount };\n } catch (error) {\n log('Failed to fetch staked balance', {\n chainId,\n accountId: account.id,\n error,\n });\n }\n }\n }\n\n if (Object.keys(balances).length > 0) {\n response.assetsBalance = balances;\n // Add metadata for each staked asset ID present in balances\n const assetIds = new Set<Caip19AssetId>();\n for (const accountBalances of Object.values(balances)) {\n for (const assetId of Object.keys(accountBalances)) {\n assetIds.add(assetId as Caip19AssetId);\n }\n }\n response.assetsInfo = {};\n for (const assetId of assetIds) {\n response.assetsInfo[assetId] = STAKED_ETH_METADATA;\n }\n }\n\n return response;\n }\n\n /**\n * Assets middleware for the fetch pipeline.\n * Fetches staked balances and merges them into the response, then passes\n * all chains to the next middleware (staked balance doesn't claim chains).\n *\n * @returns The middleware function for the assets pipeline.\n */\n get assetsMiddleware(): Middleware {\n return async (context, next) => {\n if (!this.#enabled) {\n return next(context);\n }\n const { request } = context;\n\n if (!request.dataTypes.includes('balance')) {\n return next(context);\n }\n\n if (request.chainIds.length === 0) {\n return next(context);\n }\n\n try {\n const fetchResponse = await this.fetch(request);\n\n if (fetchResponse.assetsInfo) {\n context.response.assetsInfo ??= {};\n Object.assign(context.response.assetsInfo, fetchResponse.assetsInfo);\n }\n if (fetchResponse.assetsBalance) {\n context.response.assetsBalance ??= {};\n for (const [accountId, accountBalances] of Object.entries(\n fetchResponse.assetsBalance,\n )) {\n context.response.assetsBalance[accountId] = {\n ...context.response.assetsBalance[accountId],\n ...accountBalances,\n };\n }\n }\n } catch (error) {\n log('Middleware fetch failed', { error });\n }\n\n // Pass all chains through (staked balance doesn't claim chains)\n return next(context);\n };\n }\n\n /**\n * Subscribe to staked balance updates with polling.\n * Starts polling via StakedBalanceFetcher for each account/chain combination.\n *\n * @param subscriptionRequest - The subscription request details.\n */\n async subscribe(subscriptionRequest: SubscriptionRequest): Promise<void> {\n const { request, subscriptionId, isUpdate } = subscriptionRequest;\n\n const activeChainsSet = new Set(this.state.activeChains);\n const chainsToSubscribe = request.chainIds.filter((chainId) =>\n activeChainsSet.has(chainId),\n );\n\n log('Subscribe requested', {\n subscriptionId,\n isUpdate,\n chainsToSubscribe,\n });\n\n if (chainsToSubscribe.length === 0) {\n log('No staking chains to subscribe');\n return;\n }\n\n // Handle subscription update - restart polling for new chains\n if (isUpdate) {\n const existing = this.#activeSubscriptions.get(subscriptionId);\n if (existing) {\n log('Updating existing subscription - restarting polling', {\n subscriptionId,\n });\n }\n }\n\n // Clean up existing subscription (stops old polling)\n await this.unsubscribe(subscriptionId);\n\n // Start polling through StakedBalanceFetcher for each account/chain\n const pollingTokens: string[] = [];\n\n for (const {\n account,\n supportedChains: accountChains,\n } of request.accountsWithSupportedChains) {\n const chainsForAccount = chainsToSubscribe.filter((chain) =>\n accountChains.includes(chain),\n );\n\n for (const chainId of chainsForAccount) {\n const hexChainId = caipChainIdToHex(chainId);\n\n const input: StakedBalancePollingInput = {\n chainId: hexChainId,\n accountId: account.id,\n accountAddress: account.address as Hex,\n };\n\n const pollingToken = this.#stakedBalanceFetcher.startPolling(input);\n pollingTokens.push(pollingToken);\n }\n }\n\n // Store subscription data (preserve per-account scope for refresh paths)\n const accountsWithSupportedChains: AccountWithSupportedChains[] =\n request.accountsWithSupportedChains\n .map(({ account, supportedChains }) => ({\n account,\n supportedChains: chainsToSubscribe.filter((chain) =>\n supportedChains.includes(chain),\n ),\n }))\n .filter(({ supportedChains }) => supportedChains.length > 0);\n\n const accounts = accountsWithSupportedChains.map((entry) => entry.account);\n this.#activeSubscriptions.set(subscriptionId, {\n pollingTokens,\n chains: chainsToSubscribe,\n accounts,\n accountsWithSupportedChains,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n // Also store in parent activeSubscriptions for cleanup\n this.activeSubscriptions.set(subscriptionId, {\n cleanup: () => {\n for (const token of pollingTokens) {\n this.#stakedBalanceFetcher.stopPollingByPollingToken(token);\n }\n this.#activeSubscriptions.delete(subscriptionId);\n },\n chains: chainsToSubscribe,\n request,\n onAssetsUpdate: subscriptionRequest.onAssetsUpdate,\n });\n\n log('Subscription SUCCESS', {\n subscriptionId,\n chains: chainsToSubscribe,\n pollingCount: pollingTokens.length,\n });\n }\n\n /**\n * Unsubscribe from staked balance updates and stop polling.\n *\n * @param subscriptionId - The subscription ID to unsubscribe.\n */\n async unsubscribe(subscriptionId: string): Promise<void> {\n const subscription = this.#activeSubscriptions.get(subscriptionId);\n if (subscription) {\n for (const token of subscription.pollingTokens) {\n this.#stakedBalanceFetcher.stopPollingByPollingToken(token);\n }\n this.#activeSubscriptions.delete(subscriptionId);\n }\n\n await super.unsubscribe(subscriptionId);\n }\n\n /**\n * Destroy the data source and clean up all resources.\n */\n destroy(): void {\n this.#unsubscribeTransactionConfirmed?.();\n this.#unsubscribeIncomingTransactions?.();\n this.#unsubscribeNetworkStateChange?.();\n for (const subscription of this.#activeSubscriptions.values()) {\n for (const token of subscription.pollingTokens) {\n this.#stakedBalanceFetcher.stopPollingByPollingToken(token);\n }\n }\n this.#activeSubscriptions.clear();\n this.#providerCache.clear();\n super.destroy();\n }\n}\n"]}
|