@metamask/assets-controller 0.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 +37 -0
- package/LICENSE +20 -0
- package/README.md +15 -0
- package/dist/AssetsController.cjs +1057 -0
- package/dist/AssetsController.cjs.map +1 -0
- package/dist/AssetsController.d.cts +260 -0
- package/dist/AssetsController.d.cts.map +1 -0
- package/dist/AssetsController.d.mts +260 -0
- package/dist/AssetsController.d.mts.map +1 -0
- package/dist/AssetsController.mjs +1050 -0
- package/dist/AssetsController.mjs.map +1 -0
- package/dist/data-sources/AbstractDataSource.cjs +103 -0
- package/dist/data-sources/AbstractDataSource.cjs.map +1 -0
- package/dist/data-sources/AbstractDataSource.d.cts +92 -0
- package/dist/data-sources/AbstractDataSource.d.cts.map +1 -0
- package/dist/data-sources/AbstractDataSource.d.mts +92 -0
- package/dist/data-sources/AbstractDataSource.d.mts.map +1 -0
- package/dist/data-sources/AbstractDataSource.mjs +99 -0
- package/dist/data-sources/AbstractDataSource.mjs.map +1 -0
- package/dist/data-sources/AccountsApiDataSource.cjs +421 -0
- package/dist/data-sources/AccountsApiDataSource.cjs.map +1 -0
- package/dist/data-sources/AccountsApiDataSource.d.cts +103 -0
- package/dist/data-sources/AccountsApiDataSource.d.cts.map +1 -0
- package/dist/data-sources/AccountsApiDataSource.d.mts +103 -0
- package/dist/data-sources/AccountsApiDataSource.d.mts.map +1 -0
- package/dist/data-sources/AccountsApiDataSource.mjs +416 -0
- package/dist/data-sources/AccountsApiDataSource.mjs.map +1 -0
- package/dist/data-sources/BackendWebsocketDataSource.cjs +388 -0
- package/dist/data-sources/BackendWebsocketDataSource.cjs.map +1 -0
- package/dist/data-sources/BackendWebsocketDataSource.d.cts +95 -0
- package/dist/data-sources/BackendWebsocketDataSource.d.cts.map +1 -0
- package/dist/data-sources/BackendWebsocketDataSource.d.mts +95 -0
- package/dist/data-sources/BackendWebsocketDataSource.d.mts.map +1 -0
- package/dist/data-sources/BackendWebsocketDataSource.mjs +383 -0
- package/dist/data-sources/BackendWebsocketDataSource.mjs.map +1 -0
- package/dist/data-sources/PriceDataSource.cjs +343 -0
- package/dist/data-sources/PriceDataSource.cjs.map +1 -0
- package/dist/data-sources/PriceDataSource.d.cts +153 -0
- package/dist/data-sources/PriceDataSource.d.cts.map +1 -0
- package/dist/data-sources/PriceDataSource.d.mts +153 -0
- package/dist/data-sources/PriceDataSource.d.mts.map +1 -0
- package/dist/data-sources/PriceDataSource.mjs +339 -0
- package/dist/data-sources/PriceDataSource.mjs.map +1 -0
- package/dist/data-sources/RpcDataSource.cjs +829 -0
- package/dist/data-sources/RpcDataSource.cjs.map +1 -0
- package/dist/data-sources/RpcDataSource.d.cts +243 -0
- package/dist/data-sources/RpcDataSource.d.cts.map +1 -0
- package/dist/data-sources/RpcDataSource.d.mts +243 -0
- package/dist/data-sources/RpcDataSource.d.mts.map +1 -0
- package/dist/data-sources/RpcDataSource.mjs +820 -0
- package/dist/data-sources/RpcDataSource.mjs.map +1 -0
- package/dist/data-sources/SnapDataSource.cjs +463 -0
- package/dist/data-sources/SnapDataSource.cjs.map +1 -0
- package/dist/data-sources/SnapDataSource.d.cts +155 -0
- package/dist/data-sources/SnapDataSource.d.cts.map +1 -0
- package/dist/data-sources/SnapDataSource.d.mts +155 -0
- package/dist/data-sources/SnapDataSource.d.mts.map +1 -0
- package/dist/data-sources/SnapDataSource.mjs +456 -0
- package/dist/data-sources/SnapDataSource.mjs.map +1 -0
- package/dist/data-sources/TokenDataSource.cjs +211 -0
- package/dist/data-sources/TokenDataSource.cjs.map +1 -0
- package/dist/data-sources/TokenDataSource.d.cts +62 -0
- package/dist/data-sources/TokenDataSource.d.cts.map +1 -0
- package/dist/data-sources/TokenDataSource.d.mts +62 -0
- package/dist/data-sources/TokenDataSource.d.mts.map +1 -0
- package/dist/data-sources/TokenDataSource.mjs +207 -0
- package/dist/data-sources/TokenDataSource.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs +638 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts +47 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts +47 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs +632 -0
- package/dist/data-sources/evm-rpc-services/clients/MulticallClient.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/index.cjs +8 -0
- package/dist/data-sources/evm-rpc-services/clients/index.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/index.d.cts +3 -0
- package/dist/data-sources/evm-rpc-services/clients/index.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/index.d.mts +3 -0
- package/dist/data-sources/evm-rpc-services/clients/index.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/clients/index.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/clients/index.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/index.cjs +12 -0
- package/dist/data-sources/evm-rpc-services/index.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/index.d.cts +5 -0
- package/dist/data-sources/evm-rpc-services/index.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/index.d.mts +5 -0
- package/dist/data-sources/evm-rpc-services/index.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/index.mjs +4 -0
- package/dist/data-sources/evm-rpc-services/index.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs +202 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts +75 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts +75 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs +198 -0
- package/dist/data-sources/evm-rpc-services/services/BalanceFetcher.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs +214 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts +71 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts +71 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs +210 -0
- package/dist/data-sources/evm-rpc-services/services/TokenDetector.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/index.cjs +8 -0
- package/dist/data-sources/evm-rpc-services/services/index.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/index.d.cts +3 -0
- package/dist/data-sources/evm-rpc-services/services/index.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/index.d.mts +3 -0
- package/dist/data-sources/evm-rpc-services/services/index.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/services/index.mjs +3 -0
- package/dist/data-sources/evm-rpc-services/services/index.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/assets.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/assets.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/assets.d.cts +53 -0
- package/dist/data-sources/evm-rpc-services/types/assets.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/assets.d.mts +53 -0
- package/dist/data-sources/evm-rpc-services/types/assets.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/assets.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/assets.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/config.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/config.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/config.d.cts +18 -0
- package/dist/data-sources/evm-rpc-services/types/config.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/config.d.mts +18 -0
- package/dist/data-sources/evm-rpc-services/types/config.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/config.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/config.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/core.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/core.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/core.d.cts +19 -0
- package/dist/data-sources/evm-rpc-services/types/core.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/core.d.mts +19 -0
- package/dist/data-sources/evm-rpc-services/types/core.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/core.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/core.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/index.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/index.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/index.d.cts +7 -0
- package/dist/data-sources/evm-rpc-services/types/index.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/index.d.mts +7 -0
- package/dist/data-sources/evm-rpc-services/types/index.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/index.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/index.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.d.cts +24 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.d.mts +24 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/multicall.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/services.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/services.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/services.d.cts +74 -0
- package/dist/data-sources/evm-rpc-services/types/services.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/services.d.mts +74 -0
- package/dist/data-sources/evm-rpc-services/types/services.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/services.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/services.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/state.cjs +3 -0
- package/dist/data-sources/evm-rpc-services/types/state.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/state.d.cts +52 -0
- package/dist/data-sources/evm-rpc-services/types/state.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/state.d.mts +52 -0
- package/dist/data-sources/evm-rpc-services/types/state.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/types/state.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/types/state.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.cjs +45 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.d.cts +28 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.d.mts +28 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.mjs +40 -0
- package/dist/data-sources/evm-rpc-services/utils/batch.mjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/index.cjs +7 -0
- package/dist/data-sources/evm-rpc-services/utils/index.cjs.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/index.d.cts +2 -0
- package/dist/data-sources/evm-rpc-services/utils/index.d.cts.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/index.d.mts +2 -0
- package/dist/data-sources/evm-rpc-services/utils/index.d.mts.map +1 -0
- package/dist/data-sources/evm-rpc-services/utils/index.mjs +2 -0
- package/dist/data-sources/evm-rpc-services/utils/index.mjs.map +1 -0
- package/dist/data-sources/index.cjs +33 -0
- package/dist/data-sources/index.cjs.map +1 -0
- package/dist/data-sources/index.d.cts +9 -0
- package/dist/data-sources/index.d.cts.map +1 -0
- package/dist/data-sources/index.d.mts +9 -0
- package/dist/data-sources/index.d.mts.map +1 -0
- package/dist/data-sources/index.mjs +15 -0
- package/dist/data-sources/index.mjs.map +1 -0
- package/dist/data-sources/initDataSources.cjs +215 -0
- package/dist/data-sources/initDataSources.cjs.map +1 -0
- package/dist/data-sources/initDataSources.d.cts +140 -0
- package/dist/data-sources/initDataSources.d.cts.map +1 -0
- package/dist/data-sources/initDataSources.d.mts +140 -0
- package/dist/data-sources/initDataSources.d.mts.map +1 -0
- package/dist/data-sources/initDataSources.mjs +210 -0
- package/dist/data-sources/initDataSources.mjs.map +1 -0
- package/dist/index.cjs +47 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +21 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +25 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logger.cjs +7 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +5 -0
- package/dist/logger.d.cts.map +1 -0
- package/dist/logger.d.mts +5 -0
- package/dist/logger.d.mts.map +1 -0
- package/dist/logger.mjs +4 -0
- package/dist/logger.mjs.map +1 -0
- package/dist/middlewares/DetectionMiddleware.cjs +101 -0
- package/dist/middlewares/DetectionMiddleware.cjs.map +1 -0
- package/dist/middlewares/DetectionMiddleware.d.cts +54 -0
- package/dist/middlewares/DetectionMiddleware.d.cts.map +1 -0
- package/dist/middlewares/DetectionMiddleware.d.mts +54 -0
- package/dist/middlewares/DetectionMiddleware.d.mts.map +1 -0
- package/dist/middlewares/DetectionMiddleware.mjs +97 -0
- package/dist/middlewares/DetectionMiddleware.mjs.map +1 -0
- package/dist/middlewares/index.cjs +6 -0
- package/dist/middlewares/index.cjs.map +1 -0
- package/dist/middlewares/index.d.cts +2 -0
- package/dist/middlewares/index.d.cts.map +1 -0
- package/dist/middlewares/index.d.mts +2 -0
- package/dist/middlewares/index.d.mts.map +1 -0
- package/dist/middlewares/index.mjs +2 -0
- package/dist/middlewares/index.mjs.map +1 -0
- package/dist/types.cjs +39 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +433 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +433 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +35 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils.cjs +28 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +13 -0
- package/dist/utils.d.cts.map +1 -0
- package/dist/utils.d.mts +13 -0
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +24 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
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");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
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
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
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;
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.createRpcDataSource = exports.RpcDataSource = exports.caipChainIdToHex = void 0;
|
|
19
|
+
const providers_1 = require("@ethersproject/providers");
|
|
20
|
+
const base_controller_1 = require("@metamask/base-controller");
|
|
21
|
+
const controller_utils_1 = require("@metamask/controller-utils");
|
|
22
|
+
const utils_1 = require("@metamask/utils");
|
|
23
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
24
|
+
const evm_rpc_services_1 = require("./evm-rpc-services/index.cjs");
|
|
25
|
+
const logger_1 = require("../logger.cjs");
|
|
26
|
+
const CONTROLLER_NAME = 'RpcDataSource';
|
|
27
|
+
const DEFAULT_BALANCE_INTERVAL = 30000; // 30 seconds
|
|
28
|
+
const DEFAULT_DETECTION_INTERVAL = 180000; // 3 minutes
|
|
29
|
+
const log = (0, logger_1.createModuleLogger)(logger_1.projectLogger, CONTROLLER_NAME);
|
|
30
|
+
/**
|
|
31
|
+
* Convert CAIP chain ID or hex chain ID to hex chain ID.
|
|
32
|
+
*
|
|
33
|
+
* @param chainId - CAIP chain ID or hex chain ID.
|
|
34
|
+
* @returns Hex chain ID.
|
|
35
|
+
*/
|
|
36
|
+
const caipChainIdToHex = (chainId) => {
|
|
37
|
+
if ((0, utils_1.isStrictHexString)(chainId)) {
|
|
38
|
+
return chainId;
|
|
39
|
+
}
|
|
40
|
+
if ((0, utils_1.isCaipChainId)(chainId)) {
|
|
41
|
+
return (0, controller_utils_1.toHex)((0, utils_1.parseCaipChainId)(chainId).reference);
|
|
42
|
+
}
|
|
43
|
+
throw new Error('caipChainIdToHex - Failed to provide CAIP-2 or Hex chainId');
|
|
44
|
+
};
|
|
45
|
+
exports.caipChainIdToHex = caipChainIdToHex;
|
|
46
|
+
/**
|
|
47
|
+
* Data source for fetching balances via RPC calls.
|
|
48
|
+
*
|
|
49
|
+
* Orchestrates polling through BalanceFetcher and TokenDetector,
|
|
50
|
+
* each of which handle their own polling intervals.
|
|
51
|
+
*
|
|
52
|
+
* Communicates with AssetsController via Messenger:
|
|
53
|
+
*
|
|
54
|
+
* Actions:
|
|
55
|
+
* - RpcDataSource:getActiveChains
|
|
56
|
+
* - RpcDataSource:fetch
|
|
57
|
+
* - RpcDataSource:subscribe
|
|
58
|
+
* - RpcDataSource:unsubscribe
|
|
59
|
+
*
|
|
60
|
+
* Events:
|
|
61
|
+
* - RpcDataSource:activeChainsUpdated
|
|
62
|
+
* - RpcDataSource:assetsUpdated
|
|
63
|
+
*/
|
|
64
|
+
class RpcDataSource extends base_controller_1.BaseController {
|
|
65
|
+
constructor(options) {
|
|
66
|
+
super({
|
|
67
|
+
name: CONTROLLER_NAME,
|
|
68
|
+
metadata: {},
|
|
69
|
+
state: {},
|
|
70
|
+
messenger: options.messenger,
|
|
71
|
+
});
|
|
72
|
+
_RpcDataSource_instances.add(this);
|
|
73
|
+
_RpcDataSource_timeout.set(this, void 0);
|
|
74
|
+
_RpcDataSource_tokenDetectionEnabled.set(this, void 0);
|
|
75
|
+
/** Currently active chains */
|
|
76
|
+
_RpcDataSource_activeChains.set(this, []);
|
|
77
|
+
/** Network status for each active chain */
|
|
78
|
+
_RpcDataSource_chainStatuses.set(this, {});
|
|
79
|
+
/** Cache of Web3Provider instances by chainId */
|
|
80
|
+
_RpcDataSource_providerCache.set(this, new Map());
|
|
81
|
+
/** Active subscriptions by ID */
|
|
82
|
+
_RpcDataSource_activeSubscriptions.set(this, new Map());
|
|
83
|
+
// Rpc-datasource components
|
|
84
|
+
_RpcDataSource_multicallClient.set(this, void 0);
|
|
85
|
+
_RpcDataSource_balanceFetcher.set(this, void 0);
|
|
86
|
+
_RpcDataSource_tokenDetector.set(this, void 0);
|
|
87
|
+
__classPrivateFieldSet(this, _RpcDataSource_timeout, options.timeout ?? 10000, "f");
|
|
88
|
+
__classPrivateFieldSet(this, _RpcDataSource_tokenDetectionEnabled, options.tokenDetectionEnabled ?? false, "f");
|
|
89
|
+
const balanceInterval = options.balanceInterval ?? DEFAULT_BALANCE_INTERVAL;
|
|
90
|
+
const detectionInterval = options.detectionInterval ?? DEFAULT_DETECTION_INTERVAL;
|
|
91
|
+
log('Initializing RpcDataSource', {
|
|
92
|
+
timeout: __classPrivateFieldGet(this, _RpcDataSource_timeout, "f"),
|
|
93
|
+
balanceInterval,
|
|
94
|
+
detectionInterval,
|
|
95
|
+
tokenDetectionEnabled: __classPrivateFieldGet(this, _RpcDataSource_tokenDetectionEnabled, "f"),
|
|
96
|
+
});
|
|
97
|
+
// Initialize MulticallClient with a provider getter
|
|
98
|
+
__classPrivateFieldSet(this, _RpcDataSource_multicallClient, new evm_rpc_services_1.MulticallClient((hexChainId) => {
|
|
99
|
+
return __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_getMulticallProvider).call(this, hexChainId);
|
|
100
|
+
}), "f");
|
|
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
|
+
},
|
|
109
|
+
};
|
|
110
|
+
const tokenDetectorMessenger = {
|
|
111
|
+
call: (_action) => {
|
|
112
|
+
return this.messenger.call('TokenListController:getState');
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
// Initialize BalanceFetcher with polling interval
|
|
116
|
+
__classPrivateFieldSet(this, _RpcDataSource_balanceFetcher, new evm_rpc_services_1.BalanceFetcher(__classPrivateFieldGet(this, _RpcDataSource_multicallClient, "f"), balanceFetcherMessenger, { pollingInterval: balanceInterval }), "f");
|
|
117
|
+
__classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").setOnBalanceUpdate(__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_handleBalanceUpdate).bind(this));
|
|
118
|
+
// Initialize TokenDetector with polling interval
|
|
119
|
+
__classPrivateFieldSet(this, _RpcDataSource_tokenDetector, new evm_rpc_services_1.TokenDetector(__classPrivateFieldGet(this, _RpcDataSource_multicallClient, "f"), tokenDetectorMessenger, { pollingInterval: detectionInterval }), "f");
|
|
120
|
+
__classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").setOnDetectionUpdate(__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_handleDetectionUpdate).bind(this));
|
|
121
|
+
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_registerActionHandlers).call(this);
|
|
122
|
+
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_subscribeToNetworkController).call(this);
|
|
123
|
+
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_initializeFromNetworkController).call(this);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get the data source name.
|
|
127
|
+
*
|
|
128
|
+
* @returns The name of this data source.
|
|
129
|
+
*/
|
|
130
|
+
getName() {
|
|
131
|
+
return this.name;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get currently active chains.
|
|
135
|
+
*
|
|
136
|
+
* @returns Promise resolving to array of active chain IDs.
|
|
137
|
+
*/
|
|
138
|
+
async getActiveChains() {
|
|
139
|
+
return __classPrivateFieldGet(this, _RpcDataSource_activeChains, "f");
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the status of all configured chains.
|
|
143
|
+
*
|
|
144
|
+
* @returns Record of chain statuses keyed by chain ID.
|
|
145
|
+
*/
|
|
146
|
+
getChainStatuses() {
|
|
147
|
+
return { ...__classPrivateFieldGet(this, _RpcDataSource_chainStatuses, "f") };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get the status of a specific chain.
|
|
151
|
+
*
|
|
152
|
+
* @param chainId - The chain ID to get status for.
|
|
153
|
+
* @returns The chain status or undefined if not found.
|
|
154
|
+
*/
|
|
155
|
+
getChainStatus(chainId) {
|
|
156
|
+
return __classPrivateFieldGet(this, _RpcDataSource_chainStatuses, "f")[chainId];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Set the balance polling interval.
|
|
160
|
+
*
|
|
161
|
+
* @param interval - The polling interval in milliseconds.
|
|
162
|
+
*/
|
|
163
|
+
setBalancePollingInterval(interval) {
|
|
164
|
+
log('Setting balance polling interval', { interval });
|
|
165
|
+
__classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").setIntervalLength(interval);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get the current balance polling interval.
|
|
169
|
+
*
|
|
170
|
+
* @returns The polling interval in milliseconds, or undefined if not set.
|
|
171
|
+
*/
|
|
172
|
+
getBalancePollingInterval() {
|
|
173
|
+
return __classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").getIntervalLength();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Set the token detection polling interval.
|
|
177
|
+
*
|
|
178
|
+
* @param interval - The polling interval in milliseconds.
|
|
179
|
+
*/
|
|
180
|
+
setDetectionPollingInterval(interval) {
|
|
181
|
+
log('Setting detection polling interval', { interval });
|
|
182
|
+
__classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").setIntervalLength(interval);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get the current token detection polling interval.
|
|
186
|
+
*
|
|
187
|
+
* @returns The polling interval in milliseconds, or undefined if not set.
|
|
188
|
+
*/
|
|
189
|
+
getDetectionPollingInterval() {
|
|
190
|
+
return __classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").getIntervalLength();
|
|
191
|
+
}
|
|
192
|
+
async fetch(request) {
|
|
193
|
+
const response = {};
|
|
194
|
+
const chainsToFetch = request.chainIds.filter((chainId) => __classPrivateFieldGet(this, _RpcDataSource_activeChains, "f").includes(chainId));
|
|
195
|
+
log('Fetch requested', {
|
|
196
|
+
accounts: request.accounts.map((a) => a.id),
|
|
197
|
+
requestedChains: request.chainIds,
|
|
198
|
+
chainsToFetch,
|
|
199
|
+
});
|
|
200
|
+
if (chainsToFetch.length === 0) {
|
|
201
|
+
log('No active chains to fetch');
|
|
202
|
+
return response;
|
|
203
|
+
}
|
|
204
|
+
const assetsBalance = {};
|
|
205
|
+
const assetsMetadata = {};
|
|
206
|
+
const failedChains = [];
|
|
207
|
+
// Fetch balances for each chain using BalanceFetcher
|
|
208
|
+
for (const chainId of chainsToFetch) {
|
|
209
|
+
const hexChainId = (0, exports.caipChainIdToHex)(chainId);
|
|
210
|
+
for (const account of request.accounts) {
|
|
211
|
+
if (!__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_accountSupportsChain).call(this, account, chainId)) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const { address, id: accountId } = account;
|
|
215
|
+
try {
|
|
216
|
+
// Use BalanceFetcher for batched balance fetching
|
|
217
|
+
const result = await __classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").fetchBalancesForTokens(hexChainId, accountId, address, [], // Empty array means just native token
|
|
218
|
+
{ includeNative: true });
|
|
219
|
+
if (!assetsBalance[accountId]) {
|
|
220
|
+
assetsBalance[accountId] = {};
|
|
221
|
+
}
|
|
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
|
|
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);
|
|
231
|
+
assetsBalance[accountId][balance.assetId] = {
|
|
232
|
+
amount: humanReadableAmount,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
log('Failed to fetch balance', { address, chainId, error });
|
|
238
|
+
if (!assetsBalance[accountId]) {
|
|
239
|
+
assetsBalance[accountId] = {};
|
|
240
|
+
}
|
|
241
|
+
const nativeAssetId = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_buildNativeAssetId).call(this, chainId);
|
|
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
|
+
}
|
|
253
|
+
if (!failedChains.includes(chainId)) {
|
|
254
|
+
failedChains.push(chainId);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (failedChains.length > 0) {
|
|
260
|
+
log('Fetch PARTIAL - some chains failed', {
|
|
261
|
+
successChains: chainsToFetch.filter((chain) => !failedChains.includes(chain)),
|
|
262
|
+
failedChains,
|
|
263
|
+
});
|
|
264
|
+
response.errors = {};
|
|
265
|
+
for (const chainId of failedChains) {
|
|
266
|
+
response.errors[chainId] = 'RPC fetch failed';
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
log('Fetch SUCCESS', {
|
|
271
|
+
chains: chainsToFetch,
|
|
272
|
+
accountCount: Object.keys(assetsBalance).length,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
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
|
+
}
|
|
280
|
+
return response;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Run token detection for an account on a chain.
|
|
284
|
+
*
|
|
285
|
+
* @param chainId - The chain ID to detect tokens on.
|
|
286
|
+
* @param account - The account to detect tokens for.
|
|
287
|
+
* @returns Promise resolving to a DataResponse with detected assets.
|
|
288
|
+
*/
|
|
289
|
+
async detectTokens(chainId, account) {
|
|
290
|
+
if (!__classPrivateFieldGet(this, _RpcDataSource_tokenDetectionEnabled, "f")) {
|
|
291
|
+
return {};
|
|
292
|
+
}
|
|
293
|
+
const hexChainId = (0, exports.caipChainIdToHex)(chainId);
|
|
294
|
+
const { address, id: accountId } = account;
|
|
295
|
+
log('Running token detection', { chainId, accountId });
|
|
296
|
+
try {
|
|
297
|
+
const result = await __classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").detectTokens(hexChainId, accountId, address);
|
|
298
|
+
if (result.detectedAssets.length === 0) {
|
|
299
|
+
log('No new tokens detected');
|
|
300
|
+
return {};
|
|
301
|
+
}
|
|
302
|
+
log('Detected new tokens', {
|
|
303
|
+
count: result.detectedAssets.length,
|
|
304
|
+
chainId,
|
|
305
|
+
accountId,
|
|
306
|
+
});
|
|
307
|
+
// Convert detected assets to DataResponse format
|
|
308
|
+
const balances = {};
|
|
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)
|
|
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);
|
|
328
|
+
balances[balance.assetId] = {
|
|
329
|
+
amount: humanReadableAmount,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
const response = {
|
|
333
|
+
detectedAssets: {
|
|
334
|
+
[accountId]: result.detectedAssets.map((asset) => asset.assetId),
|
|
335
|
+
},
|
|
336
|
+
assetsBalance: {
|
|
337
|
+
[accountId]: balances,
|
|
338
|
+
},
|
|
339
|
+
};
|
|
340
|
+
// Include metadata if we have any
|
|
341
|
+
if (Object.keys(assetsMetadata).length > 0) {
|
|
342
|
+
response.assetsMetadata = assetsMetadata;
|
|
343
|
+
}
|
|
344
|
+
return response;
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
log('Token detection failed', { chainId, accountId, error });
|
|
348
|
+
return {};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
get assetsMiddleware() {
|
|
352
|
+
return async (context, next) => {
|
|
353
|
+
var _a, _b, _c;
|
|
354
|
+
const { request } = context;
|
|
355
|
+
const supportedChains = request.chainIds.filter((chainId) => __classPrivateFieldGet(this, _RpcDataSource_activeChains, "f").includes(chainId));
|
|
356
|
+
if (supportedChains.length === 0) {
|
|
357
|
+
return next(context);
|
|
358
|
+
}
|
|
359
|
+
let successfullyHandledChains = [];
|
|
360
|
+
log('Middleware fetching', {
|
|
361
|
+
chains: supportedChains,
|
|
362
|
+
accounts: request.accounts.map((a) => a.id),
|
|
363
|
+
});
|
|
364
|
+
const response = await this.fetch({
|
|
365
|
+
...request,
|
|
366
|
+
chainIds: supportedChains,
|
|
367
|
+
});
|
|
368
|
+
if (response.assetsBalance) {
|
|
369
|
+
(_a = context.response).assetsBalance ?? (_a.assetsBalance = {});
|
|
370
|
+
for (const [accountId, accountBalances] of Object.entries(response.assetsBalance)) {
|
|
371
|
+
(_b = context.response.assetsBalance)[accountId] ?? (_b[accountId] = {});
|
|
372
|
+
context.response.assetsBalance[accountId] = {
|
|
373
|
+
...context.response.assetsBalance[accountId],
|
|
374
|
+
...accountBalances,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
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
|
+
}
|
|
385
|
+
const failedChains = new Set(Object.keys(response.errors ?? {}));
|
|
386
|
+
successfullyHandledChains = supportedChains.filter((chainId) => !failedChains.has(chainId));
|
|
387
|
+
if (successfullyHandledChains.length > 0) {
|
|
388
|
+
const remainingChains = request.chainIds.filter((chainId) => !successfullyHandledChains.includes(chainId));
|
|
389
|
+
return next({
|
|
390
|
+
...context,
|
|
391
|
+
request: {
|
|
392
|
+
...request,
|
|
393
|
+
chainIds: remainingChains,
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
return next(context);
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Subscribe to updates for the given request.
|
|
402
|
+
* Starts polling through BalanceFetcher and TokenDetector.
|
|
403
|
+
*
|
|
404
|
+
* @param subscriptionRequest - The subscription request details.
|
|
405
|
+
*/
|
|
406
|
+
async subscribe(subscriptionRequest) {
|
|
407
|
+
const { request, subscriptionId, isUpdate } = subscriptionRequest;
|
|
408
|
+
const chainsToSubscribe = request.chainIds.filter((chainId) => __classPrivateFieldGet(this, _RpcDataSource_activeChains, "f").includes(chainId));
|
|
409
|
+
log('Subscribe requested', {
|
|
410
|
+
subscriptionId,
|
|
411
|
+
isUpdate,
|
|
412
|
+
accounts: request.accounts.map((a) => a.id),
|
|
413
|
+
chainsToSubscribe,
|
|
414
|
+
});
|
|
415
|
+
if (chainsToSubscribe.length === 0) {
|
|
416
|
+
log('No active chains to subscribe');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
// Handle subscription update - restart polling for new chains
|
|
420
|
+
if (isUpdate) {
|
|
421
|
+
const existing = __classPrivateFieldGet(this, _RpcDataSource_activeSubscriptions, "f").get(subscriptionId);
|
|
422
|
+
if (existing) {
|
|
423
|
+
log('Updating existing subscription - restarting polling', {
|
|
424
|
+
subscriptionId,
|
|
425
|
+
existingChains: existing.chains,
|
|
426
|
+
newChains: chainsToSubscribe,
|
|
427
|
+
});
|
|
428
|
+
// Don't return early - continue to unsubscribe and restart polling
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// Clean up existing subscription (stops old polling)
|
|
432
|
+
await this.unsubscribe(subscriptionId);
|
|
433
|
+
// Start polling through BalanceFetcher and TokenDetector
|
|
434
|
+
const balancePollingTokens = [];
|
|
435
|
+
const detectionPollingTokens = [];
|
|
436
|
+
for (const chainId of chainsToSubscribe) {
|
|
437
|
+
const hexChainId = (0, exports.caipChainIdToHex)(chainId);
|
|
438
|
+
for (const account of request.accounts) {
|
|
439
|
+
if (!__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_accountSupportsChain).call(this, account, chainId)) {
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
const { address, id: accountId } = account;
|
|
443
|
+
// Start balance polling
|
|
444
|
+
const balanceInput = {
|
|
445
|
+
chainId: hexChainId,
|
|
446
|
+
accountId,
|
|
447
|
+
accountAddress: address,
|
|
448
|
+
};
|
|
449
|
+
const balanceToken = __classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").startPolling(balanceInput);
|
|
450
|
+
balancePollingTokens.push(balanceToken);
|
|
451
|
+
// Start detection polling if enabled
|
|
452
|
+
if (__classPrivateFieldGet(this, _RpcDataSource_tokenDetectionEnabled, "f")) {
|
|
453
|
+
const detectionInput = {
|
|
454
|
+
chainId: hexChainId,
|
|
455
|
+
accountId,
|
|
456
|
+
accountAddress: address,
|
|
457
|
+
};
|
|
458
|
+
const detectionToken = __classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").startPolling(detectionInput);
|
|
459
|
+
detectionPollingTokens.push(detectionToken);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// Store subscription data
|
|
464
|
+
__classPrivateFieldGet(this, _RpcDataSource_activeSubscriptions, "f").set(subscriptionId, {
|
|
465
|
+
balancePollingTokens,
|
|
466
|
+
detectionPollingTokens,
|
|
467
|
+
chains: chainsToSubscribe,
|
|
468
|
+
accounts: request.accounts,
|
|
469
|
+
});
|
|
470
|
+
log('Subscription SUCCESS', {
|
|
471
|
+
subscriptionId,
|
|
472
|
+
chains: chainsToSubscribe,
|
|
473
|
+
balancePollingCount: balancePollingTokens.length,
|
|
474
|
+
detectionPollingCount: detectionPollingTokens.length,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Unsubscribe from updates and stop polling.
|
|
479
|
+
*
|
|
480
|
+
* @param subscriptionId - The subscription ID to unsubscribe.
|
|
481
|
+
*/
|
|
482
|
+
async unsubscribe(subscriptionId) {
|
|
483
|
+
const subscription = __classPrivateFieldGet(this, _RpcDataSource_activeSubscriptions, "f").get(subscriptionId);
|
|
484
|
+
if (subscription) {
|
|
485
|
+
// Stop balance polling
|
|
486
|
+
for (const token of subscription.balancePollingTokens) {
|
|
487
|
+
__classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").stopPollingByPollingToken(token);
|
|
488
|
+
}
|
|
489
|
+
// Stop detection polling
|
|
490
|
+
for (const token of subscription.detectionPollingTokens) {
|
|
491
|
+
__classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").stopPollingByPollingToken(token);
|
|
492
|
+
}
|
|
493
|
+
__classPrivateFieldGet(this, _RpcDataSource_activeSubscriptions, "f").delete(subscriptionId);
|
|
494
|
+
log('Unsubscribed and stopped polling', { subscriptionId });
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Destroy the data source and clean up resources.
|
|
499
|
+
*/
|
|
500
|
+
destroy() {
|
|
501
|
+
log('Destroying RpcDataSource');
|
|
502
|
+
// Stop all polling
|
|
503
|
+
__classPrivateFieldGet(this, _RpcDataSource_balanceFetcher, "f").stopAllPolling();
|
|
504
|
+
__classPrivateFieldGet(this, _RpcDataSource_tokenDetector, "f").stopAllPolling();
|
|
505
|
+
// Clear subscriptions
|
|
506
|
+
__classPrivateFieldGet(this, _RpcDataSource_activeSubscriptions, "f").clear();
|
|
507
|
+
// Clear caches
|
|
508
|
+
__classPrivateFieldGet(this, _RpcDataSource_providerCache, "f").clear();
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
exports.RpcDataSource = RpcDataSource;
|
|
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
|
|
567
|
+
for (const balance of result.balances) {
|
|
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,
|
|
574
|
+
};
|
|
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
|
|
578
|
+
const response = {
|
|
579
|
+
assetsBalance: {
|
|
580
|
+
[result.accountId]: newBalances,
|
|
581
|
+
},
|
|
582
|
+
assetsMetadata,
|
|
583
|
+
};
|
|
584
|
+
log('Balance update response', {
|
|
585
|
+
accountId: result.accountId,
|
|
586
|
+
newBalanceCount: Object.keys(newBalances).length,
|
|
587
|
+
});
|
|
588
|
+
this.messenger
|
|
589
|
+
.call('AssetsController:assetsUpdate', response, CONTROLLER_NAME)
|
|
590
|
+
.catch((error) => {
|
|
591
|
+
log('Failed to update assets', { error });
|
|
592
|
+
});
|
|
593
|
+
}, _RpcDataSource_handleDetectionUpdate = function _RpcDataSource_handleDetectionUpdate(result) {
|
|
594
|
+
log('Detected new tokens', {
|
|
595
|
+
count: result.detectedAssets.length,
|
|
596
|
+
});
|
|
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 = {};
|
|
615
|
+
if (result.detectedBalances.length > 0) {
|
|
616
|
+
for (const balance of result.detectedBalances) {
|
|
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,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
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
|
+
};
|
|
638
|
+
this.messenger
|
|
639
|
+
.call('AssetsController:assetsUpdate', response, CONTROLLER_NAME)
|
|
640
|
+
.catch((error) => {
|
|
641
|
+
log('Failed to update detected assets', { error });
|
|
642
|
+
});
|
|
643
|
+
}, _RpcDataSource_registerActionHandlers = function _RpcDataSource_registerActionHandlers() {
|
|
644
|
+
const getAssetsMiddlewareHandler = () => this.assetsMiddleware;
|
|
645
|
+
const getActiveChainsHandler = async () => this.getActiveChains();
|
|
646
|
+
const fetchHandler = async (request) => this.fetch(request);
|
|
647
|
+
const subscribeHandler = async (request) => this.subscribe(request);
|
|
648
|
+
const unsubscribeHandler = async (subscriptionId) => this.unsubscribe(subscriptionId);
|
|
649
|
+
this.messenger.registerActionHandler('RpcDataSource:getAssetsMiddleware', getAssetsMiddlewareHandler);
|
|
650
|
+
this.messenger.registerActionHandler('RpcDataSource:getActiveChains', getActiveChainsHandler);
|
|
651
|
+
this.messenger.registerActionHandler('RpcDataSource:fetch', fetchHandler);
|
|
652
|
+
this.messenger.registerActionHandler('RpcDataSource:subscribe', subscribeHandler);
|
|
653
|
+
this.messenger.registerActionHandler('RpcDataSource:unsubscribe', unsubscribeHandler);
|
|
654
|
+
}, _RpcDataSource_subscribeToNetworkController = function _RpcDataSource_subscribeToNetworkController() {
|
|
655
|
+
this.messenger.subscribe('NetworkController:stateChange', (networkState) => {
|
|
656
|
+
log('NetworkController state changed');
|
|
657
|
+
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_clearProviderCache).call(this);
|
|
658
|
+
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_updateFromNetworkState).call(this, networkState);
|
|
659
|
+
});
|
|
660
|
+
}, _RpcDataSource_initializeFromNetworkController = function _RpcDataSource_initializeFromNetworkController() {
|
|
661
|
+
log('Initializing from NetworkController');
|
|
662
|
+
try {
|
|
663
|
+
const networkState = this.messenger.call('NetworkController:getState');
|
|
664
|
+
__classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_updateFromNetworkState).call(this, networkState);
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
log('Failed to initialize from NetworkController', error);
|
|
668
|
+
}
|
|
669
|
+
}, _RpcDataSource_updateFromNetworkState = function _RpcDataSource_updateFromNetworkState(networkState) {
|
|
670
|
+
const { networkConfigurationsByChainId, networksMetadata } = networkState;
|
|
671
|
+
const chainStatuses = {};
|
|
672
|
+
const activeChains = [];
|
|
673
|
+
for (const [hexChainId, config] of Object.entries(networkConfigurationsByChainId)) {
|
|
674
|
+
const decimalChainId = parseInt(hexChainId, 16);
|
|
675
|
+
const caip2ChainId = `eip155:${decimalChainId}`;
|
|
676
|
+
const defaultRpcEndpoint = config.rpcEndpoints[config.defaultRpcEndpointIndex];
|
|
677
|
+
if (!defaultRpcEndpoint) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
const { networkClientId } = defaultRpcEndpoint;
|
|
681
|
+
const metadata = networksMetadata[networkClientId];
|
|
682
|
+
const status = metadata?.status ?? 'unknown';
|
|
683
|
+
chainStatuses[caip2ChainId] = {
|
|
684
|
+
chainId: caip2ChainId,
|
|
685
|
+
status,
|
|
686
|
+
name: config.name,
|
|
687
|
+
nativeCurrency: config.nativeCurrency,
|
|
688
|
+
networkClientId,
|
|
689
|
+
};
|
|
690
|
+
if (status === 'available' || status === 'unknown') {
|
|
691
|
+
activeChains.push(caip2ChainId);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
log('Network state updated', {
|
|
695
|
+
configuredChains: Object.keys(chainStatuses),
|
|
696
|
+
activeChains,
|
|
697
|
+
});
|
|
698
|
+
// Check if chains changed
|
|
699
|
+
const previousChains = new Set(__classPrivateFieldGet(this, _RpcDataSource_activeChains, "f"));
|
|
700
|
+
const hasChanges = previousChains.size !== activeChains.length ||
|
|
701
|
+
activeChains.some((chain) => !previousChains.has(chain));
|
|
702
|
+
// Update internal state
|
|
703
|
+
__classPrivateFieldSet(this, _RpcDataSource_chainStatuses, chainStatuses, "f");
|
|
704
|
+
__classPrivateFieldSet(this, _RpcDataSource_activeChains, activeChains, "f");
|
|
705
|
+
if (hasChanges) {
|
|
706
|
+
this.messenger.call('AssetsController:activeChainsUpdate', CONTROLLER_NAME, activeChains);
|
|
707
|
+
}
|
|
708
|
+
}, _RpcDataSource_getProvider = function _RpcDataSource_getProvider(chainId) {
|
|
709
|
+
const cached = __classPrivateFieldGet(this, _RpcDataSource_providerCache, "f").get(chainId);
|
|
710
|
+
if (cached) {
|
|
711
|
+
return cached;
|
|
712
|
+
}
|
|
713
|
+
const chainStatus = __classPrivateFieldGet(this, _RpcDataSource_chainStatuses, "f")[chainId];
|
|
714
|
+
if (!chainStatus) {
|
|
715
|
+
return undefined;
|
|
716
|
+
}
|
|
717
|
+
try {
|
|
718
|
+
const networkClient = this.messenger.call('NetworkController:getNetworkClientById', chainStatus.networkClientId);
|
|
719
|
+
const web3Provider = new providers_1.Web3Provider(networkClient.provider);
|
|
720
|
+
__classPrivateFieldGet(this, _RpcDataSource_providerCache, "f").set(chainId, web3Provider);
|
|
721
|
+
return web3Provider;
|
|
722
|
+
}
|
|
723
|
+
catch (error) {
|
|
724
|
+
log('Failed to get provider for chain', { chainId, error });
|
|
725
|
+
return undefined;
|
|
726
|
+
}
|
|
727
|
+
}, _RpcDataSource_getMulticallProvider = function _RpcDataSource_getMulticallProvider(hexChainId) {
|
|
728
|
+
const decimalChainId = parseInt(hexChainId, 16);
|
|
729
|
+
const caip2ChainId = `eip155:${decimalChainId}`;
|
|
730
|
+
const web3Provider = __classPrivateFieldGet(this, _RpcDataSource_instances, "m", _RpcDataSource_getProvider).call(this, caip2ChainId);
|
|
731
|
+
if (!web3Provider) {
|
|
732
|
+
throw new Error(`No provider available for chain ${hexChainId}`);
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
call: async (params) => {
|
|
736
|
+
return web3Provider.call({
|
|
737
|
+
to: params.to,
|
|
738
|
+
data: params.data,
|
|
739
|
+
});
|
|
740
|
+
},
|
|
741
|
+
getBalance: async (address) => {
|
|
742
|
+
const balance = await web3Provider.getBalance(address);
|
|
743
|
+
return balance;
|
|
744
|
+
},
|
|
745
|
+
};
|
|
746
|
+
}, _RpcDataSource_clearProviderCache = function _RpcDataSource_clearProviderCache() {
|
|
747
|
+
__classPrivateFieldGet(this, _RpcDataSource_providerCache, "f").clear();
|
|
748
|
+
}, _RpcDataSource_accountSupportsChain = function _RpcDataSource_accountSupportsChain(account, chainId) {
|
|
749
|
+
const scopes = account.scopes ?? [];
|
|
750
|
+
if (scopes.length === 0) {
|
|
751
|
+
return true;
|
|
752
|
+
}
|
|
753
|
+
const [chainNamespace, chainReference] = chainId.split(':');
|
|
754
|
+
for (const scope of scopes) {
|
|
755
|
+
const [scopeNamespace, scopeReference] = scope.split(':');
|
|
756
|
+
if (scopeNamespace !== chainNamespace) {
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
// Wildcard scope (e.g., eip155:0) matches all chains in the namespace
|
|
760
|
+
if (scopeReference === '0') {
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
// RpcDataSource only handles eip155 (EVM) chains
|
|
764
|
+
// Normalize hex chain references (e.g., 0x1 -> 1) for comparison
|
|
765
|
+
const normalizedScopeRef = scopeReference?.startsWith('0x')
|
|
766
|
+
? parseInt(scopeReference, 16).toString()
|
|
767
|
+
: scopeReference;
|
|
768
|
+
if (normalizedScopeRef === chainReference) {
|
|
769
|
+
return true;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return false;
|
|
773
|
+
}, _RpcDataSource_buildNativeAssetId = function _RpcDataSource_buildNativeAssetId(chainId) {
|
|
774
|
+
const { nativeAssetIdentifiers } = this.messenger.call('NetworkEnablementController:getState');
|
|
775
|
+
return (nativeAssetIdentifiers[chainId] ??
|
|
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
|
+
}
|
|
824
|
+
};
|
|
825
|
+
function createRpcDataSource(options) {
|
|
826
|
+
return new RpcDataSource(options);
|
|
827
|
+
}
|
|
828
|
+
exports.createRpcDataSource = createRpcDataSource;
|
|
829
|
+
//# sourceMappingURL=RpcDataSource.cjs.map
|