@steerprotocol/data-connector-loader 3.2.1 → 3.2.2
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/README.md +5 -14
- package/lib/bundle/bundleBase.js +27 -2
- package/lib/bundle/bundleDataConnector.d.ts +0 -6
- package/lib/bundle/bundleDataConnector.js +3 -41
- package/lib/esm/bundle/bundleBase.js +26 -1
- package/lib/esm/bundle/bundleDataConnector.d.ts +0 -6
- package/lib/esm/bundle/bundleDataConnector.js +4 -41
- package/lib/esm/execution/executionApp.js +5 -1
- package/lib/esm/types.d.ts +6 -6
- package/lib/execution/executionApp.js +5 -2
- package/lib/types.d.ts +6 -6
- package/package.json +2 -3
- package/lib/esm/utils/providerUtils.d.ts +0 -4
- package/lib/esm/utils/providerUtils.js +0 -37
- package/lib/utils/providerUtils.d.ts +0 -4
- package/lib/utils/providerUtils.js +0 -43
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Steer Protocol App Loader
|
|
2
2
|
|
|
3
3
|
## Public API
|
|
4
|
+
|
|
4
5
|
- `ExecutionAppConfig`: Configuration object for `ExecutionApp` (vault, chainId, subgraph URL, pool type flags, API keys, retries).
|
|
5
6
|
- `ExecutionApp`: High-level execution entrypoint for running bundles with a config-based constructor.
|
|
6
7
|
- `DataConnectorExecution`: Executes data connector bundles and handles request/response flow.
|
|
@@ -8,23 +9,13 @@
|
|
|
8
9
|
## Installation
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
|
-
npm install
|
|
12
|
+
npm install @steerprotocol/data-connector-loader
|
|
12
13
|
# or
|
|
13
|
-
yarn add
|
|
14
|
+
yarn add @steerprotocol/data-connector-loader
|
|
14
15
|
# or
|
|
15
|
-
pnpm add
|
|
16
|
+
pnpm add @steerprotocol/data-connector-loader
|
|
16
17
|
```
|
|
17
18
|
|
|
18
|
-
The package includes an automatic postinstall script that fixes ESM/CJS interoperability issues with dependencies. No additional configuration is needed.
|
|
19
|
-
|
|
20
19
|
## ESM Support
|
|
21
20
|
|
|
22
|
-
This package
|
|
23
|
-
|
|
24
|
-
If you encounter import errors after installation, you can manually run the fix script:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm run postinstall
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
For more details about the ESM fixes, see [docs/esm-fixes.md](docs/esm-fixes.md).
|
|
21
|
+
This package publishes both CommonJS and ESM entrypoints via `exports`.
|
package/lib/bundle/bundleBase.js
CHANGED
|
@@ -11,7 +11,32 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.BundleBase = void 0;
|
|
13
13
|
const app_loader_1 = require("@steerprotocol/app-loader");
|
|
14
|
-
const
|
|
14
|
+
const ethers_1 = require("ethers");
|
|
15
|
+
const UNSTABLE_RPC_PATTERNS = [/drpc\.org/i];
|
|
16
|
+
function createFallbackRpcProvider(urls) {
|
|
17
|
+
const seen = new Set();
|
|
18
|
+
const preferred = [];
|
|
19
|
+
const deprioritized = [];
|
|
20
|
+
for (const url of urls) {
|
|
21
|
+
const trimmed = url.trim();
|
|
22
|
+
if (trimmed.length === 0 || seen.has(trimmed)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
seen.add(trimmed);
|
|
26
|
+
if (UNSTABLE_RPC_PATTERNS.some((pattern) => pattern.test(trimmed))) {
|
|
27
|
+
deprioritized.push(trimmed);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
preferred.push(trimmed);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const prioritized = preferred.length > 0 ? [...preferred, ...deprioritized] : [...preferred, ...deprioritized];
|
|
34
|
+
if (prioritized.length === 0) {
|
|
35
|
+
throw new Error('No RPC URLs configured');
|
|
36
|
+
}
|
|
37
|
+
const providers = prioritized.map((url) => new ethers_1.ethers.JsonRpcProvider(url));
|
|
38
|
+
return providers.length === 1 ? providers[0] : new ethers_1.ethers.FallbackProvider(providers);
|
|
39
|
+
}
|
|
15
40
|
function bigIntReplacer(_key, value) {
|
|
16
41
|
return typeof value === 'bigint' ? value.toString() : value;
|
|
17
42
|
}
|
|
@@ -179,7 +204,7 @@ class BundleBase {
|
|
|
179
204
|
}
|
|
180
205
|
if (chainId && this.etherRpcConfig && this.etherRpcConfig[chainId]) {
|
|
181
206
|
const rpcConfig = this.etherRpcConfig[chainId];
|
|
182
|
-
return
|
|
207
|
+
return createFallbackRpcProvider((_a = rpcConfig.urls) !== null && _a !== void 0 ? _a : [rpcConfig.url]);
|
|
183
208
|
}
|
|
184
209
|
else {
|
|
185
210
|
return this.providerIdentity;
|
|
@@ -6,10 +6,4 @@ export declare class DataConnector extends BundleBase {
|
|
|
6
6
|
constructor(wasmFile: string | ArrayBuffer, _config: string, executionAppConfig: ExecutionAppConfig, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
|
|
7
7
|
getRpcUrl(config: any): string | undefined;
|
|
8
8
|
view(config: ViewConfig): Promise<string>;
|
|
9
|
-
/**
|
|
10
|
-
* Attempts to decode raw return data when the declared ABI doesn't match the actual
|
|
11
|
-
* contract output. Tries removing trailing outputs one-by-one until decoding succeeds.
|
|
12
|
-
* This handles pool variants that omit optional fields (e.g. feeProtocol in slot0).
|
|
13
|
-
*/
|
|
14
|
-
private decodeFallback;
|
|
15
9
|
}
|
|
@@ -48,22 +48,9 @@ class DataConnector extends bundleBase_js_1.BundleBase {
|
|
|
48
48
|
const paramsArray = config.arguments;
|
|
49
49
|
let result;
|
|
50
50
|
if (consts_js_1.CENTRALIZE_CONTRACT_INTERACTION_CHAINS.indexOf(this.configObj.chainId.toString()) === -1) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
// Some pool variants return fewer ABI outputs than the standard spec (e.g. Aerodrome/
|
|
58
|
-
// Velodrome slot0 has 6 fields instead of 7 — no feeProtocol). When ethers fails to
|
|
59
|
-
// decode the raw return data, fall back to decoding with progressively fewer outputs.
|
|
60
|
-
if ((err === null || err === void 0 ? void 0 : err.code) === 'BAD_DATA' && (err === null || err === void 0 ? void 0 : err.value)) {
|
|
61
|
-
result = this.decodeFallback(err.value, config);
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
throw err;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
51
|
+
result = yield contract[config.method](...paramsArray, {
|
|
52
|
+
blockTag: (_a = this.executionContext) === null || _a === void 0 ? void 0 : _a.blockNumber,
|
|
53
|
+
});
|
|
67
54
|
}
|
|
68
55
|
else {
|
|
69
56
|
const viewContractConfig = {
|
|
@@ -80,30 +67,5 @@ class DataConnector extends bundleBase_js_1.BundleBase {
|
|
|
80
67
|
return result;
|
|
81
68
|
});
|
|
82
69
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Attempts to decode raw return data when the declared ABI doesn't match the actual
|
|
85
|
-
* contract output. Tries removing trailing outputs one-by-one until decoding succeeds.
|
|
86
|
-
* This handles pool variants that omit optional fields (e.g. feeProtocol in slot0).
|
|
87
|
-
*/
|
|
88
|
-
decodeFallback(rawData, config) {
|
|
89
|
-
var _a;
|
|
90
|
-
const iface = new ethers_1.Interface(config.abi);
|
|
91
|
-
const fragment = iface.getFunction(config.method);
|
|
92
|
-
if (!((_a = fragment === null || fragment === void 0 ? void 0 : fragment.outputs) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
93
|
-
throw new Error(`Cannot find outputs for method "${config.method}" in ABI`);
|
|
94
|
-
}
|
|
95
|
-
const coder = ethers_1.AbiCoder.defaultAbiCoder();
|
|
96
|
-
for (let numOutputs = fragment.outputs.length - 1; numOutputs >= 1; numOutputs--) {
|
|
97
|
-
try {
|
|
98
|
-
const types = fragment.outputs.slice(0, numOutputs).map((o) => o.format());
|
|
99
|
-
const decoded = coder.decode(types, rawData);
|
|
100
|
-
return decoded;
|
|
101
|
-
}
|
|
102
|
-
catch (_b) {
|
|
103
|
-
// try with one fewer output
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
throw new Error(`Could not decode result data for method "${config.method}" — no matching ABI shape found`);
|
|
107
|
-
}
|
|
108
70
|
}
|
|
109
71
|
exports.DataConnector = DataConnector;
|
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import { loadWasm, loadWasmSync } from '@steerprotocol/app-loader';
|
|
2
|
-
import {
|
|
2
|
+
import { ethers } from 'ethers';
|
|
3
|
+
const UNSTABLE_RPC_PATTERNS = [/drpc\.org/i];
|
|
4
|
+
function createFallbackRpcProvider(urls) {
|
|
5
|
+
const seen = new Set();
|
|
6
|
+
const preferred = [];
|
|
7
|
+
const deprioritized = [];
|
|
8
|
+
for (const url of urls) {
|
|
9
|
+
const trimmed = url.trim();
|
|
10
|
+
if (trimmed.length === 0 || seen.has(trimmed)) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
seen.add(trimmed);
|
|
14
|
+
if (UNSTABLE_RPC_PATTERNS.some((pattern) => pattern.test(trimmed))) {
|
|
15
|
+
deprioritized.push(trimmed);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
preferred.push(trimmed);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const prioritized = preferred.length > 0 ? [...preferred, ...deprioritized] : [...preferred, ...deprioritized];
|
|
22
|
+
if (prioritized.length === 0) {
|
|
23
|
+
throw new Error('No RPC URLs configured');
|
|
24
|
+
}
|
|
25
|
+
const providers = prioritized.map((url) => new ethers.JsonRpcProvider(url));
|
|
26
|
+
return providers.length === 1 ? providers[0] : new ethers.FallbackProvider(providers);
|
|
27
|
+
}
|
|
3
28
|
function bigIntReplacer(_key, value) {
|
|
4
29
|
return typeof value === 'bigint' ? value.toString() : value;
|
|
5
30
|
}
|
|
@@ -6,10 +6,4 @@ export declare class DataConnector extends BundleBase {
|
|
|
6
6
|
constructor(wasmFile: string | ArrayBuffer, _config: string, executionAppConfig: ExecutionAppConfig, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
|
|
7
7
|
getRpcUrl(config: any): string | undefined;
|
|
8
8
|
view(config: ViewConfig): Promise<string>;
|
|
9
|
-
/**
|
|
10
|
-
* Attempts to decode raw return data when the declared ABI doesn't match the actual
|
|
11
|
-
* contract output. Tries removing trailing outputs one-by-one until decoding succeeds.
|
|
12
|
-
* This handles pool variants that omit optional fields (e.g. feeProtocol in slot0).
|
|
13
|
-
*/
|
|
14
|
-
private decodeFallback;
|
|
15
9
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Contract } from 'ethers';
|
|
2
2
|
import { CENTRALIZE_CONTRACT_INTERACTION_CHAINS } from '../utils/consts.js';
|
|
3
3
|
import { callWithRetry } from '../utils/utils.js';
|
|
4
4
|
import { BundleBase } from './bundleBase.js';
|
|
@@ -34,22 +34,9 @@ export class DataConnector extends BundleBase {
|
|
|
34
34
|
const paramsArray = config.arguments;
|
|
35
35
|
let result;
|
|
36
36
|
if (CENTRALIZE_CONTRACT_INTERACTION_CHAINS.indexOf(this.configObj.chainId.toString()) === -1) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
// Some pool variants return fewer ABI outputs than the standard spec (e.g. Aerodrome/
|
|
44
|
-
// Velodrome slot0 has 6 fields instead of 7 — no feeProtocol). When ethers fails to
|
|
45
|
-
// decode the raw return data, fall back to decoding with progressively fewer outputs.
|
|
46
|
-
if (err?.code === 'BAD_DATA' && err?.value) {
|
|
47
|
-
result = this.decodeFallback(err.value, config);
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
37
|
+
result = await contract[config.method](...paramsArray, {
|
|
38
|
+
blockTag: this.executionContext?.blockNumber,
|
|
39
|
+
});
|
|
53
40
|
}
|
|
54
41
|
else {
|
|
55
42
|
const viewContractConfig = {
|
|
@@ -65,28 +52,4 @@ export class DataConnector extends BundleBase {
|
|
|
65
52
|
// This gets stringified before calling main
|
|
66
53
|
return result;
|
|
67
54
|
}
|
|
68
|
-
/**
|
|
69
|
-
* Attempts to decode raw return data when the declared ABI doesn't match the actual
|
|
70
|
-
* contract output. Tries removing trailing outputs one-by-one until decoding succeeds.
|
|
71
|
-
* This handles pool variants that omit optional fields (e.g. feeProtocol in slot0).
|
|
72
|
-
*/
|
|
73
|
-
decodeFallback(rawData, config) {
|
|
74
|
-
const iface = new Interface(config.abi);
|
|
75
|
-
const fragment = iface.getFunction(config.method);
|
|
76
|
-
if (!fragment?.outputs?.length) {
|
|
77
|
-
throw new Error(`Cannot find outputs for method "${config.method}" in ABI`);
|
|
78
|
-
}
|
|
79
|
-
const coder = AbiCoder.defaultAbiCoder();
|
|
80
|
-
for (let numOutputs = fragment.outputs.length - 1; numOutputs >= 1; numOutputs--) {
|
|
81
|
-
try {
|
|
82
|
-
const types = fragment.outputs.slice(0, numOutputs).map((o) => o.format());
|
|
83
|
-
const decoded = coder.decode(types, rawData);
|
|
84
|
-
return decoded;
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
// try with one fewer output
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
throw new Error(`Could not decode result data for method "${config.method}" — no matching ABI shape found`);
|
|
91
|
-
}
|
|
92
55
|
}
|
|
@@ -501,8 +501,12 @@ export class ExecutionApp extends ExecutionBase {
|
|
|
501
501
|
const dataConnector = new DataConnector(_wasmFile, _vaultConfig, this.config, _identity, _etherRpcConfig);
|
|
502
502
|
await dataConnector.loadSync();
|
|
503
503
|
const executionContext = await this.getExecutionContext(dataConnector, JSON.parse(_vaultConfig));
|
|
504
|
+
const smartRewardsContractAddress = _job.targetAddresses[0];
|
|
505
|
+
if (!smartRewardsContractAddress) {
|
|
506
|
+
throw new Error('Dynamic job must include at least one target address');
|
|
507
|
+
}
|
|
504
508
|
const dynamicJobExecutionContext = {
|
|
505
|
-
smartRewardsContractAddress
|
|
509
|
+
smartRewardsContractAddress,
|
|
506
510
|
};
|
|
507
511
|
dataConnector.setExecutionContextStrategyExecution({
|
|
508
512
|
...executionContext,
|
package/lib/esm/types.d.ts
CHANGED
|
@@ -108,10 +108,10 @@ export type ViewContractConfig = {
|
|
|
108
108
|
};
|
|
109
109
|
export type JobDetails = {
|
|
110
110
|
id: string;
|
|
111
|
-
name
|
|
112
|
-
timestamp
|
|
113
|
-
jobInfo
|
|
114
|
-
targetAddresses
|
|
115
|
-
ipfsHash
|
|
116
|
-
status
|
|
111
|
+
name: string;
|
|
112
|
+
timestamp: string;
|
|
113
|
+
jobInfo: ReadonlyArray<unknown>;
|
|
114
|
+
targetAddresses: ReadonlyArray<string>;
|
|
115
|
+
ipfsHash: string;
|
|
116
|
+
status: string;
|
|
117
117
|
};
|
|
@@ -509,13 +509,16 @@ class ExecutionApp extends executionBase_js_1.ExecutionBase {
|
|
|
509
509
|
});
|
|
510
510
|
}
|
|
511
511
|
executeDynamicJobs(_wasmFile, _vaultConfig, _data, _job, _identity, _etherRpcConfig, forceDeposit) {
|
|
512
|
-
var _a;
|
|
513
512
|
return __awaiter(this, void 0, void 0, function* () {
|
|
514
513
|
const dataConnector = new bundleDataConnector_js_1.DataConnector(_wasmFile, _vaultConfig, this.config, _identity, _etherRpcConfig);
|
|
515
514
|
yield dataConnector.loadSync();
|
|
516
515
|
const executionContext = yield this.getExecutionContext(dataConnector, JSON.parse(_vaultConfig));
|
|
516
|
+
const smartRewardsContractAddress = _job.targetAddresses[0];
|
|
517
|
+
if (!smartRewardsContractAddress) {
|
|
518
|
+
throw new Error('Dynamic job must include at least one target address');
|
|
519
|
+
}
|
|
517
520
|
const dynamicJobExecutionContext = {
|
|
518
|
-
smartRewardsContractAddress
|
|
521
|
+
smartRewardsContractAddress,
|
|
519
522
|
};
|
|
520
523
|
dataConnector.setExecutionContextStrategyExecution(Object.assign(Object.assign({}, executionContext), dynamicJobExecutionContext), forceDeposit);
|
|
521
524
|
_data = _data.map((element) => JSON.stringify(element));
|
package/lib/types.d.ts
CHANGED
|
@@ -108,10 +108,10 @@ export type ViewContractConfig = {
|
|
|
108
108
|
};
|
|
109
109
|
export type JobDetails = {
|
|
110
110
|
id: string;
|
|
111
|
-
name
|
|
112
|
-
timestamp
|
|
113
|
-
jobInfo
|
|
114
|
-
targetAddresses
|
|
115
|
-
ipfsHash
|
|
116
|
-
status
|
|
111
|
+
name: string;
|
|
112
|
+
timestamp: string;
|
|
113
|
+
jobInfo: ReadonlyArray<unknown>;
|
|
114
|
+
targetAddresses: ReadonlyArray<string>;
|
|
115
|
+
ipfsHash: string;
|
|
116
|
+
status: string;
|
|
117
117
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steerprotocol/data-connector-loader",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.2",
|
|
4
4
|
"description": "App Loader for Steer Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"test": "jest --config jest.config.cjs",
|
|
25
25
|
"pack:local": "npm pack",
|
|
26
26
|
"publish:test": "node scripts/publish-test.cjs",
|
|
27
|
-
"postinstall": "node scripts/fix-node-modules.js",
|
|
28
27
|
"prepare": "npm run build",
|
|
29
28
|
"prepublishOnly": "npm test && npm run lint",
|
|
30
29
|
"preversion": "npm run lint",
|
|
@@ -84,8 +83,8 @@
|
|
|
84
83
|
"lib/**/*"
|
|
85
84
|
],
|
|
86
85
|
"dependencies": {
|
|
87
|
-
"@steerprotocol/sdk": "^1.28.0",
|
|
88
86
|
"@steerprotocol/app-loader": "^2.1.1",
|
|
87
|
+
"@steerprotocol/sdk": "^2.0.0",
|
|
89
88
|
"@steerprotocol/strategy-utils": "^3.1.2",
|
|
90
89
|
"axios": "^1.3.4",
|
|
91
90
|
"ethers": "^6.16.0",
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
export declare const prioritizeRpcUrls: (urls: ReadonlyArray<string>) => Array<string>;
|
|
3
|
-
export declare const getPrimaryRpcUrl: (urls: ReadonlyArray<string>) => string;
|
|
4
|
-
export declare const createFallbackRpcProvider: (urls: ReadonlyArray<string>) => ethers.Provider;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
const UNSTABLE_RPC_PATTERNS = [/drpc\.org/i];
|
|
3
|
-
const uniqueUrls = (urls) => {
|
|
4
|
-
const seen = new Set();
|
|
5
|
-
const normalized = [];
|
|
6
|
-
for (const url of urls) {
|
|
7
|
-
const trimmed = url.trim();
|
|
8
|
-
if (trimmed.length === 0 || seen.has(trimmed)) {
|
|
9
|
-
continue;
|
|
10
|
-
}
|
|
11
|
-
seen.add(trimmed);
|
|
12
|
-
normalized.push(trimmed);
|
|
13
|
-
}
|
|
14
|
-
return normalized;
|
|
15
|
-
};
|
|
16
|
-
const isDeprioritizedRpcUrl = (url) => UNSTABLE_RPC_PATTERNS.some((pattern) => pattern.test(url));
|
|
17
|
-
export const prioritizeRpcUrls = (urls) => {
|
|
18
|
-
const normalized = uniqueUrls(urls);
|
|
19
|
-
const preferred = normalized.filter((url) => !isDeprioritizedRpcUrl(url));
|
|
20
|
-
const deprioritized = normalized.filter((url) => isDeprioritizedRpcUrl(url));
|
|
21
|
-
return preferred.length > 0 ? [...preferred, ...deprioritized] : normalized;
|
|
22
|
-
};
|
|
23
|
-
export const getPrimaryRpcUrl = (urls) => {
|
|
24
|
-
const prioritized = prioritizeRpcUrls(urls);
|
|
25
|
-
if (prioritized.length === 0) {
|
|
26
|
-
throw new Error('No RPC URLs configured');
|
|
27
|
-
}
|
|
28
|
-
return prioritized[0];
|
|
29
|
-
};
|
|
30
|
-
export const createFallbackRpcProvider = (urls) => {
|
|
31
|
-
const prioritized = prioritizeRpcUrls(urls);
|
|
32
|
-
if (prioritized.length === 0) {
|
|
33
|
-
throw new Error('No RPC URLs configured');
|
|
34
|
-
}
|
|
35
|
-
const providers = prioritized.map((url) => new ethers.JsonRpcProvider(url));
|
|
36
|
-
return providers.length === 1 ? providers[0] : new ethers.FallbackProvider(providers);
|
|
37
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { ethers } from 'ethers';
|
|
2
|
-
export declare const prioritizeRpcUrls: (urls: ReadonlyArray<string>) => Array<string>;
|
|
3
|
-
export declare const getPrimaryRpcUrl: (urls: ReadonlyArray<string>) => string;
|
|
4
|
-
export declare const createFallbackRpcProvider: (urls: ReadonlyArray<string>) => ethers.Provider;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createFallbackRpcProvider = exports.getPrimaryRpcUrl = exports.prioritizeRpcUrls = void 0;
|
|
4
|
-
const ethers_1 = require("ethers");
|
|
5
|
-
const UNSTABLE_RPC_PATTERNS = [/drpc\.org/i];
|
|
6
|
-
const uniqueUrls = (urls) => {
|
|
7
|
-
const seen = new Set();
|
|
8
|
-
const normalized = [];
|
|
9
|
-
for (const url of urls) {
|
|
10
|
-
const trimmed = url.trim();
|
|
11
|
-
if (trimmed.length === 0 || seen.has(trimmed)) {
|
|
12
|
-
continue;
|
|
13
|
-
}
|
|
14
|
-
seen.add(trimmed);
|
|
15
|
-
normalized.push(trimmed);
|
|
16
|
-
}
|
|
17
|
-
return normalized;
|
|
18
|
-
};
|
|
19
|
-
const isDeprioritizedRpcUrl = (url) => UNSTABLE_RPC_PATTERNS.some((pattern) => pattern.test(url));
|
|
20
|
-
const prioritizeRpcUrls = (urls) => {
|
|
21
|
-
const normalized = uniqueUrls(urls);
|
|
22
|
-
const preferred = normalized.filter((url) => !isDeprioritizedRpcUrl(url));
|
|
23
|
-
const deprioritized = normalized.filter((url) => isDeprioritizedRpcUrl(url));
|
|
24
|
-
return preferred.length > 0 ? [...preferred, ...deprioritized] : normalized;
|
|
25
|
-
};
|
|
26
|
-
exports.prioritizeRpcUrls = prioritizeRpcUrls;
|
|
27
|
-
const getPrimaryRpcUrl = (urls) => {
|
|
28
|
-
const prioritized = (0, exports.prioritizeRpcUrls)(urls);
|
|
29
|
-
if (prioritized.length === 0) {
|
|
30
|
-
throw new Error('No RPC URLs configured');
|
|
31
|
-
}
|
|
32
|
-
return prioritized[0];
|
|
33
|
-
};
|
|
34
|
-
exports.getPrimaryRpcUrl = getPrimaryRpcUrl;
|
|
35
|
-
const createFallbackRpcProvider = (urls) => {
|
|
36
|
-
const prioritized = (0, exports.prioritizeRpcUrls)(urls);
|
|
37
|
-
if (prioritized.length === 0) {
|
|
38
|
-
throw new Error('No RPC URLs configured');
|
|
39
|
-
}
|
|
40
|
-
const providers = prioritized.map((url) => new ethers_1.ethers.JsonRpcProvider(url));
|
|
41
|
-
return providers.length === 1 ? providers[0] : new ethers_1.ethers.FallbackProvider(providers);
|
|
42
|
-
};
|
|
43
|
-
exports.createFallbackRpcProvider = createFallbackRpcProvider;
|