@metamask-previews/assets-controller 0.0.0-preview-e09bf49f → 0.0.0-preview-52f4a2ca
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 +3 -0
- package/dist/AssetsController.cjs +26 -32
- package/dist/AssetsController.cjs.map +1 -1
- package/dist/AssetsController.d.cts +5 -1
- package/dist/AssetsController.d.cts.map +1 -1
- package/dist/AssetsController.d.mts +5 -1
- package/dist/AssetsController.d.mts.map +1 -1
- package/dist/AssetsController.mjs +26 -32
- package/dist/AssetsController.mjs.map +1 -1
- package/dist/data-sources/PriceDataSource.cjs +12 -19
- package/dist/data-sources/PriceDataSource.cjs.map +1 -1
- package/dist/data-sources/PriceDataSource.d.cts.map +1 -1
- package/dist/data-sources/PriceDataSource.d.mts.map +1 -1
- package/dist/data-sources/PriceDataSource.mjs +12 -19
- package/dist/data-sources/PriceDataSource.mjs.map +1 -1
- package/dist/data-sources/RpcDataSource.cjs +232 -42
- package/dist/data-sources/RpcDataSource.cjs.map +1 -1
- package/dist/data-sources/RpcDataSource.d.cts +5 -1
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -1
- package/dist/data-sources/RpcDataSource.d.mts +5 -1
- package/dist/data-sources/RpcDataSource.d.mts.map +1 -1
- package/dist/data-sources/RpcDataSource.mjs +229 -42
- package/dist/data-sources/RpcDataSource.mjs.map +1 -1
- 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.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +32 -27
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +12 -5
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +12 -5
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +32 -27
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs +23 -12
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts +8 -3
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts +8 -3
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs +23 -12
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.d.cts +2 -2
- 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 +2 -2
- package/dist/data-sources/evm-rpc-services/services/index.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/services/index.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/index.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/index.d.cts +1 -1
- package/dist/data-sources/evm-rpc-services/types/index.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/index.d.mts +1 -1
- package/dist/data-sources/evm-rpc-services/types/index.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/index.mjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/state.cjs.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/state.d.cts +9 -24
- package/dist/data-sources/evm-rpc-services/types/state.d.cts.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/state.d.mts +9 -24
- package/dist/data-sources/evm-rpc-services/types/state.d.mts.map +1 -1
- package/dist/data-sources/evm-rpc-services/types/state.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +40 -6
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +40 -6
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -10,13 +10,17 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
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");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
var _RpcDataSource_instances, _RpcDataSource_timeout, _RpcDataSource_tokenDetectionEnabled, _RpcDataSource_activeChains, _RpcDataSource_chainStatuses, _RpcDataSource_providerCache, _RpcDataSource_activeSubscriptions, _RpcDataSource_multicallClient, _RpcDataSource_balanceFetcher, _RpcDataSource_tokenDetector, _RpcDataSource_convertToHumanReadable, _RpcDataSource_collectMetadataForBalances, _RpcDataSource_handleBalanceUpdate, _RpcDataSource_handleDetectionUpdate, _RpcDataSource_registerActionHandlers, _RpcDataSource_subscribeToNetworkController, _RpcDataSource_initializeFromNetworkController, _RpcDataSource_updateFromNetworkState, _RpcDataSource_getProvider, _RpcDataSource_getMulticallProvider, _RpcDataSource_clearProviderCache, _RpcDataSource_accountSupportsChain, _RpcDataSource_buildNativeAssetId, _RpcDataSource_getExistingAssetsMetadata, _RpcDataSource_getTokenMetadataFromTokenList;
|
|
14
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
18
|
exports.createRpcDataSource = exports.RpcDataSource = exports.caipChainIdToHex = void 0;
|
|
16
19
|
const providers_1 = require("@ethersproject/providers");
|
|
17
20
|
const base_controller_1 = require("@metamask/base-controller");
|
|
18
21
|
const controller_utils_1 = require("@metamask/controller-utils");
|
|
19
22
|
const utils_1 = require("@metamask/utils");
|
|
23
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
20
24
|
const evm_rpc_services_1 = require("./evm-rpc-services/index.cjs");
|
|
21
25
|
const logger_1 = require("../logger.cjs");
|
|
22
26
|
const CONTROLLER_NAME = 'RpcDataSource';
|
|
@@ -94,24 +98,25 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
94
98
|
__classPrivateFieldSet(this, _RpcDataSource_multicallClient, new evm_rpc_services_1.MulticallClient((hexChainId) => {
|
|
95
99
|
return __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_getMulticallProvider).call(this, hexChainId);
|
|
96
100
|
}), "f");
|
|
97
|
-
// Create
|
|
98
|
-
const
|
|
99
|
-
|
|
101
|
+
// Create messenger adapters for BalanceFetcher and TokenDetector
|
|
102
|
+
const balanceFetcherMessenger = {
|
|
103
|
+
call: (_action) => {
|
|
104
|
+
const state = this.messenger.call('AssetsController:getState');
|
|
105
|
+
return {
|
|
106
|
+
assetsBalance: (state.assetsBalance ?? {}),
|
|
107
|
+
};
|
|
108
|
+
},
|
|
100
109
|
};
|
|
101
|
-
const
|
|
102
|
-
|
|
110
|
+
const tokenDetectorMessenger = {
|
|
111
|
+
call: (_action) => {
|
|
112
|
+
return this.messenger.call('TokenListController:getState');
|
|
113
|
+
},
|
|
103
114
|
};
|
|
104
115
|
// Initialize BalanceFetcher with polling interval
|
|
105
|
-
__classPrivateFieldSet(this, _RpcDataSource_balanceFetcher, new evm_rpc_services_1.BalanceFetcher(__classPrivateFieldGet(this, _RpcDataSource_multicallClient, "f"), {
|
|
106
|
-
pollingInterval: balanceInterval,
|
|
107
|
-
}), "f");
|
|
108
|
-
__classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").setUserTokensStateGetter(getUserTokensState);
|
|
116
|
+
__classPrivateFieldSet(this, _RpcDataSource_balanceFetcher, new evm_rpc_services_1.BalanceFetcher(__classPrivateFieldGet(this, _RpcDataSource_multicallClient, "f"), balanceFetcherMessenger, { pollingInterval: balanceInterval }), "f");
|
|
109
117
|
__classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").setOnBalanceUpdate(__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_handleBalanceUpdate).bind(this));
|
|
110
118
|
// Initialize TokenDetector with polling interval
|
|
111
|
-
__classPrivateFieldSet(this, _RpcDataSource_tokenDetector, new evm_rpc_services_1.TokenDetector(__classPrivateFieldGet(this, _RpcDataSource_multicallClient, "f"), {
|
|
112
|
-
pollingInterval: detectionInterval,
|
|
113
|
-
}), "f");
|
|
114
|
-
__classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").setTokenListStateGetter(getTokenListState);
|
|
119
|
+
__classPrivateFieldSet(this, _RpcDataSource_tokenDetector, new evm_rpc_services_1.TokenDetector(__classPrivateFieldGet(this, _RpcDataSource_multicallClient, "f"), tokenDetectorMessenger, { pollingInterval: detectionInterval }), "f");
|
|
115
120
|
__classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").setOnDetectionUpdate(__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_handleDetectionUpdate).bind(this));
|
|
116
121
|
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_registerActionHandlers).call(this);
|
|
117
122
|
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_subscribeToNetworkController).call(this);
|
|
@@ -197,6 +202,7 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
197
202
|
return response;
|
|
198
203
|
}
|
|
199
204
|
const assetsBalance = {};
|
|
205
|
+
const assetsMetadata = {};
|
|
200
206
|
const failedChains = [];
|
|
201
207
|
// Fetch balances for each chain using BalanceFetcher
|
|
202
208
|
for (const chainId of chainsToFetch) {
|
|
@@ -213,10 +219,17 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
213
219
|
if (!assetsBalance[accountId]) {
|
|
214
220
|
assetsBalance[accountId] = {};
|
|
215
221
|
}
|
|
216
|
-
//
|
|
222
|
+
// Collect metadata for all balances
|
|
223
|
+
const balanceMetadata = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_collectMetadataForBalances).call(this, result.balances, chainId);
|
|
224
|
+
Object.assign(assetsMetadata, balanceMetadata);
|
|
225
|
+
// Convert balances to human-readable format
|
|
217
226
|
for (const balance of result.balances) {
|
|
227
|
+
const metadata = assetsMetadata[balance.assetId];
|
|
228
|
+
// Default to 18 decimals (ERC20 standard) for consistent human-readable format
|
|
229
|
+
const decimals = metadata?.decimals ?? 18;
|
|
230
|
+
const humanReadableAmount = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_convertToHumanReadable).call(this, balance.balance, decimals);
|
|
218
231
|
assetsBalance[accountId][balance.assetId] = {
|
|
219
|
-
amount:
|
|
232
|
+
amount: humanReadableAmount,
|
|
220
233
|
};
|
|
221
234
|
}
|
|
222
235
|
}
|
|
@@ -227,6 +240,16 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
227
240
|
}
|
|
228
241
|
const nativeAssetId = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_buildNativeAssetId).call(this, chainId);
|
|
229
242
|
assetsBalance[accountId][nativeAssetId] = { amount: '0' };
|
|
243
|
+
// Even on error, include native token metadata
|
|
244
|
+
const chainStatus = __classPrivateFieldGet(this, _RpcDataSource_chainStatuses, "f")[chainId];
|
|
245
|
+
if (chainStatus) {
|
|
246
|
+
assetsMetadata[nativeAssetId] = {
|
|
247
|
+
type: 'native',
|
|
248
|
+
symbol: chainStatus.nativeCurrency,
|
|
249
|
+
name: chainStatus.nativeCurrency,
|
|
250
|
+
decimals: 18,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
230
253
|
if (!failedChains.includes(chainId)) {
|
|
231
254
|
failedChains.push(chainId);
|
|
232
255
|
}
|
|
@@ -250,6 +273,10 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
250
273
|
});
|
|
251
274
|
}
|
|
252
275
|
response.assetsBalance = assetsBalance;
|
|
276
|
+
// Include metadata for native tokens if we have any
|
|
277
|
+
if (Object.keys(assetsMetadata).length > 0) {
|
|
278
|
+
response.assetsMetadata = assetsMetadata;
|
|
279
|
+
}
|
|
253
280
|
return response;
|
|
254
281
|
}
|
|
255
282
|
/**
|
|
@@ -279,10 +306,27 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
279
306
|
});
|
|
280
307
|
// Convert detected assets to DataResponse format
|
|
281
308
|
const balances = {};
|
|
282
|
-
|
|
309
|
+
const assetsMetadata = {};
|
|
310
|
+
// Build metadata from detected assets
|
|
311
|
+
for (const asset of result.detectedAssets) {
|
|
312
|
+
if (asset.symbol && asset.decimals !== undefined) {
|
|
313
|
+
assetsMetadata[asset.assetId] = {
|
|
314
|
+
type: 'erc20',
|
|
315
|
+
symbol: asset.symbol,
|
|
316
|
+
name: asset.name ?? asset.symbol,
|
|
317
|
+
decimals: asset.decimals,
|
|
318
|
+
image: asset.image,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// Add balances for detected tokens (converted to human-readable format)
|
|
283
323
|
for (const balance of result.detectedBalances) {
|
|
324
|
+
const detectedAsset = result.detectedAssets.find((asset) => asset.assetId === balance.assetId);
|
|
325
|
+
// Default to 18 decimals (ERC20 standard) for consistent human-readable format
|
|
326
|
+
const decimals = detectedAsset?.decimals ?? 18;
|
|
327
|
+
const humanReadableAmount = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_convertToHumanReadable).call(this, balance.balance, decimals);
|
|
284
328
|
balances[balance.assetId] = {
|
|
285
|
-
amount:
|
|
329
|
+
amount: humanReadableAmount,
|
|
286
330
|
};
|
|
287
331
|
}
|
|
288
332
|
const response = {
|
|
@@ -293,6 +337,10 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
293
337
|
[accountId]: balances,
|
|
294
338
|
},
|
|
295
339
|
};
|
|
340
|
+
// Include metadata if we have any
|
|
341
|
+
if (Object.keys(assetsMetadata).length > 0) {
|
|
342
|
+
response.assetsMetadata = assetsMetadata;
|
|
343
|
+
}
|
|
296
344
|
return response;
|
|
297
345
|
}
|
|
298
346
|
catch (error) {
|
|
@@ -302,7 +350,7 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
302
350
|
}
|
|
303
351
|
get assetsMiddleware() {
|
|
304
352
|
return async (context, next) => {
|
|
305
|
-
var _a, _b;
|
|
353
|
+
var _a, _b, _c;
|
|
306
354
|
const { request } = context;
|
|
307
355
|
const supportedChains = request.chainIds.filter((chainId) => __classPrivateFieldGet(this, _RpcDataSource_activeChains, "f").includes(chainId));
|
|
308
356
|
if (supportedChains.length === 0) {
|
|
@@ -327,6 +375,13 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
327
375
|
};
|
|
328
376
|
}
|
|
329
377
|
}
|
|
378
|
+
if (response.assetsMetadata) {
|
|
379
|
+
(_c = context.response).assetsMetadata ?? (_c.assetsMetadata = {});
|
|
380
|
+
context.response.assetsMetadata = {
|
|
381
|
+
...context.response.assetsMetadata,
|
|
382
|
+
...response.assetsMetadata,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
330
385
|
const failedChains = new Set(Object.keys(response.errors ?? {}));
|
|
331
386
|
successfullyHandledChains = supportedChains.filter((chainId) => !failedChains.has(chainId));
|
|
332
387
|
if (successfullyHandledChains.length > 0) {
|
|
@@ -361,20 +416,19 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
361
416
|
log('No active chains to subscribe');
|
|
362
417
|
return;
|
|
363
418
|
}
|
|
364
|
-
// Handle subscription update
|
|
419
|
+
// Handle subscription update - restart polling for new chains
|
|
365
420
|
if (isUpdate) {
|
|
366
421
|
const existing = __classPrivateFieldGet(this, _RpcDataSource_activeSubscriptions, "f").get(subscriptionId);
|
|
367
422
|
if (existing) {
|
|
368
|
-
log('Updating existing subscription', {
|
|
423
|
+
log('Updating existing subscription - restarting polling', {
|
|
369
424
|
subscriptionId,
|
|
370
|
-
|
|
425
|
+
existingChains: existing.chains,
|
|
426
|
+
newChains: chainsToSubscribe,
|
|
371
427
|
});
|
|
372
|
-
|
|
373
|
-
existing.accounts = request.accounts;
|
|
374
|
-
return;
|
|
428
|
+
// Don't return early - continue to unsubscribe and restart polling
|
|
375
429
|
}
|
|
376
430
|
}
|
|
377
|
-
// Clean up existing subscription
|
|
431
|
+
// Clean up existing subscription (stops old polling)
|
|
378
432
|
await this.unsubscribe(subscriptionId);
|
|
379
433
|
// Start polling through BalanceFetcher and TokenDetector
|
|
380
434
|
const balancePollingTokens = [];
|
|
@@ -455,18 +509,82 @@ class RpcDataSource extends base_controller_1.BaseController {
|
|
|
455
509
|
}
|
|
456
510
|
}
|
|
457
511
|
exports.RpcDataSource = RpcDataSource;
|
|
458
|
-
_RpcDataSource_timeout = new WeakMap(), _RpcDataSource_tokenDetectionEnabled = new WeakMap(), _RpcDataSource_activeChains = new WeakMap(), _RpcDataSource_chainStatuses = new WeakMap(), _RpcDataSource_providerCache = new WeakMap(), _RpcDataSource_activeSubscriptions = new WeakMap(), _RpcDataSource_multicallClient = new WeakMap(), _RpcDataSource_balanceFetcher = new WeakMap(), _RpcDataSource_tokenDetector = new WeakMap(), _RpcDataSource_instances = new WeakSet(),
|
|
459
|
-
const
|
|
512
|
+
_RpcDataSource_timeout = new WeakMap(), _RpcDataSource_tokenDetectionEnabled = new WeakMap(), _RpcDataSource_activeChains = new WeakMap(), _RpcDataSource_chainStatuses = new WeakMap(), _RpcDataSource_providerCache = new WeakMap(), _RpcDataSource_activeSubscriptions = new WeakMap(), _RpcDataSource_multicallClient = new WeakMap(), _RpcDataSource_balanceFetcher = new WeakMap(), _RpcDataSource_tokenDetector = new WeakMap(), _RpcDataSource_instances = new WeakSet(), _RpcDataSource_convertToHumanReadable = function _RpcDataSource_convertToHumanReadable(rawBalance, decimals) {
|
|
513
|
+
const rawAmount = new bignumber_js_1.default(rawBalance);
|
|
514
|
+
const divisor = new bignumber_js_1.default(10).pow(decimals);
|
|
515
|
+
return rawAmount.dividedBy(divisor).toString();
|
|
516
|
+
}, _RpcDataSource_collectMetadataForBalances = function _RpcDataSource_collectMetadataForBalances(balances, chainId) {
|
|
517
|
+
const assetsMetadata = {};
|
|
518
|
+
const existingMetadata = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_getExistingAssetsMetadata).call(this);
|
|
519
|
+
for (const balance of balances) {
|
|
520
|
+
const isNative = balance.assetId.includes('/slip44:');
|
|
521
|
+
if (isNative) {
|
|
522
|
+
const chainStatus = __classPrivateFieldGet(this, _RpcDataSource_chainStatuses, "f")[chainId];
|
|
523
|
+
if (chainStatus) {
|
|
524
|
+
assetsMetadata[balance.assetId] = {
|
|
525
|
+
type: 'native',
|
|
526
|
+
symbol: chainStatus.nativeCurrency,
|
|
527
|
+
name: chainStatus.nativeCurrency,
|
|
528
|
+
decimals: 18,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
else {
|
|
533
|
+
// For ERC20 tokens, try existing metadata from state first
|
|
534
|
+
const existingMeta = existingMetadata[balance.assetId];
|
|
535
|
+
if (existingMeta) {
|
|
536
|
+
assetsMetadata[balance.assetId] = existingMeta;
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
// Fallback to token list if not in state
|
|
540
|
+
const tokenListMeta = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_getTokenMetadataFromTokenList).call(this, balance.assetId);
|
|
541
|
+
if (tokenListMeta) {
|
|
542
|
+
assetsMetadata[balance.assetId] = tokenListMeta;
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
// Default metadata for unknown ERC20 tokens.
|
|
546
|
+
// Use 18 decimals (the standard for most ERC20 tokens)
|
|
547
|
+
// to ensure consistent human-readable balance format.
|
|
548
|
+
assetsMetadata[balance.assetId] = {
|
|
549
|
+
type: 'erc20',
|
|
550
|
+
symbol: '',
|
|
551
|
+
name: '',
|
|
552
|
+
decimals: 18,
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return assetsMetadata;
|
|
559
|
+
}, _RpcDataSource_handleBalanceUpdate = function _RpcDataSource_handleBalanceUpdate(result) {
|
|
560
|
+
const newBalances = {};
|
|
561
|
+
// Convert hex chain ID to CAIP-2 format
|
|
562
|
+
const chainIdDecimal = parseInt(result.chainId, 16);
|
|
563
|
+
const caipChainId = `eip155:${chainIdDecimal}`;
|
|
564
|
+
// Collect metadata for all balances
|
|
565
|
+
const assetsMetadata = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_collectMetadataForBalances).call(this, result.balances, caipChainId);
|
|
566
|
+
// Convert balances to human-readable format using metadata
|
|
460
567
|
for (const balance of result.balances) {
|
|
461
|
-
|
|
462
|
-
|
|
568
|
+
const metadata = assetsMetadata[balance.assetId];
|
|
569
|
+
// Default to 18 decimals (ERC20 standard) for consistent human-readable format
|
|
570
|
+
const decimals = metadata?.decimals ?? 18;
|
|
571
|
+
const humanReadableAmount = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_convertToHumanReadable).call(this, balance.balance, decimals);
|
|
572
|
+
newBalances[balance.assetId] = {
|
|
573
|
+
amount: humanReadableAmount,
|
|
463
574
|
};
|
|
464
575
|
}
|
|
576
|
+
// Only send new data to AssetsController - it handles merging atomically
|
|
577
|
+
// to avoid race conditions when concurrent updates occur for the same account
|
|
465
578
|
const response = {
|
|
466
579
|
assetsBalance: {
|
|
467
|
-
[result.accountId]:
|
|
580
|
+
[result.accountId]: newBalances,
|
|
468
581
|
},
|
|
582
|
+
assetsMetadata,
|
|
469
583
|
};
|
|
584
|
+
log('Balance update response', {
|
|
585
|
+
accountId: result.accountId,
|
|
586
|
+
newBalanceCount: Object.keys(newBalances).length,
|
|
587
|
+
});
|
|
470
588
|
this.messenger
|
|
471
589
|
.call('AssetsController:assetsUpdate', response, CONTROLLER_NAME)
|
|
472
590
|
.catch((error) => {
|
|
@@ -476,22 +594,47 @@ _RpcDataSource_timeout = new WeakMap(), _RpcDataSource_tokenDetectionEnabled = n
|
|
|
476
594
|
log('Detected new tokens', {
|
|
477
595
|
count: result.detectedAssets.length,
|
|
478
596
|
});
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
597
|
+
// Build new metadata from detected assets
|
|
598
|
+
const newMetadata = {};
|
|
599
|
+
if (result.detectedAssets.length > 0) {
|
|
600
|
+
for (const asset of result.detectedAssets) {
|
|
601
|
+
// Only include if we have metadata (symbol and decimals at minimum)
|
|
602
|
+
if (asset.symbol && asset.decimals !== undefined) {
|
|
603
|
+
newMetadata[asset.assetId] = {
|
|
604
|
+
type: 'erc20',
|
|
605
|
+
symbol: asset.symbol,
|
|
606
|
+
name: asset.name ?? asset.symbol,
|
|
607
|
+
decimals: asset.decimals,
|
|
608
|
+
image: asset.image,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
// Build new balances from detected tokens
|
|
614
|
+
const newBalances = {};
|
|
485
615
|
if (result.detectedBalances.length > 0) {
|
|
486
|
-
response.assetsBalance = {
|
|
487
|
-
[result.accountId]: {},
|
|
488
|
-
};
|
|
489
616
|
for (const balance of result.detectedBalances) {
|
|
490
|
-
|
|
491
|
-
|
|
617
|
+
// Get decimals from the detected asset metadata
|
|
618
|
+
const detectedAsset = result.detectedAssets.find((asset) => asset.assetId === balance.assetId);
|
|
619
|
+
// Default to 18 decimals (ERC20 standard) for consistent human-readable format
|
|
620
|
+
const decimals = detectedAsset?.decimals ?? 18;
|
|
621
|
+
const humanReadableAmount = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_convertToHumanReadable).call(this, balance.balance, decimals);
|
|
622
|
+
newBalances[balance.assetId] = {
|
|
623
|
+
amount: humanReadableAmount,
|
|
492
624
|
};
|
|
493
625
|
}
|
|
494
626
|
}
|
|
627
|
+
// Only send new data to AssetsController - it handles merging atomically
|
|
628
|
+
// to avoid race conditions when concurrent updates occur for the same account
|
|
629
|
+
const response = {
|
|
630
|
+
detectedAssets: {
|
|
631
|
+
[result.accountId]: result.detectedAssets.map((asset) => asset.assetId),
|
|
632
|
+
},
|
|
633
|
+
assetsMetadata: newMetadata,
|
|
634
|
+
assetsBalance: {
|
|
635
|
+
[result.accountId]: newBalances,
|
|
636
|
+
},
|
|
637
|
+
};
|
|
495
638
|
this.messenger
|
|
496
639
|
.call('AssetsController:assetsUpdate', response, CONTROLLER_NAME)
|
|
497
640
|
.catch((error) => {
|
|
@@ -631,6 +774,53 @@ _RpcDataSource_timeout = new WeakMap(), _RpcDataSource_tokenDetectionEnabled = n
|
|
|
631
774
|
const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
|
|
632
775
|
return (nativeAssetIdentifiers[chainId] ??
|
|
633
776
|
`${chainId}/slip44:60`);
|
|
777
|
+
}, _RpcDataSource_getExistingAssetsMetadata = function _RpcDataSource_getExistingAssetsMetadata() {
|
|
778
|
+
try {
|
|
779
|
+
const state = this.messenger.call('AssetsController:getState');
|
|
780
|
+
return (state.assetsMetadata ?? {});
|
|
781
|
+
}
|
|
782
|
+
catch {
|
|
783
|
+
// If AssetsController:getState fails, return empty metadata
|
|
784
|
+
return {};
|
|
785
|
+
}
|
|
786
|
+
}, _RpcDataSource_getTokenMetadataFromTokenList = function _RpcDataSource_getTokenMetadataFromTokenList(assetId) {
|
|
787
|
+
try {
|
|
788
|
+
// Parse asset ID to get chain and token address
|
|
789
|
+
// Format: eip155:{chainId}/erc20:{address}
|
|
790
|
+
const [chainPart, assetPart] = assetId.split('/');
|
|
791
|
+
if (!assetPart?.startsWith('erc20:')) {
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
const tokenAddress = assetPart.slice(6); // Remove 'erc20:' prefix
|
|
795
|
+
const chainIdDecimal = chainPart.split(':')[1];
|
|
796
|
+
const hexChainId = `0x${parseInt(chainIdDecimal, 10).toString(16)}`;
|
|
797
|
+
const tokenListState = this.messenger.call('TokenListController:getState');
|
|
798
|
+
const chainCacheEntry = tokenListState.tokensChainsCache[hexChainId];
|
|
799
|
+
const chainTokenList = chainCacheEntry?.data;
|
|
800
|
+
if (!chainTokenList) {
|
|
801
|
+
return undefined;
|
|
802
|
+
}
|
|
803
|
+
// Look up token by address (case-insensitive)
|
|
804
|
+
const lowerAddress = tokenAddress.toLowerCase();
|
|
805
|
+
for (const [address, tokenData] of Object.entries(chainTokenList)) {
|
|
806
|
+
if (address.toLowerCase() === lowerAddress) {
|
|
807
|
+
const token = tokenData;
|
|
808
|
+
if (token.symbol && token.decimals !== undefined) {
|
|
809
|
+
return {
|
|
810
|
+
type: 'erc20',
|
|
811
|
+
symbol: token.symbol,
|
|
812
|
+
name: token.name ?? token.symbol,
|
|
813
|
+
decimals: token.decimals,
|
|
814
|
+
image: token.iconUrl,
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
return undefined;
|
|
820
|
+
}
|
|
821
|
+
catch {
|
|
822
|
+
return undefined;
|
|
823
|
+
}
|
|
634
824
|
};
|
|
635
825
|
function createRpcDataSource(options) {
|
|
636
826
|
return new RpcDataSource(options);
|