@defillama/sdk 5.0.14 → 5.0.16
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/build/abi/rpcCall.d.ts +1 -1
- package/build/abi/rpcCall.js +1 -1
- package/build/general.d.ts +2 -12
- package/build/general.js +5 -124
- package/build/generalUtil.d.ts +1 -1
- package/build/generalUtil.js +8 -1
- package/build/providers.json +1 -1
- package/build/types.d.ts +1 -1
- package/build/util/LlamaProvider.d.ts +34 -0
- package/build/util/LlamaProvider.js +274 -0
- package/build/util/env.js +13 -9
- package/build/util/updateProviderList.js +62 -15
- package/package.json +1 -1
package/build/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Chain } from "./general";
|
|
2
1
|
export type Address = string;
|
|
3
2
|
export type StringNumber = string;
|
|
4
3
|
export type Block = number | string;
|
|
@@ -20,6 +19,7 @@ export type CallOptions = {
|
|
|
20
19
|
skipCache?: boolean;
|
|
21
20
|
logArray?: LogArray;
|
|
22
21
|
};
|
|
22
|
+
export type Chain = string;
|
|
23
23
|
export type MulticallOptions = {
|
|
24
24
|
abi: string | any;
|
|
25
25
|
calls: CallsParams[] | (string | number)[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { AbstractProvider, AddressLike, Block, BlockTag, FallbackProvider, Filter, FilterByBlockHash, Log, TransactionRequest } from "ethers";
|
|
2
|
+
import { Chain } from "../types";
|
|
3
|
+
type ProviderWithURL = {
|
|
4
|
+
url: string;
|
|
5
|
+
provider: AbstractProvider;
|
|
6
|
+
};
|
|
7
|
+
export declare class LlamaProvider extends FallbackProvider {
|
|
8
|
+
isCustomLlamaProvider: boolean;
|
|
9
|
+
rpcs: ProviderWithURL[];
|
|
10
|
+
archivalRPCs: ProviderWithURL[];
|
|
11
|
+
_isReady: Promise<void>;
|
|
12
|
+
chainName: string;
|
|
13
|
+
chainId: number;
|
|
14
|
+
constructor({ providers, chainId, chainName, archivalRPCs, }: {
|
|
15
|
+
providers: ProviderWithURL[];
|
|
16
|
+
archivalRPCs: ProviderWithURL[];
|
|
17
|
+
chainId: number;
|
|
18
|
+
chainName: string;
|
|
19
|
+
}, fallbackConfig?: any);
|
|
20
|
+
getNetwork(): any;
|
|
21
|
+
_removeProvider(rpc: string): void;
|
|
22
|
+
_ready(): Promise<void>;
|
|
23
|
+
call(_tx: TransactionRequest): Promise<string>;
|
|
24
|
+
getBalance(address: AddressLike, blockTag?: BlockTag): Promise<bigint>;
|
|
25
|
+
getBlock(block: BlockTag, prefetchTxs?: boolean | undefined): Promise<Block | null>;
|
|
26
|
+
getLogs(_filter: Filter | FilterByBlockHash): Promise<Log[]>;
|
|
27
|
+
_performAction(method: string, params: any, attempts?: number): Promise<any>;
|
|
28
|
+
}
|
|
29
|
+
export declare const providers: {
|
|
30
|
+
[chain: string]: AbstractProvider;
|
|
31
|
+
};
|
|
32
|
+
export declare function setProvider(chain: Chain, provider: AbstractProvider): void;
|
|
33
|
+
export declare function getProvider(chain?: Chain, _getArchivalNode?: boolean): AbstractProvider;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getProvider = exports.setProvider = exports.providers = exports.LlamaProvider = void 0;
|
|
7
|
+
const ethers_1 = require("ethers");
|
|
8
|
+
const providers_json_1 = __importDefault(require("../providers.json"));
|
|
9
|
+
const env_1 = require("./env");
|
|
10
|
+
const debugLog_1 = require("./debugLog");
|
|
11
|
+
const axios_1 = __importDefault(require("axios"));
|
|
12
|
+
class LlamaProvider extends ethers_1.FallbackProvider {
|
|
13
|
+
constructor({ providers, chainId, chainName, archivalRPCs, }, fallbackConfig) {
|
|
14
|
+
const networkish = { name: chainName, chainId };
|
|
15
|
+
super(providers.map(i => i.provider), networkish, fallbackConfig);
|
|
16
|
+
this.isCustomLlamaProvider = true;
|
|
17
|
+
this.rpcs = providers;
|
|
18
|
+
this.archivalRPCs = archivalRPCs;
|
|
19
|
+
this.chainName = chainName;
|
|
20
|
+
this.chainId = chainId;
|
|
21
|
+
this._isReady = this._ready();
|
|
22
|
+
}
|
|
23
|
+
getNetwork() {
|
|
24
|
+
return { chainId: this.chainId, name: this.chainName };
|
|
25
|
+
}
|
|
26
|
+
_removeProvider(rpc) {
|
|
27
|
+
this.rpcs = this.rpcs.filter(i => i.url !== rpc);
|
|
28
|
+
this.archivalRPCs = this.archivalRPCs.filter(i => i.url !== rpc);
|
|
29
|
+
}
|
|
30
|
+
async _ready() {
|
|
31
|
+
const outOfSyncLimit = 1000;
|
|
32
|
+
const _this = this;
|
|
33
|
+
const currentBlocks = {};
|
|
34
|
+
await Promise.all(this.rpcs.map(checkRPCWorks));
|
|
35
|
+
if (this.archivalRPCs.length) {
|
|
36
|
+
await Promise.all(this.archivalRPCs.map(checkRPCWorks));
|
|
37
|
+
}
|
|
38
|
+
const highestBlock = Object.values(currentBlocks).reduce((highest, current) => Math.max(highest, current), 0);
|
|
39
|
+
Object.entries(currentBlocks).forEach(([url, block]) => {
|
|
40
|
+
if (highestBlock - block > outOfSyncLimit) {
|
|
41
|
+
(0, debugLog_1.debugLog)(`RPC ${url} is out of sync by ${highestBlock - block} blocks`);
|
|
42
|
+
_this.rpcs = _this.rpcs.filter(i => i.url !== url);
|
|
43
|
+
_this.archivalRPCs = _this.archivalRPCs.filter(i => i.url !== url);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
async function checkRPCWorks({ url, provider }) {
|
|
47
|
+
try {
|
|
48
|
+
const block = await httpRPC.getBlockNumber(url);
|
|
49
|
+
currentBlocks[url] = block;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
// debugLog(`${_this.chainName} skipping RPC ${url} is not working, error: ${(e as any).message}`)
|
|
53
|
+
_this._removeProvider(url);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async call(_tx) {
|
|
58
|
+
var _a;
|
|
59
|
+
return this._performAction('call', [{ to: _tx.to, data: _tx.data }, (_a = _tx.blockTag) !== null && _a !== void 0 ? _a : 'latest']);
|
|
60
|
+
}
|
|
61
|
+
async getBalance(address, blockTag = 'latest') {
|
|
62
|
+
return this._performAction('getBalance', [address, blockTag]);
|
|
63
|
+
}
|
|
64
|
+
async getBlock(block, prefetchTxs) {
|
|
65
|
+
return this._performAction('getBlock', [block, false]);
|
|
66
|
+
}
|
|
67
|
+
async getLogs(_filter) {
|
|
68
|
+
return this._performAction('getLogs', [_filter], 3);
|
|
69
|
+
}
|
|
70
|
+
async _performAction(method, params, attempts = 7) {
|
|
71
|
+
await this._isReady;
|
|
72
|
+
let runners = [...this.rpcs];
|
|
73
|
+
if (method === 'getLogs') {
|
|
74
|
+
runners = [...this.archivalRPCs];
|
|
75
|
+
this.rpcs.filter(i => !runners.map(i => i.url).includes(i.url)).forEach(i => runners.push(i)); // ensure that there are no duplicates
|
|
76
|
+
}
|
|
77
|
+
let primaryRunner = runners[0];
|
|
78
|
+
let errors = [];
|
|
79
|
+
runners = runners.slice(1).sort(() => Math.random() - 0.5); // randomize order of runners
|
|
80
|
+
const isArchivalRequest = ['call', 'getBalance'].includes(method) && params[1] !== 'latest';
|
|
81
|
+
let noPlayingAround = primaryRunner.url.includes('llama.fi') || method === 'getLogs' || isArchivalRequest;
|
|
82
|
+
if (noPlayingAround) {
|
|
83
|
+
// if primary runner is llama.fi or alchemy, then try it first
|
|
84
|
+
runners.unshift(primaryRunner);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// add it as second runner
|
|
88
|
+
runners.splice(1, 0, primaryRunner);
|
|
89
|
+
}
|
|
90
|
+
runners = runners.slice(0, attempts);
|
|
91
|
+
for (const runner of runners) {
|
|
92
|
+
try {
|
|
93
|
+
const result = await httpRPC[method](runner.url, params);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
// console.log('failed', runner.url, (e as any).message)
|
|
98
|
+
errors.push({ host: runner.url, error: e });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
throw { llamaRPCError: true, errors };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.LlamaProvider = LlamaProvider;
|
|
105
|
+
function createProvider(name, rpcString, chainId = 400069, archivalRPCList = []) {
|
|
106
|
+
chainId = (0, env_1.getChainId)(name, chainId);
|
|
107
|
+
const networkish = { name, chainId };
|
|
108
|
+
const rpcList = rpcString.split(',');
|
|
109
|
+
if ((0, env_1.getEnvValue)('HISTORICAL')) {
|
|
110
|
+
if (chainId === 1) {
|
|
111
|
+
(0, debugLog_1.debugLog)("RPC providers set to historical, only the first RPC provider will be used");
|
|
112
|
+
}
|
|
113
|
+
return getProviderObject(rpcList[0], name);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
try {
|
|
117
|
+
const fallbackConfig = { cacheTimeout: 5 * 1000, quorum: 1, eventQuorum: 1, };
|
|
118
|
+
const getProviderWithURL = (url) => ({ url, provider: getProviderObject(url, name) });
|
|
119
|
+
const providers = rpcList.map(getProviderWithURL);
|
|
120
|
+
const archivalRPCs = archivalRPCList.map(getProviderWithURL);
|
|
121
|
+
return new LlamaProvider({ providers, archivalRPCs, chainId, chainName: name, }, fallbackConfig);
|
|
122
|
+
// return new FallbackProvider(providers, networkish, fallbackConfig)
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
// debugLog(`Error creating provider for ${name} with RPCs: ${rpcList.join(', ')}`)
|
|
126
|
+
// we dont throw errors for chains not present in providers.json, these can be non-evm chains like solana
|
|
127
|
+
if (providers_json_1.default[name])
|
|
128
|
+
throw e;
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function getProviderObject(url, chain) {
|
|
133
|
+
/**
|
|
134
|
+
* Options for configuring a [[JsonRpcApiProvider]]. Much of this
|
|
135
|
+
* is targetted towards sub-classes, which often will not expose
|
|
136
|
+
* any of these options to their consumers.
|
|
137
|
+
*
|
|
138
|
+
* **``polling``** - use the polling strategy is used immediately
|
|
139
|
+
* for events; otherwise, attempt to use filters and fall back onto
|
|
140
|
+
* polling (default: ``false``)
|
|
141
|
+
*
|
|
142
|
+
* **``staticNetwork``** - do not request chain ID on requests to
|
|
143
|
+
* validate the underlying chain has not changed (default: ``null``)
|
|
144
|
+
*
|
|
145
|
+
* This should **ONLY** be used if it is **certain** that the network
|
|
146
|
+
* cannot change, such as when using INFURA (since the URL dictates the
|
|
147
|
+
* network). If the network is assumed static and it does change, this
|
|
148
|
+
* can have tragic consequences. For example, this **CANNOT** be used
|
|
149
|
+
* with MetaMask, since the used can select a new network from the
|
|
150
|
+
* drop-down at any time.
|
|
151
|
+
*
|
|
152
|
+
* **``batchStallTime``** - how long (ms) to aggregate requests into a
|
|
153
|
+
* single batch. ``0`` indicates batching will only encompass the current
|
|
154
|
+
* event loop. If ``batchMaxCount = 1``, this is ignored. (default: ``10``)
|
|
155
|
+
*
|
|
156
|
+
* **``batchMaxSize``** - target maximum size (bytes) to allow per batch
|
|
157
|
+
* request (default: 1Mb)
|
|
158
|
+
*
|
|
159
|
+
* **``batchMaxCount``** - maximum number of requests to allow in a batch.
|
|
160
|
+
* If ``batchMaxCount = 1``, then batching is disabled. (default: ``100``)
|
|
161
|
+
*
|
|
162
|
+
* **``cacheTimeout``** - passed as [[AbstractProviderOptions]].
|
|
163
|
+
* **``cacheTimeout``** - how long to cache a low-level ``_perform``
|
|
164
|
+
* for, based on input parameters. This reduces the number of calls
|
|
165
|
+
* to getChainId and getBlockNumber, but may break test chains which
|
|
166
|
+
* can perform operations (internally) synchronously. Use ``-1`` to
|
|
167
|
+
* disable, ``0`` will only buffer within the same event loop and
|
|
168
|
+
* any other value is in ms. (default: ``250``)
|
|
169
|
+
*/
|
|
170
|
+
// const batchMaxSize = 10 * (1024 * 1024) // 10Mb
|
|
171
|
+
// some rpcs throw error if batchMaxCount is set higher than 100
|
|
172
|
+
const batchMaxCount = (0, env_1.getBatchMaxCount)(chain);
|
|
173
|
+
const jsonRpcApiProviderOptions = { staticNetwork: true, batchMaxCount: 1, };
|
|
174
|
+
if (url.startsWith('wss://')) {
|
|
175
|
+
delete jsonRpcApiProviderOptions.batchMaxCount;
|
|
176
|
+
return new ethers_1.WebSocketProvider(url, networkish, jsonRpcApiProviderOptions);
|
|
177
|
+
}
|
|
178
|
+
return new ethers_1.JsonRpcProvider(url, networkish, jsonRpcApiProviderOptions);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.providers = {};
|
|
182
|
+
function setProvider(chain, provider) {
|
|
183
|
+
exports.providers[chain] = provider;
|
|
184
|
+
}
|
|
185
|
+
exports.setProvider = setProvider;
|
|
186
|
+
function getProvider(chain = "ethereum", _getArchivalNode = false) {
|
|
187
|
+
var _a, _b;
|
|
188
|
+
if (exports.providers[chain])
|
|
189
|
+
return exports.providers[chain];
|
|
190
|
+
// use RPC from env variable if set else use RPC from providers.json
|
|
191
|
+
let rpcList = (0, env_1.getChainRPCs)(chain, (_a = providers_json_1.default[chain]) === null || _a === void 0 ? void 0 : _a.rpc);
|
|
192
|
+
let archivalRPCList = (0, env_1.getArchivalRPCs)(chain);
|
|
193
|
+
if (!rpcList) {
|
|
194
|
+
// @ts-ignore (throwing error here would alter function behavior and have side effects)
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
if (!exports.providers[chain])
|
|
198
|
+
exports.providers[chain] = createProvider(chain, rpcList, (_b = providers_json_1.default[chain]) === null || _b === void 0 ? void 0 : _b.chainId, archivalRPCList);
|
|
199
|
+
return exports.providers[chain];
|
|
200
|
+
}
|
|
201
|
+
exports.getProvider = getProvider;
|
|
202
|
+
function toHex(n) {
|
|
203
|
+
if (typeof n === 'string')
|
|
204
|
+
return n;
|
|
205
|
+
return '0x' + n.toString(16);
|
|
206
|
+
}
|
|
207
|
+
const httpRPC = {
|
|
208
|
+
getBlockNumber: async (rpc) => {
|
|
209
|
+
const { data } = await axios_1.default.post(rpc, {
|
|
210
|
+
jsonrpc: '2.0', id: 1, params: [],
|
|
211
|
+
method: 'eth_blockNumber',
|
|
212
|
+
}, {
|
|
213
|
+
timeout: 3000
|
|
214
|
+
});
|
|
215
|
+
if (data.error)
|
|
216
|
+
throw data.error;
|
|
217
|
+
return parseInt(data.result);
|
|
218
|
+
},
|
|
219
|
+
getBlock: async (rpc, params) => {
|
|
220
|
+
params[0] = toHex(params[0]);
|
|
221
|
+
const { data: { result, error } } = await axios_1.default.post(rpc, {
|
|
222
|
+
jsonrpc: '2.0', id: 1, params,
|
|
223
|
+
method: 'eth_getBlockByNumber',
|
|
224
|
+
}, {
|
|
225
|
+
timeout: 3000
|
|
226
|
+
});
|
|
227
|
+
if (error)
|
|
228
|
+
throw error;
|
|
229
|
+
result.number = parseInt(result.number);
|
|
230
|
+
result.timestamp = parseInt(result.timestamp);
|
|
231
|
+
return result;
|
|
232
|
+
},
|
|
233
|
+
getBalance: async (rpc, params) => {
|
|
234
|
+
params[1] = toHex(params[1]);
|
|
235
|
+
const { data: { result, error } } = await axios_1.default.post(rpc, {
|
|
236
|
+
jsonrpc: '2.0', id: 1, params,
|
|
237
|
+
method: 'eth_getBalance',
|
|
238
|
+
}, {
|
|
239
|
+
timeout: 5000
|
|
240
|
+
});
|
|
241
|
+
if (error)
|
|
242
|
+
throw error;
|
|
243
|
+
return BigInt(result).toString();
|
|
244
|
+
},
|
|
245
|
+
call: async (rpc, params) => {
|
|
246
|
+
params[1] = toHex(params[1]);
|
|
247
|
+
const { data } = await axios_1.default.post(rpc, {
|
|
248
|
+
jsonrpc: '2.0', id: 1, params,
|
|
249
|
+
method: 'eth_call',
|
|
250
|
+
}, {
|
|
251
|
+
timeout: 5000
|
|
252
|
+
});
|
|
253
|
+
if (data.error)
|
|
254
|
+
throw data.error;
|
|
255
|
+
return data.result;
|
|
256
|
+
},
|
|
257
|
+
getLogs: async (rpc, params) => {
|
|
258
|
+
params[0].fromBlock = toHex(params[0].fromBlock);
|
|
259
|
+
params[0].toBlock = toHex(params[0].toBlock);
|
|
260
|
+
const { data: { result, error } } = await axios_1.default.post(rpc, {
|
|
261
|
+
jsonrpc: '2.0', id: 1, params,
|
|
262
|
+
method: 'eth_getLogs',
|
|
263
|
+
});
|
|
264
|
+
if (error)
|
|
265
|
+
throw error;
|
|
266
|
+
result.forEach((i) => {
|
|
267
|
+
i.blockNumber = parseInt(i.blockNumber);
|
|
268
|
+
i.transactionIndex = parseInt(i.transactionIndex);
|
|
269
|
+
i.logIndex = parseInt(i.logIndex);
|
|
270
|
+
i.index = i.logIndex;
|
|
271
|
+
});
|
|
272
|
+
return result;
|
|
273
|
+
},
|
|
274
|
+
};
|
package/build/util/env.js
CHANGED
|
@@ -32,8 +32,10 @@ function getMaxParallelRequests(chain) {
|
|
|
32
32
|
}
|
|
33
33
|
exports.getMaxParallelRequests = getMaxParallelRequests;
|
|
34
34
|
function getParallelGetLogsLimit(chain, providerUrl) {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
let defaultLimit = getEnvValue('GET_LOGS_CONCURRENCY_LIMIT', '25');
|
|
36
|
+
if (chain === 'fantom')
|
|
37
|
+
defaultLimit = '10';
|
|
38
|
+
const defaultAlchemyLimit = getEnvValue('ALCHEMY_GET_LOGS_CONCURRENCY_LIMIT', '25');
|
|
37
39
|
if (providerUrl && providerUrl.includes('alchemy.com'))
|
|
38
40
|
return +(defaultAlchemyLimit);
|
|
39
41
|
return +(getEnvValue(`${chain}_RPC_GET_LOGS_CONCURRENCY_LIMIT`, defaultLimit));
|
|
@@ -76,9 +78,8 @@ function getBatchMaxCount(chain) {
|
|
|
76
78
|
if (getEnvValue(key))
|
|
77
79
|
return +getEnvValue(key);
|
|
78
80
|
switch (chain) {
|
|
79
|
-
case 'cronos': return 5;
|
|
80
81
|
case 'zkfair': return 1;
|
|
81
|
-
default: return +getEnvValue('BATCH_MAX_COUNT', '
|
|
82
|
+
default: return +getEnvValue('BATCH_MAX_COUNT', '5');
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
exports.getBatchMaxCount = getBatchMaxCount;
|
|
@@ -91,10 +92,13 @@ function getArchivalRPCs(chain) {
|
|
|
91
92
|
exports.getArchivalRPCs = getArchivalRPCs;
|
|
92
93
|
function getChainRPCs(chain, defaultList = []) {
|
|
93
94
|
const key = chain + '_RPC';
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
const envValue = getEnvValue(key);
|
|
96
|
+
if (defaultList.length) {
|
|
97
|
+
const listString = defaultList.join(',');
|
|
98
|
+
if (envValue)
|
|
99
|
+
return envValue + ',' + listString;
|
|
100
|
+
return listString;
|
|
101
|
+
}
|
|
102
|
+
return envValue || undefined;
|
|
99
103
|
}
|
|
100
104
|
exports.getChainRPCs = getChainRPCs;
|
|
@@ -6,26 +6,73 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const providers_json_1 = __importDefault(require("../providers.json"));
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const providerList = providers_json_1.default;
|
|
9
10
|
async function main() {
|
|
10
|
-
let { data: chainData } = await (0, axios_1.default)('https://
|
|
11
|
-
const
|
|
12
|
-
|
|
11
|
+
let { data: chainData } = await (0, axios_1.default)('https://chainlist.org/rpcs.json');
|
|
12
|
+
const providerIDMap = {};
|
|
13
|
+
Object.values(providerList).forEach((i) => providerIDMap[i.chainId] = i.rpc);
|
|
13
14
|
chainData = chainData
|
|
14
15
|
.filter((i) => i.rpc.length)
|
|
15
16
|
.filter((i) => !i.status || i.status === 'active')
|
|
16
|
-
.filter((i) => i.shortName)
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
.filter((i) => i.shortName);
|
|
18
|
+
for (const i of chainData) {
|
|
19
|
+
i.rpc = await filterForWorkingRPCs(i.rpc.map((j) => j.url), i.name, i.chainId);
|
|
20
|
+
if (!i.rpc.length)
|
|
21
|
+
continue;
|
|
22
|
+
if (providerIDMap[i.chainId]) {
|
|
23
|
+
providerIDMap[i.chainId].push(...i.rpc);
|
|
24
|
+
}
|
|
25
|
+
else if (providerList[i.shortName]) {
|
|
26
|
+
providerList[i.shortName].rpc.push(...i.rpc);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
providerList[i.shortName.toLowerCase()] = {
|
|
30
|
+
rpc: i.rpc,
|
|
31
|
+
chainId: i.chainId
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
Object.values(providerList).forEach((i) => {
|
|
36
|
+
i.rpc = Array.from(new Set(filterRPCs(i.rpc)));
|
|
21
37
|
});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
fs_1.default.writeFileSync(__dirname + '/../providers.json', JSON.stringify(providerList));
|
|
39
|
+
}
|
|
40
|
+
function filterRPCs(rpc) {
|
|
41
|
+
return rpc.filter((i) => {
|
|
42
|
+
if (i.endsWith('/demo'))
|
|
43
|
+
return false; // remove demo rpc
|
|
44
|
+
if (i.includes('$'))
|
|
45
|
+
return false; // remove anything where api key is injected
|
|
46
|
+
if (i.startsWith('wss://') || i.startsWith('ws://'))
|
|
47
|
+
return false; // remove websocket rpcs
|
|
48
|
+
return true;
|
|
49
|
+
}).map((i) => {
|
|
50
|
+
if (i.endsWith('/'))
|
|
51
|
+
return i.slice(0, -1);
|
|
52
|
+
return i;
|
|
28
53
|
});
|
|
29
|
-
|
|
54
|
+
}
|
|
55
|
+
async function filterForWorkingRPCs(rpc, chain, chainId) {
|
|
56
|
+
if (rpc.length < 6)
|
|
57
|
+
return rpc;
|
|
58
|
+
rpc = filterRPCs(rpc);
|
|
59
|
+
const promises = await Promise.all(rpc.map(async (i) => {
|
|
60
|
+
try {
|
|
61
|
+
const { data } = await axios_1.default.post(i, {
|
|
62
|
+
jsonrpc: '2.0',
|
|
63
|
+
method: 'eth_blockNumber',
|
|
64
|
+
params: [],
|
|
65
|
+
id: 1
|
|
66
|
+
}, {
|
|
67
|
+
timeout: 3000
|
|
68
|
+
});
|
|
69
|
+
if (data.result)
|
|
70
|
+
return i;
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
// console.log((e as any).message, i, chain)
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
return rpc.filter((_i, index) => promises[index]);
|
|
30
77
|
}
|
|
31
78
|
main();
|