@metamask/assets-controllers 94.0.0 → 94.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -1
- package/dist/AccountTrackerController.cjs +71 -57
- package/dist/AccountTrackerController.cjs.map +1 -1
- package/dist/AccountTrackerController.d.cts +3 -2
- package/dist/AccountTrackerController.d.cts.map +1 -1
- package/dist/AccountTrackerController.d.mts +3 -2
- package/dist/AccountTrackerController.d.mts.map +1 -1
- package/dist/AccountTrackerController.mjs +71 -57
- package/dist/AccountTrackerController.mjs.map +1 -1
- package/dist/TokenBalancesController.cjs +351 -382
- package/dist/TokenBalancesController.cjs.map +1 -1
- package/dist/TokenBalancesController.d.cts +20 -39
- package/dist/TokenBalancesController.d.cts.map +1 -1
- package/dist/TokenBalancesController.d.mts +20 -39
- package/dist/TokenBalancesController.d.mts.map +1 -1
- package/dist/TokenBalancesController.mjs +351 -382
- package/dist/TokenBalancesController.mjs.map +1 -1
- package/dist/TokenDetectionController.cjs +139 -207
- package/dist/TokenDetectionController.cjs.map +1 -1
- package/dist/TokenDetectionController.d.cts +38 -12
- package/dist/TokenDetectionController.d.cts.map +1 -1
- package/dist/TokenDetectionController.d.mts +38 -12
- package/dist/TokenDetectionController.d.mts.map +1 -1
- package/dist/TokenDetectionController.mjs +140 -208
- package/dist/TokenDetectionController.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs +13 -2
- package/dist/multi-chain-accounts-service/api-balance-fetcher.cjs.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.cts.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.d.mts.map +1 -1
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs +13 -2
- package/dist/multi-chain-accounts-service/api-balance-fetcher.mjs.map +1 -1
- package/dist/multi-chain-accounts-service/types.cjs.map +1 -1
- package/dist/multi-chain-accounts-service/types.d.cts +2 -1
- package/dist/multi-chain-accounts-service/types.d.cts.map +1 -1
- package/dist/multi-chain-accounts-service/types.d.mts +2 -1
- package/dist/multi-chain-accounts-service/types.d.mts.map +1 -1
- package/dist/multi-chain-accounts-service/types.mjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.cjs +12 -0
- package/dist/token-prices-service/codefi-v2.cjs.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.cts +12 -2
- package/dist/token-prices-service/codefi-v2.d.cts.map +1 -1
- package/dist/token-prices-service/codefi-v2.d.mts +12 -2
- package/dist/token-prices-service/codefi-v2.d.mts.map +1 -1
- package/dist/token-prices-service/codefi-v2.mjs +12 -0
- package/dist/token-prices-service/codefi-v2.mjs.map +1 -1
- package/dist/token-service.cjs +11 -3
- package/dist/token-service.cjs.map +1 -1
- package/dist/token-service.d.cts +3 -1
- package/dist/token-service.d.cts.map +1 -1
- package/dist/token-service.d.mts +3 -1
- package/dist/token-service.d.mts.map +1 -1
- package/dist/token-service.mjs +11 -3
- package/dist/token-service.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -13,18 +13,16 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
13
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
|
-
var _TokenDetectionController_instances, _TokenDetectionController_intervalId, _TokenDetectionController_selectedAccountId, _TokenDetectionController_tokensChainsCache, _TokenDetectionController_disabled, _TokenDetectionController_isUnlocked, _TokenDetectionController_isDetectionEnabledFromPreferences, _TokenDetectionController_useTokenDetection, _TokenDetectionController_useExternalServices, _TokenDetectionController_getBalancesInSingleCall, _TokenDetectionController_trackMetaMetricsEvent,
|
|
16
|
+
var _TokenDetectionController_instances, _TokenDetectionController_intervalId, _TokenDetectionController_selectedAccountId, _TokenDetectionController_tokensChainsCache, _TokenDetectionController_disabled, _TokenDetectionController_isUnlocked, _TokenDetectionController_isDetectionEnabledFromPreferences, _TokenDetectionController_useTokenDetection, _TokenDetectionController_useExternalServices, _TokenDetectionController_getBalancesInSingleCall, _TokenDetectionController_trackMetaMetricsEvent, _TokenDetectionController_registerEventListeners, _TokenDetectionController_stopPolling, _TokenDetectionController_startPolling, _TokenDetectionController_compareTokensChainsCache, _TokenDetectionController_getCorrectNetworkClientIdByChainId, _TokenDetectionController_restartTokenDetection, _TokenDetectionController_shouldDetectTokens, _TokenDetectionController_detectTokensUsingRpc, _TokenDetectionController_getSlicesOfTokensToDetect, _TokenDetectionController_getConvertedStaticMainnetTokenList, _TokenDetectionController_addDetectedTokens, _TokenDetectionController_getSelectedAccount, _TokenDetectionController_getSelectedAddress;
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.TokenDetectionController = exports.controllerName = exports.mapChainIdWithTokenListMap = exports.STATIC_MAINNET_TOKEN_LIST = void 0;
|
|
19
19
|
const contract_metadata_1 = __importDefault(require("@metamask/contract-metadata"));
|
|
20
20
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
21
21
|
const polling_controller_1 = require("@metamask/polling-controller");
|
|
22
|
-
const utils_1 = require("@metamask/utils");
|
|
23
22
|
const lodash_1 = require("lodash");
|
|
24
23
|
const assetsUtil_1 = require("./assetsUtil.cjs");
|
|
25
|
-
const
|
|
24
|
+
const constants_1 = require("./constants.cjs");
|
|
26
25
|
const DEFAULT_INTERVAL = 180000;
|
|
27
|
-
const ACCOUNTS_API_TIMEOUT_MS = 10000;
|
|
28
26
|
exports.STATIC_MAINNET_TOKEN_LIST = Object.entries(contract_metadata_1.default).reduce((acc, [base, contract]) => {
|
|
29
27
|
const { logo, erc20, erc721, ...tokenMetadata } = contract;
|
|
30
28
|
return {
|
|
@@ -79,12 +77,10 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
79
77
|
* @param options.interval - Polling interval used to fetch new token rates
|
|
80
78
|
* @param options.getBalancesInSingleCall - Gets the balances of a list of tokens for the given address.
|
|
81
79
|
* @param options.trackMetaMetricsEvent - Sets options for MetaMetrics event tracking.
|
|
82
|
-
* @param options.useAccountsAPI - Feature Switch for using the accounts API when detecting tokens (default: true)
|
|
83
80
|
* @param options.useTokenDetection - Feature Switch for using token detection (default: true)
|
|
84
81
|
* @param options.useExternalServices - Feature Switch for using external services (default: false)
|
|
85
|
-
* @param options.platform - Indicates whether the platform is extension or mobile
|
|
86
82
|
*/
|
|
87
|
-
constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger,
|
|
83
|
+
constructor({ interval = DEFAULT_INTERVAL, disabled = true, getBalancesInSingleCall, trackMetaMetricsEvent, messenger, useTokenDetection = () => true, useExternalServices = () => true, }) {
|
|
88
84
|
super({
|
|
89
85
|
name: exports.controllerName,
|
|
90
86
|
messenger,
|
|
@@ -102,38 +98,9 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
102
98
|
_TokenDetectionController_useExternalServices.set(this, void 0);
|
|
103
99
|
_TokenDetectionController_getBalancesInSingleCall.set(this, void 0);
|
|
104
100
|
_TokenDetectionController_trackMetaMetricsEvent.set(this, void 0);
|
|
105
|
-
_TokenDetectionController_accountsAPI.set(this, {
|
|
106
|
-
isAccountsAPIEnabled: true,
|
|
107
|
-
supportedNetworksCache: null,
|
|
108
|
-
platform: '',
|
|
109
|
-
async getSupportedNetworks() {
|
|
110
|
-
/* istanbul ignore next */
|
|
111
|
-
if (!this.isAccountsAPIEnabled) {
|
|
112
|
-
throw new Error('Accounts API Feature Switch is disabled');
|
|
113
|
-
}
|
|
114
|
-
/* istanbul ignore next */
|
|
115
|
-
if (this.supportedNetworksCache) {
|
|
116
|
-
return this.supportedNetworksCache;
|
|
117
|
-
}
|
|
118
|
-
const result = await (0, multi_chain_accounts_service_1.fetchSupportedNetworks)().catch(() => null);
|
|
119
|
-
this.supportedNetworksCache = result;
|
|
120
|
-
return result;
|
|
121
|
-
},
|
|
122
|
-
async getMultiNetworksBalances(address, chainIds, supportedNetworks, jwtToken) {
|
|
123
|
-
const chainIdNumbers = chainIds.map((chainId) => (0, utils_1.hexToNumber)(chainId));
|
|
124
|
-
if (!supportedNetworks ||
|
|
125
|
-
!chainIdNumbers.every((id) => supportedNetworks.includes(id))) {
|
|
126
|
-
const supportedNetworksErrStr = (supportedNetworks ?? []).toString();
|
|
127
|
-
throw new Error(`Unsupported Network: supported networks ${supportedNetworksErrStr}, requested networks: ${chainIdNumbers.toString()}`);
|
|
128
|
-
}
|
|
129
|
-
const result = await (0, multi_chain_accounts_service_1.fetchMultiChainBalances)(address, {
|
|
130
|
-
networks: chainIdNumbers,
|
|
131
|
-
}, this.platform, jwtToken);
|
|
132
|
-
// Return the full response including unprocessedNetworks
|
|
133
|
-
return result;
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
101
|
this.messenger.registerActionHandler(`${exports.controllerName}:addDetectedTokensViaWs`, this.addDetectedTokensViaWs.bind(this));
|
|
102
|
+
this.messenger.registerActionHandler(`${exports.controllerName}:addDetectedTokensViaPolling`, this.addDetectedTokensViaPolling.bind(this));
|
|
103
|
+
this.messenger.registerActionHandler(`${exports.controllerName}:detectTokens`, this.detectTokens.bind(this));
|
|
137
104
|
__classPrivateFieldSet(this, _TokenDetectionController_disabled, disabled, "f");
|
|
138
105
|
this.setIntervalLength(interval);
|
|
139
106
|
__classPrivateFieldSet(this, _TokenDetectionController_selectedAccountId, __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAccount).call(this).id, "f");
|
|
@@ -145,10 +112,8 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
145
112
|
__classPrivateFieldSet(this, _TokenDetectionController_trackMetaMetricsEvent, trackMetaMetricsEvent, "f");
|
|
146
113
|
const { isUnlocked } = this.messenger.call('KeyringController:getState');
|
|
147
114
|
__classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, isUnlocked, "f");
|
|
148
|
-
__classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").isAccountsAPIEnabled = useAccountsAPI;
|
|
149
115
|
__classPrivateFieldSet(this, _TokenDetectionController_useTokenDetection, useTokenDetection, "f");
|
|
150
116
|
__classPrivateFieldSet(this, _TokenDetectionController_useExternalServices, useExternalServices, "f");
|
|
151
|
-
__classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f").platform = platform;
|
|
152
117
|
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_registerEventListeners).call(this);
|
|
153
118
|
}
|
|
154
119
|
/**
|
|
@@ -201,48 +166,40 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
201
166
|
* @param options - Options for token detection.
|
|
202
167
|
* @param options.chainIds - The chain IDs of the network client to use.
|
|
203
168
|
* @param options.selectedAddress - the selectedAddress against which to detect for token balances.
|
|
169
|
+
* @param options.forceRpc - Force RPC-based token detection for all specified chains,
|
|
170
|
+
* bypassing external services check and ensuring RPC is used even for chains
|
|
171
|
+
* that might otherwise be handled by the Accounts API.
|
|
204
172
|
*/
|
|
205
|
-
async detectTokens({ chainIds, selectedAddress, } = {}) {
|
|
173
|
+
async detectTokens({ chainIds, selectedAddress, forceRpc = false, } = {}) {
|
|
206
174
|
if (!this.isActive) {
|
|
207
175
|
return;
|
|
208
176
|
}
|
|
209
|
-
|
|
177
|
+
// When forceRpc is true, bypass the useTokenDetection check to ensure RPC detection runs
|
|
178
|
+
if (!forceRpc && !__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// If external services are disabled and not forcing RPC, skip all detection
|
|
182
|
+
if (!forceRpc && !__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
|
|
210
183
|
return;
|
|
211
184
|
}
|
|
212
185
|
const addressToDetect = selectedAddress ?? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
|
|
213
186
|
const clientNetworks = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getCorrectNetworkClientIdByChainId).call(this, chainIds);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getChainsToDetect).call(this, clientNetworks, supportedNetworks);
|
|
222
|
-
// Try detecting tokens via Account API first if conditions allow
|
|
223
|
-
if (supportedNetworks && chainsToDetectUsingAccountAPI.length > 0) {
|
|
224
|
-
const apiResult = await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_attemptAccountAPIDetection).call(this, chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks, jwtToken);
|
|
225
|
-
// If the account API call failed or returned undefined, have those chains fall back to RPC detection
|
|
226
|
-
if (!apiResult || apiResult.result === 'failed') {
|
|
227
|
-
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks);
|
|
228
|
-
}
|
|
229
|
-
else if (apiResult?.result === 'success' &&
|
|
230
|
-
apiResult.unprocessedNetworks &&
|
|
231
|
-
apiResult.unprocessedNetworks.length > 0) {
|
|
232
|
-
// Handle unprocessed networks by adding them to RPC detection
|
|
233
|
-
const unprocessedChainIds = apiResult.unprocessedNetworks.map((chainId) => (0, controller_utils_1.toHex)(chainId));
|
|
234
|
-
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addChainsToRpcDetection).call(this, chainsToDetectUsingRpc, unprocessedChainIds, clientNetworks);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
// Proceed with RPC detection if there are chains remaining in chainsToDetectUsingRpc
|
|
238
|
-
if (chainsToDetectUsingRpc.length > 0) {
|
|
239
|
-
await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
|
|
187
|
+
// If forceRpc is true, use RPC for all chains
|
|
188
|
+
// Otherwise, skip chains supported by Accounts API (they are handled by TokenBalancesController)
|
|
189
|
+
const chainsToDetectUsingRpc = forceRpc
|
|
190
|
+
? clientNetworks
|
|
191
|
+
: clientNetworks.filter(({ chainId }) => !constants_1.SUPPORTED_NETWORKS_ACCOUNTS_API_V4.includes(chainId));
|
|
192
|
+
if (chainsToDetectUsingRpc.length === 0) {
|
|
193
|
+
return;
|
|
240
194
|
}
|
|
195
|
+
await __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_detectTokensUsingRpc).call(this, chainsToDetectUsingRpc, addressToDetect);
|
|
241
196
|
}
|
|
242
197
|
/**
|
|
243
198
|
* Add tokens detected from websocket balance updates
|
|
244
|
-
* This method
|
|
245
|
-
* -
|
|
199
|
+
* This method:
|
|
200
|
+
* - Checks if useTokenDetection preference is enabled (skips if disabled)
|
|
201
|
+
* - Checks if external services are enabled (skips if disabled)
|
|
202
|
+
* - Tokens are expected to be in the tokensChainsCache with full metadata
|
|
246
203
|
* - Balance fetching is skipped since balances are provided by the websocket
|
|
247
204
|
* - Ignored tokens have been filtered out by the caller
|
|
248
205
|
*
|
|
@@ -252,6 +209,18 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
252
209
|
* @returns Promise that resolves when tokens are added
|
|
253
210
|
*/
|
|
254
211
|
async addDetectedTokensViaWs({ tokensSlice, chainId, }) {
|
|
212
|
+
// Check if token detection is enabled via preferences
|
|
213
|
+
if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Check if external services are enabled (websocket requires external services)
|
|
217
|
+
if (!__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
// Refresh the token cache to ensure we have the latest token metadata
|
|
221
|
+
// This fixes a bug where the cache from construction time could be stale/empty
|
|
222
|
+
const { tokensChainsCache } = this.messenger.call('TokenListController:getState');
|
|
223
|
+
__classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, tokensChainsCache ?? {}, "f");
|
|
255
224
|
const tokensWithBalance = [];
|
|
256
225
|
const eventTokensDetails = [];
|
|
257
226
|
for (const tokenAddress of tokensSlice) {
|
|
@@ -292,48 +261,136 @@ class TokenDetectionController extends (0, polling_controller_1.StaticIntervalPo
|
|
|
292
261
|
await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
|
|
293
262
|
}
|
|
294
263
|
}
|
|
264
|
+
/**
|
|
265
|
+
* Add tokens detected from polling balance updates
|
|
266
|
+
* This method:
|
|
267
|
+
* - Checks if useTokenDetection preference is enabled (skips if disabled)
|
|
268
|
+
* - Checks if external services are enabled (skips if disabled)
|
|
269
|
+
* - Filters out tokens already in allTokens or allIgnoredTokens
|
|
270
|
+
* - Tokens are expected to be in the tokensChainsCache with full metadata
|
|
271
|
+
* - Balance fetching is skipped since balances are provided by the caller
|
|
272
|
+
*
|
|
273
|
+
* @param options - The options object
|
|
274
|
+
* @param options.tokensSlice - Array of token addresses detected from polling
|
|
275
|
+
* @param options.chainId - Hex chain ID
|
|
276
|
+
* @returns Promise that resolves when tokens are added
|
|
277
|
+
*/
|
|
278
|
+
async addDetectedTokensViaPolling({ tokensSlice, chainId, }) {
|
|
279
|
+
// Check if token detection is enabled via preferences
|
|
280
|
+
if (!__classPrivateFieldGet(this, _TokenDetectionController_useTokenDetection, "f").call(this)) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
// Check if external services are enabled (polling via API requires external services)
|
|
284
|
+
if (!__classPrivateFieldGet(this, _TokenDetectionController_useExternalServices, "f").call(this)) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
// Refresh the token cache to ensure we have the latest token metadata
|
|
288
|
+
// This fixes a bug where the cache from construction time could be stale/empty
|
|
289
|
+
const { tokensChainsCache } = this.messenger.call('TokenListController:getState');
|
|
290
|
+
__classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, tokensChainsCache ?? {}, "f");
|
|
291
|
+
const selectedAddress = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAddress).call(this);
|
|
292
|
+
// Get current token states to filter out already tracked/ignored tokens
|
|
293
|
+
const { allTokens, allIgnoredTokens } = this.messenger.call('TokensController:getState');
|
|
294
|
+
const existingTokenAddresses = (allTokens[chainId]?.[selectedAddress] ?? []).map((token) => token.address.toLowerCase());
|
|
295
|
+
const ignoredTokenAddresses = (allIgnoredTokens[chainId]?.[selectedAddress] ?? []).map((address) => address.toLowerCase());
|
|
296
|
+
const tokensWithBalance = [];
|
|
297
|
+
const eventTokensDetails = [];
|
|
298
|
+
for (const tokenAddress of tokensSlice) {
|
|
299
|
+
const lowercaseTokenAddress = tokenAddress.toLowerCase();
|
|
300
|
+
const checksummedTokenAddress = (0, controller_utils_1.toChecksumHexAddress)(tokenAddress);
|
|
301
|
+
// Skip tokens already in allTokens
|
|
302
|
+
if (existingTokenAddresses.includes(lowercaseTokenAddress)) {
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
// Skip tokens in allIgnoredTokens
|
|
306
|
+
if (ignoredTokenAddresses.includes(lowercaseTokenAddress)) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
// Check map of validated tokens (cache keys are lowercase)
|
|
310
|
+
const tokenData = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId]?.data?.[lowercaseTokenAddress];
|
|
311
|
+
if (!tokenData) {
|
|
312
|
+
console.warn(`Token metadata not found in cache for ${tokenAddress} on chain ${chainId}`);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
const { decimals, symbol, aggregators, iconUrl, name } = tokenData;
|
|
316
|
+
eventTokensDetails.push(`${symbol} - ${checksummedTokenAddress}`);
|
|
317
|
+
tokensWithBalance.push({
|
|
318
|
+
address: checksummedTokenAddress,
|
|
319
|
+
decimals,
|
|
320
|
+
symbol,
|
|
321
|
+
aggregators,
|
|
322
|
+
image: iconUrl,
|
|
323
|
+
isERC721: false,
|
|
324
|
+
name,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
// Perform addition
|
|
328
|
+
if (tokensWithBalance.length) {
|
|
329
|
+
__classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
|
|
330
|
+
event: 'Token Detected',
|
|
331
|
+
category: 'Wallet',
|
|
332
|
+
properties: {
|
|
333
|
+
tokens: eventTokensDetails,
|
|
334
|
+
token_standard: controller_utils_1.ERC20,
|
|
335
|
+
asset_type: controller_utils_1.ASSET_TYPES.TOKEN,
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
|
|
339
|
+
await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
295
342
|
}
|
|
296
343
|
exports.TokenDetectionController = TokenDetectionController;
|
|
297
|
-
_TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_selectedAccountId = new WeakMap(), _TokenDetectionController_tokensChainsCache = new WeakMap(), _TokenDetectionController_disabled = new WeakMap(), _TokenDetectionController_isUnlocked = new WeakMap(), _TokenDetectionController_isDetectionEnabledFromPreferences = new WeakMap(), _TokenDetectionController_useTokenDetection = new WeakMap(), _TokenDetectionController_useExternalServices = new WeakMap(), _TokenDetectionController_getBalancesInSingleCall = new WeakMap(), _TokenDetectionController_trackMetaMetricsEvent = new WeakMap(),
|
|
298
|
-
this.messenger.subscribe('KeyringController:unlock',
|
|
344
|
+
_TokenDetectionController_intervalId = new WeakMap(), _TokenDetectionController_selectedAccountId = new WeakMap(), _TokenDetectionController_tokensChainsCache = new WeakMap(), _TokenDetectionController_disabled = new WeakMap(), _TokenDetectionController_isUnlocked = new WeakMap(), _TokenDetectionController_isDetectionEnabledFromPreferences = new WeakMap(), _TokenDetectionController_useTokenDetection = new WeakMap(), _TokenDetectionController_useExternalServices = new WeakMap(), _TokenDetectionController_getBalancesInSingleCall = new WeakMap(), _TokenDetectionController_trackMetaMetricsEvent = new WeakMap(), _TokenDetectionController_instances = new WeakSet(), _TokenDetectionController_registerEventListeners = function _TokenDetectionController_registerEventListeners() {
|
|
345
|
+
this.messenger.subscribe('KeyringController:unlock', () => {
|
|
299
346
|
__classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, true, "f");
|
|
300
|
-
|
|
347
|
+
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this).catch(() => {
|
|
348
|
+
// Silently handle token detection errors
|
|
349
|
+
});
|
|
301
350
|
});
|
|
302
351
|
this.messenger.subscribe('KeyringController:lock', () => {
|
|
303
352
|
__classPrivateFieldSet(this, _TokenDetectionController_isUnlocked, false, "f");
|
|
304
353
|
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_stopPolling).call(this);
|
|
305
354
|
});
|
|
306
|
-
this.messenger.subscribe('TokenListController:stateChange',
|
|
355
|
+
this.messenger.subscribe('TokenListController:stateChange', ({ tokensChainsCache }) => {
|
|
307
356
|
const isEqualValues = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_compareTokensChainsCache).call(this, tokensChainsCache, __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f"));
|
|
308
357
|
if (!isEqualValues) {
|
|
309
|
-
|
|
358
|
+
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this).catch(() => {
|
|
359
|
+
// Silently handle token detection errors
|
|
360
|
+
});
|
|
310
361
|
}
|
|
311
362
|
});
|
|
312
|
-
this.messenger.subscribe('PreferencesController:stateChange',
|
|
363
|
+
this.messenger.subscribe('PreferencesController:stateChange', ({ useTokenDetection }) => {
|
|
313
364
|
const selectedAccount = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSelectedAccount).call(this);
|
|
314
365
|
const isDetectionChangedFromPreferences = __classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") !== useTokenDetection;
|
|
315
366
|
__classPrivateFieldSet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, useTokenDetection, "f");
|
|
316
367
|
if (isDetectionChangedFromPreferences) {
|
|
317
|
-
|
|
368
|
+
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
|
|
318
369
|
selectedAddress: selectedAccount.address,
|
|
370
|
+
}).catch(() => {
|
|
371
|
+
// Silently handle token detection errors
|
|
319
372
|
});
|
|
320
373
|
}
|
|
321
374
|
});
|
|
322
|
-
this.messenger.subscribe('AccountsController:selectedEvmAccountChange',
|
|
375
|
+
this.messenger.subscribe('AccountsController:selectedEvmAccountChange', (selectedAccount) => {
|
|
323
376
|
const { networkConfigurationsByChainId } = this.messenger.call('NetworkController:getState');
|
|
324
377
|
const chainIds = Object.keys(networkConfigurationsByChainId);
|
|
325
378
|
const isSelectedAccountIdChanged = __classPrivateFieldGet(this, _TokenDetectionController_selectedAccountId, "f") !== selectedAccount.id;
|
|
326
379
|
if (isSelectedAccountIdChanged) {
|
|
327
380
|
__classPrivateFieldSet(this, _TokenDetectionController_selectedAccountId, selectedAccount.id, "f");
|
|
328
|
-
|
|
381
|
+
__classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_restartTokenDetection).call(this, {
|
|
329
382
|
selectedAddress: selectedAccount.address,
|
|
330
383
|
chainIds,
|
|
384
|
+
}).catch(() => {
|
|
385
|
+
// Silently handle token detection errors
|
|
331
386
|
});
|
|
332
387
|
}
|
|
333
388
|
});
|
|
334
|
-
this.messenger.subscribe('TransactionController:transactionConfirmed',
|
|
335
|
-
|
|
389
|
+
this.messenger.subscribe('TransactionController:transactionConfirmed', (transactionMeta) => {
|
|
390
|
+
this.detectTokens({
|
|
336
391
|
chainIds: [transactionMeta.chainId],
|
|
392
|
+
}).catch(() => {
|
|
393
|
+
// Silently handle token detection errors
|
|
337
394
|
});
|
|
338
395
|
});
|
|
339
396
|
}, _TokenDetectionController_stopPolling = function _TokenDetectionController_stopPolling() {
|
|
@@ -394,41 +451,6 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
|
|
|
394
451
|
selectedAddress,
|
|
395
452
|
});
|
|
396
453
|
this.setIntervalLength(DEFAULT_INTERVAL);
|
|
397
|
-
}, _TokenDetectionController_getChainsToDetect = function _TokenDetectionController_getChainsToDetect(clientNetworks, supportedNetworks) {
|
|
398
|
-
const chainsToDetectUsingAccountAPI = [];
|
|
399
|
-
const chainsToDetectUsingRpc = [];
|
|
400
|
-
clientNetworks.forEach(({ chainId, networkClientId }) => {
|
|
401
|
-
if (supportedNetworks?.includes((0, utils_1.hexToNumber)(chainId))) {
|
|
402
|
-
chainsToDetectUsingAccountAPI.push(chainId);
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
chainsToDetectUsingRpc.push({ chainId, networkClientId });
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
return { chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI };
|
|
409
|
-
}, _TokenDetectionController_attemptAccountAPIDetection = async function _TokenDetectionController_attemptAccountAPIDetection(chainsToDetectUsingAccountAPI, addressToDetect, supportedNetworks, jwtToken) {
|
|
410
|
-
const result = await (0, controller_utils_1.safelyExecuteWithTimeout)(async () => {
|
|
411
|
-
return __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_addDetectedTokensViaAPI).call(this, {
|
|
412
|
-
chainIds: chainsToDetectUsingAccountAPI,
|
|
413
|
-
selectedAddress: addressToDetect,
|
|
414
|
-
supportedNetworks,
|
|
415
|
-
jwtToken,
|
|
416
|
-
});
|
|
417
|
-
}, false, ACCOUNTS_API_TIMEOUT_MS);
|
|
418
|
-
if (!result) {
|
|
419
|
-
return { result: 'failed' };
|
|
420
|
-
}
|
|
421
|
-
return result;
|
|
422
|
-
}, _TokenDetectionController_addChainsToRpcDetection = function _TokenDetectionController_addChainsToRpcDetection(chainsToDetectUsingRpc, chainsToDetectUsingAccountAPI, clientNetworks) {
|
|
423
|
-
chainsToDetectUsingAccountAPI.forEach((chainId) => {
|
|
424
|
-
const networkEntry = clientNetworks.find((network) => network.chainId === chainId);
|
|
425
|
-
if (networkEntry) {
|
|
426
|
-
chainsToDetectUsingRpc.push({
|
|
427
|
-
chainId: networkEntry.chainId,
|
|
428
|
-
networkClientId: networkEntry.networkClientId,
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
454
|
}, _TokenDetectionController_shouldDetectTokens = function _TokenDetectionController_shouldDetectTokens(chainId) {
|
|
433
455
|
if (!(0, assetsUtil_1.isTokenDetectionSupportedForNetwork)(chainId)) {
|
|
434
456
|
return false;
|
|
@@ -503,96 +525,6 @@ async function _TokenDetectionController_restartTokenDetection({ selectedAddress
|
|
|
503
525
|
timestamp: 0,
|
|
504
526
|
},
|
|
505
527
|
};
|
|
506
|
-
}, _TokenDetectionController_addDetectedTokensViaAPI =
|
|
507
|
-
/**
|
|
508
|
-
* This adds detected tokens from the Accounts API, avoiding the multi-call RPC calls for balances
|
|
509
|
-
*
|
|
510
|
-
* @param options - method arguments
|
|
511
|
-
* @param options.selectedAddress - address to check against
|
|
512
|
-
* @param options.chainIds - array of chainIds to check tokens for
|
|
513
|
-
* @param options.supportedNetworks - array of chainIds to check tokens for
|
|
514
|
-
* @param options.jwtToken - JWT token for authentication
|
|
515
|
-
* @returns a success or failed object
|
|
516
|
-
*/
|
|
517
|
-
async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddress, chainIds, supportedNetworks, jwtToken, }) {
|
|
518
|
-
return await (0, controller_utils_1.safelyExecute)(async () => {
|
|
519
|
-
// Fetch balances for multiple chain IDs at once
|
|
520
|
-
const apiResponse = await __classPrivateFieldGet(this, _TokenDetectionController_accountsAPI, "f")
|
|
521
|
-
.getMultiNetworksBalances(selectedAddress, chainIds, supportedNetworks, jwtToken)
|
|
522
|
-
.catch(() => null);
|
|
523
|
-
if (apiResponse === null) {
|
|
524
|
-
return { result: 'failed' };
|
|
525
|
-
}
|
|
526
|
-
const tokenBalancesByChain = apiResponse.balances;
|
|
527
|
-
// Process each chain ID individually
|
|
528
|
-
for (const chainId of chainIds) {
|
|
529
|
-
const isTokenDetectionInactiveInMainnet = !__classPrivateFieldGet(this, _TokenDetectionController_isDetectionEnabledFromPreferences, "f") &&
|
|
530
|
-
chainId === controller_utils_1.ChainId.mainnet;
|
|
531
|
-
const { tokensChainsCache } = this.messenger.call('TokenListController:getState');
|
|
532
|
-
__classPrivateFieldSet(this, _TokenDetectionController_tokensChainsCache, isTokenDetectionInactiveInMainnet
|
|
533
|
-
? __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getConvertedStaticMainnetTokenList).call(this)
|
|
534
|
-
: (tokensChainsCache ?? {}), "f");
|
|
535
|
-
// Generate token candidates based on chainId and selectedAddress
|
|
536
|
-
const tokenCandidateSlices = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_getSlicesOfTokensToDetect).call(this, {
|
|
537
|
-
chainId,
|
|
538
|
-
selectedAddress,
|
|
539
|
-
});
|
|
540
|
-
// Filter balances for the current chainId
|
|
541
|
-
const tokenBalances = tokenBalancesByChain.filter((balance) => balance.chainId === (0, utils_1.hexToNumber)(chainId));
|
|
542
|
-
if (!tokenBalances || tokenBalances.length === 0) {
|
|
543
|
-
continue;
|
|
544
|
-
}
|
|
545
|
-
// Use helper function to filter tokens with balance for this chainId
|
|
546
|
-
const { tokensWithBalance, eventTokensDetails } = __classPrivateFieldGet(this, _TokenDetectionController_instances, "m", _TokenDetectionController_filterAndBuildTokensWithBalance).call(this, tokenCandidateSlices, tokenBalances, chainId);
|
|
547
|
-
if (tokensWithBalance.length) {
|
|
548
|
-
__classPrivateFieldGet(this, _TokenDetectionController_trackMetaMetricsEvent, "f").call(this, {
|
|
549
|
-
event: 'Token Detected',
|
|
550
|
-
category: 'Wallet',
|
|
551
|
-
properties: {
|
|
552
|
-
tokens: eventTokensDetails,
|
|
553
|
-
token_standard: controller_utils_1.ERC20,
|
|
554
|
-
asset_type: controller_utils_1.ASSET_TYPES.TOKEN,
|
|
555
|
-
},
|
|
556
|
-
});
|
|
557
|
-
const networkClientId = this.messenger.call('NetworkController:findNetworkClientIdByChainId', chainId);
|
|
558
|
-
await this.messenger.call('TokensController:addTokens', tokensWithBalance, networkClientId);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
return {
|
|
562
|
-
result: 'success',
|
|
563
|
-
unprocessedNetworks: apiResponse.unprocessedNetworks,
|
|
564
|
-
};
|
|
565
|
-
});
|
|
566
|
-
}, _TokenDetectionController_filterAndBuildTokensWithBalance = function _TokenDetectionController_filterAndBuildTokensWithBalance(tokenCandidateSlices, tokenBalances, chainId) {
|
|
567
|
-
const tokensWithBalance = [];
|
|
568
|
-
const eventTokensDetails = [];
|
|
569
|
-
const tokenCandidateSet = new Set(tokenCandidateSlices.flat());
|
|
570
|
-
tokenBalances?.forEach((token) => {
|
|
571
|
-
const tokenAddress = token.address;
|
|
572
|
-
// Make sure the token to add is in our candidate list
|
|
573
|
-
if (!tokenCandidateSet.has(tokenAddress)) {
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
// Retrieve token data from cache to safely add it
|
|
577
|
-
const tokenData = __classPrivateFieldGet(this, _TokenDetectionController_tokensChainsCache, "f")[chainId]?.data[tokenAddress];
|
|
578
|
-
// We need specific data from tokensChainsCache to correctly create a token
|
|
579
|
-
// So even if we have a token that was detected correctly by the API, if its missing data we cannot safely add it.
|
|
580
|
-
if (!tokenData) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
const { decimals, symbol, aggregators, iconUrl, name } = tokenData;
|
|
584
|
-
eventTokensDetails.push(`${symbol} - ${tokenAddress}`);
|
|
585
|
-
tokensWithBalance.push({
|
|
586
|
-
address: tokenAddress,
|
|
587
|
-
decimals,
|
|
588
|
-
symbol,
|
|
589
|
-
aggregators,
|
|
590
|
-
image: iconUrl,
|
|
591
|
-
isERC721: false,
|
|
592
|
-
name,
|
|
593
|
-
});
|
|
594
|
-
});
|
|
595
|
-
return { tokensWithBalance, eventTokensDetails };
|
|
596
528
|
}, _TokenDetectionController_addDetectedTokens = async function _TokenDetectionController_addDetectedTokens({ tokensSlice, selectedAddress, networkClientId, chainId, }) {
|
|
597
529
|
await (0, controller_utils_1.safelyExecute)(async () => {
|
|
598
530
|
const balances = await __classPrivateFieldGet(this, _TokenDetectionController_getBalancesInSingleCall, "f").call(this, selectedAddress, tokensSlice, networkClientId);
|
|
@@ -629,7 +561,7 @@ async function _TokenDetectionController_addDetectedTokensViaAPI({ selectedAddre
|
|
|
629
561
|
}, _TokenDetectionController_getSelectedAddress = function _TokenDetectionController_getSelectedAddress() {
|
|
630
562
|
// If the address is not defined (or empty), we fallback to the currently selected account's address
|
|
631
563
|
const account = this.messenger.call('AccountsController:getAccount', __classPrivateFieldGet(this, _TokenDetectionController_selectedAccountId, "f"));
|
|
632
|
-
return account?.address
|
|
564
|
+
return account?.address ?? '';
|
|
633
565
|
};
|
|
634
566
|
exports.default = TokenDetectionController;
|
|
635
567
|
//# sourceMappingURL=TokenDetectionController.cjs.map
|