@steerprotocol/data-connector-loader 3.1.1 → 3.2.1

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.
Files changed (46) hide show
  1. package/README.md +30 -1
  2. package/lib/bundle/bundleBase.d.ts +10 -5
  3. package/lib/bundle/bundleBase.js +65 -11
  4. package/lib/bundle/bundleDataConnector.d.ts +11 -4
  5. package/lib/bundle/bundleDataConnector.js +49 -13
  6. package/lib/esm/bundle/bundleBase.d.ts +10 -5
  7. package/lib/esm/bundle/bundleBase.js +60 -11
  8. package/lib/esm/bundle/bundleDataConnector.d.ts +11 -4
  9. package/lib/esm/bundle/bundleDataConnector.js +46 -11
  10. package/lib/esm/execution/executionApp.d.ts +52 -7
  11. package/lib/esm/execution/executionApp.js +557 -113
  12. package/lib/esm/execution/executionBase.d.ts +4 -4
  13. package/lib/esm/execution/executionBase.js +11 -12
  14. package/lib/esm/execution/executionDataConnector.d.ts +4 -2
  15. package/lib/esm/execution/executionDataConnector.js +56 -25
  16. package/lib/esm/index.d.ts +6 -4
  17. package/lib/esm/index.js +3 -4
  18. package/lib/esm/types.d.ts +17 -4
  19. package/lib/esm/utils/blockFinder.d.ts +1 -1
  20. package/lib/esm/utils/consts.js +43 -1
  21. package/lib/esm/utils/pluginManager.d.ts +1 -1
  22. package/lib/esm/utils/providerUtils.d.ts +4 -0
  23. package/lib/esm/utils/providerUtils.js +37 -0
  24. package/lib/esm/utils/replace-old-subgraphs.d.ts +23 -0
  25. package/lib/esm/utils/replace-old-subgraphs.js +123 -0
  26. package/lib/esm/utils/utils.d.ts +7 -6
  27. package/lib/esm/utils/utils.js +8 -9
  28. package/lib/execution/executionApp.d.ts +52 -7
  29. package/lib/execution/executionApp.js +556 -117
  30. package/lib/execution/executionBase.d.ts +4 -4
  31. package/lib/execution/executionBase.js +11 -12
  32. package/lib/execution/executionDataConnector.d.ts +4 -2
  33. package/lib/execution/executionDataConnector.js +61 -29
  34. package/lib/index.d.ts +6 -4
  35. package/lib/index.js +6 -21
  36. package/lib/types.d.ts +17 -4
  37. package/lib/utils/blockFinder.d.ts +1 -1
  38. package/lib/utils/consts.js +43 -1
  39. package/lib/utils/pluginManager.d.ts +1 -1
  40. package/lib/utils/providerUtils.d.ts +4 -0
  41. package/lib/utils/providerUtils.js +43 -0
  42. package/lib/utils/replace-old-subgraphs.d.ts +23 -0
  43. package/lib/utils/replace-old-subgraphs.js +129 -0
  44. package/lib/utils/utils.d.ts +7 -6
  45. package/lib/utils/utils.js +15 -16
  46. package/package.json +12 -3
package/README.md CHANGED
@@ -1 +1,30 @@
1
- # Steer Protocol App Loader
1
+ # Steer Protocol App Loader
2
+
3
+ ## Public API
4
+ - `ExecutionAppConfig`: Configuration object for `ExecutionApp` (vault, chainId, subgraph URL, pool type flags, API keys, retries).
5
+ - `ExecutionApp`: High-level execution entrypoint for running bundles with a config-based constructor.
6
+ - `DataConnectorExecution`: Executes data connector bundles and handles request/response flow.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install test-data-connector-loader
12
+ # or
13
+ yarn add test-data-connector-loader
14
+ # or
15
+ pnpm add test-data-connector-loader
16
+ ```
17
+
18
+ The package includes an automatic postinstall script that fixes ESM/CJS interoperability issues with dependencies. No additional configuration is needed.
19
+
20
+ ## ESM Support
21
+
22
+ This package is an ESM module (`"type": "module"`). It automatically fixes ESM compatibility issues in its dependencies during installation.
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).
@@ -1,6 +1,7 @@
1
- import { WasmModule } from '@steerprotocol/app-loader';
1
+ import type { WasmModule } from '@steerprotocol/app-loader';
2
2
  import { ethers } from 'ethers';
3
- import { EtherRpcConfig, ExecutionContext } from '../types';
3
+ import type { ExecutionAppConfig } from '../execution/executionApp.js';
4
+ import type { EtherRpcConfig, ExecutionContext } from '../types.js';
4
5
  export declare class BundleBase {
5
6
  module?: WasmModule;
6
7
  protected wasmFile: ArrayBuffer | string;
@@ -13,13 +14,17 @@ export declare class BundleBase {
13
14
  executionContext?: ExecutionContext & {
14
15
  epochTimestamp: number;
15
16
  };
16
- protected scheduleEpochTimestamp: number | undefined;
17
- constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
17
+ protected scheduleEpochTimestamp?: number;
18
+ executionAppConfig: ExecutionAppConfig;
19
+ constructor(wasmFile: string | ArrayBuffer, _config: string, executionAppConfig: ExecutionAppConfig, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
18
20
  load(): Promise<WasmModule>;
19
21
  loadSync(): WasmModule;
20
22
  execute(response: string): Promise<string>;
23
+ transform(): Promise<string>;
21
24
  executeBundle(data: Array<any>): Promise<string>;
22
- setExecutionContextStrategyExecution(executionContext: ExecutionContext): void;
25
+ executeDynamicJobBundle(data: Array<any>): Promise<string>;
26
+ reset(): void;
27
+ setExecutionContextStrategyExecution(executionContext: ExecutionContext, forceDeposit?: boolean): void;
23
28
  setExecutionContextDataConnector(executionContext: ExecutionContext): void;
24
29
  protected executeModule(response: string): Promise<string>;
25
30
  getProvider(config: any): ethers.Provider | undefined;
@@ -11,14 +11,18 @@ 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 ethers_1 = require("ethers");
14
+ const providerUtils_js_1 = require("../utils/providerUtils.js");
15
+ function bigIntReplacer(_key, value) {
16
+ return typeof value === 'bigint' ? value.toString() : value;
17
+ }
15
18
  class BundleBase {
16
- constructor(wasmFile, _config, identity, etherRpcConfig) {
19
+ constructor(wasmFile, _config, executionAppConfig, identity, etherRpcConfig) {
17
20
  this.wasmFile = wasmFile;
18
21
  this.config = _config;
19
22
  this.configObj = JSON.parse(_config);
20
23
  this.providerIdentity = identity;
21
24
  this.etherRpcConfig = etherRpcConfig;
25
+ this.executionAppConfig = executionAppConfig;
22
26
  }
23
27
  load() {
24
28
  return __awaiter(this, void 0, void 0, function* () {
@@ -29,8 +33,9 @@ class BundleBase {
29
33
  });
30
34
  }
31
35
  loadSync() {
32
- if (typeof this.wasmFile === 'string')
36
+ if (typeof this.wasmFile === 'string') {
33
37
  throw new Error('Cannot load module synchronously unless wasmFile is of type ArrayBuffer');
38
+ }
34
39
  this.module = (0, app_loader_1.loadWasmSync)(this.wasmFile, {});
35
40
  return this.module;
36
41
  }
@@ -55,6 +60,28 @@ class BundleBase {
55
60
  return yield this.module.execute(response);
56
61
  });
57
62
  }
63
+ // For dynamic job data connector
64
+ transform() {
65
+ return __awaiter(this, void 0, void 0, function* () {
66
+ if (!this.executionContext) {
67
+ throw new Error('Execution context missing');
68
+ }
69
+ // If the module is not initialized, try to load it
70
+ if (!this.module) {
71
+ try {
72
+ yield this.load();
73
+ }
74
+ catch (_a) {
75
+ throw new Error('Module not initialized');
76
+ }
77
+ }
78
+ // If the module is still not initialized, throw an error
79
+ if (!this.module)
80
+ throw new Error('Module not initialized');
81
+ // Call the main function with the response
82
+ return yield this.module.transform();
83
+ });
84
+ }
58
85
  executeBundle(data) {
59
86
  return __awaiter(this, void 0, void 0, function* () {
60
87
  if (!this.executionContext) {
@@ -76,7 +103,33 @@ class BundleBase {
76
103
  return this.module.execute(...data);
77
104
  });
78
105
  }
79
- setExecutionContextStrategyExecution(executionContext) {
106
+ executeDynamicJobBundle(data) {
107
+ return __awaiter(this, void 0, void 0, function* () {
108
+ if (!this.executionContext) {
109
+ throw new Error('Execution context missing');
110
+ }
111
+ // If the module is not initialized, try to load it
112
+ if (!this.module) {
113
+ try {
114
+ yield this.load();
115
+ }
116
+ catch (_a) {
117
+ throw new Error('Module not initialized');
118
+ }
119
+ }
120
+ // If the module is still not initialized, throw an error
121
+ if (!this.module)
122
+ throw new Error('Module not initialized');
123
+ // Call the main function with the response
124
+ return this.module.execute(...data);
125
+ });
126
+ }
127
+ reset() {
128
+ if (this.module && this.module['reset']) {
129
+ this.module.reset();
130
+ }
131
+ }
132
+ setExecutionContextStrategyExecution(executionContext, forceDeposit) {
80
133
  var _a;
81
134
  // Determine the timestamp for epoch
82
135
  const timestamp = this.subtractDate(executionContext.executionTimestamp, Number(executionContext.epochLength)).getTime();
@@ -85,8 +138,10 @@ class BundleBase {
85
138
  this.executionContext = Object.assign(Object.assign({}, executionContext), { epochTimestamp: timestampInSecs });
86
139
  const completeConfig = Object.assign(Object.assign({}, JSON.parse(this.config)), this.executionContext);
87
140
  this.scheduleEpochTimestamp = executionContext.epochTimestamp;
88
- console.log('Complete execution config : ', completeConfig);
89
- (_a = this.module) === null || _a === void 0 ? void 0 : _a.initialize(JSON.stringify(completeConfig));
141
+ if (completeConfig.triggerStyle && forceDeposit === true) {
142
+ completeConfig.triggerStyle = 'None';
143
+ }
144
+ (_a = this.module) === null || _a === void 0 ? void 0 : _a.initialize(JSON.stringify(completeConfig, bigIntReplacer));
90
145
  }
91
146
  setExecutionContextDataConnector(executionContext) {
92
147
  var _a;
@@ -97,8 +152,7 @@ class BundleBase {
97
152
  this.executionContext = Object.assign(Object.assign({}, executionContext), { epochTimestamp: timestampInSecs });
98
153
  const completeConfig = Object.assign(Object.assign({}, JSON.parse(this.config)), { executionContext: this.executionContext });
99
154
  this.scheduleEpochTimestamp = executionContext.epochTimestamp;
100
- console.log('Complete execution config : ', completeConfig);
101
- (_a = this.module) === null || _a === void 0 ? void 0 : _a.initialize(JSON.stringify(completeConfig));
155
+ (_a = this.module) === null || _a === void 0 ? void 0 : _a.initialize(JSON.stringify(completeConfig, bigIntReplacer));
102
156
  }
103
157
  executeModule(response) {
104
158
  return __awaiter(this, void 0, void 0, function* () {
@@ -112,8 +166,8 @@ class BundleBase {
112
166
  // The chainId is first checked in the data connector config, and if not found
113
167
  // it is checked in the request config. If the chainId is found in either of
114
168
  // these places, the provider is returned from the etherRpcConfig object
115
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
116
169
  getProvider(config) {
170
+ var _a;
117
171
  let chainId;
118
172
  // check if chainId is configured in data connector config
119
173
  if (this.configObj.chainId) {
@@ -124,8 +178,8 @@ class BundleBase {
124
178
  chainId = config.chainId;
125
179
  }
126
180
  if (chainId && this.etherRpcConfig && this.etherRpcConfig[chainId]) {
127
- const provider = new ethers_1.ethers.JsonRpcProvider(this.etherRpcConfig[chainId].url);
128
- return provider;
181
+ const rpcConfig = this.etherRpcConfig[chainId];
182
+ return (0, providerUtils_js_1.createFallbackRpcProvider)((_a = rpcConfig.urls) !== null && _a !== void 0 ? _a : [rpcConfig.url]);
129
183
  }
130
184
  else {
131
185
  return this.providerIdentity;
@@ -1,8 +1,15 @@
1
- import { ethers } from 'ethers';
2
- import { EtherRpcConfig, ViewConfig } from '../types';
3
- import { BundleBase } from './bundleBase';
1
+ import type { ethers } from 'ethers';
2
+ import type { ExecutionAppConfig } from '../execution/executionApp.js';
3
+ import type { EtherRpcConfig, ViewConfig } from '../types.js';
4
+ import { BundleBase } from './bundleBase.js';
4
5
  export declare class DataConnector extends BundleBase {
5
- constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
6
+ constructor(wasmFile: string | ArrayBuffer, _config: string, executionAppConfig: ExecutionAppConfig, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
6
7
  getRpcUrl(config: any): string | undefined;
7
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;
8
15
  }
@@ -11,13 +11,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.DataConnector = void 0;
13
13
  const ethers_1 = require("ethers");
14
- const consts_1 = require("../utils/consts");
15
- const utils_1 = require("../utils/utils");
16
- const bundleBase_1 = require("./bundleBase");
17
- class DataConnector extends bundleBase_1.BundleBase {
14
+ const consts_js_1 = require("../utils/consts.js");
15
+ const utils_js_1 = require("../utils/utils.js");
16
+ const bundleBase_js_1 = require("./bundleBase.js");
17
+ class DataConnector extends bundleBase_js_1.BundleBase {
18
18
  // Identity should come from the node's IdentityManager.wallet
19
- constructor(wasmFile, _config, identity, etherRpcConfig) {
20
- super(wasmFile, _config, identity, etherRpcConfig);
19
+ constructor(wasmFile, _config, executionAppConfig, identity, etherRpcConfig) {
20
+ super(wasmFile, _config, executionAppConfig, identity, etherRpcConfig);
21
21
  }
22
22
  // get rpc url from configuration
23
23
  getRpcUrl(config) {
@@ -38,7 +38,6 @@ class DataConnector extends bundleBase_1.BundleBase {
38
38
  }
39
39
  }
40
40
  // Makes contract instance and calls, returns stringified result
41
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
41
  view(config) {
43
42
  var _a;
44
43
  return __awaiter(this, void 0, void 0, function* () {
@@ -46,13 +45,25 @@ class DataConnector extends bundleBase_1.BundleBase {
46
45
  if (!provider)
47
46
  throw new Error('Provider not initialized');
48
47
  const contract = new ethers_1.Contract(config.address, config.abi, provider);
49
- // For formatting the parameters if needed
50
48
  const paramsArray = config.arguments;
51
49
  let result;
52
- if (consts_1.CENTRALIZE_CONTRACT_INTERACTION_CHAINS.indexOf(this.configObj.chainId.toString()) === -1) {
53
- result = yield contract[config.method](...paramsArray, {
54
- blockTag: (_a = this.executionContext) === null || _a === void 0 ? void 0 : _a.blockNumber,
55
- }); //@note uncomment for deterministic blocks
50
+ if (consts_js_1.CENTRALIZE_CONTRACT_INTERACTION_CHAINS.indexOf(this.configObj.chainId.toString()) === -1) {
51
+ try {
52
+ result = yield contract[config.method](...paramsArray, {
53
+ blockTag: (_a = this.executionContext) === null || _a === void 0 ? void 0 : _a.blockNumber,
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
+ }
56
67
  }
57
68
  else {
58
69
  const viewContractConfig = {
@@ -63,11 +74,36 @@ class DataConnector extends bundleBase_1.BundleBase {
63
74
  method: config.method,
64
75
  rpcUrl: this.getRpcUrl(config),
65
76
  };
66
- result = yield (0, utils_1.callWithRetry)(viewContractConfig);
77
+ result = yield (0, utils_js_1.callWithRetry)(viewContractConfig);
67
78
  }
68
79
  // This gets stringified before calling main
69
80
  return result;
70
81
  });
71
82
  }
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
+ }
72
108
  }
73
109
  exports.DataConnector = DataConnector;
@@ -1,6 +1,7 @@
1
- import { WasmModule } from '@steerprotocol/app-loader';
1
+ import type { WasmModule } from '@steerprotocol/app-loader';
2
2
  import { ethers } from 'ethers';
3
- import { EtherRpcConfig, ExecutionContext } from '../types';
3
+ import type { ExecutionAppConfig } from '../execution/executionApp.js';
4
+ import type { EtherRpcConfig, ExecutionContext } from '../types.js';
4
5
  export declare class BundleBase {
5
6
  module?: WasmModule;
6
7
  protected wasmFile: ArrayBuffer | string;
@@ -13,13 +14,17 @@ export declare class BundleBase {
13
14
  executionContext?: ExecutionContext & {
14
15
  epochTimestamp: number;
15
16
  };
16
- protected scheduleEpochTimestamp: number | undefined;
17
- constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
17
+ protected scheduleEpochTimestamp?: number;
18
+ executionAppConfig: ExecutionAppConfig;
19
+ constructor(wasmFile: string | ArrayBuffer, _config: string, executionAppConfig: ExecutionAppConfig, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
18
20
  load(): Promise<WasmModule>;
19
21
  loadSync(): WasmModule;
20
22
  execute(response: string): Promise<string>;
23
+ transform(): Promise<string>;
21
24
  executeBundle(data: Array<any>): Promise<string>;
22
- setExecutionContextStrategyExecution(executionContext: ExecutionContext): void;
25
+ executeDynamicJobBundle(data: Array<any>): Promise<string>;
26
+ reset(): void;
27
+ setExecutionContextStrategyExecution(executionContext: ExecutionContext, forceDeposit?: boolean): void;
23
28
  setExecutionContextDataConnector(executionContext: ExecutionContext): void;
24
29
  protected executeModule(response: string): Promise<string>;
25
30
  getProvider(config: any): ethers.Provider | undefined;
@@ -1,12 +1,16 @@
1
1
  import { loadWasm, loadWasmSync } from '@steerprotocol/app-loader';
2
- import { ethers } from 'ethers';
2
+ import { createFallbackRpcProvider } from '../utils/providerUtils.js';
3
+ function bigIntReplacer(_key, value) {
4
+ return typeof value === 'bigint' ? value.toString() : value;
5
+ }
3
6
  export class BundleBase {
4
- constructor(wasmFile, _config, identity, etherRpcConfig) {
7
+ constructor(wasmFile, _config, executionAppConfig, identity, etherRpcConfig) {
5
8
  this.wasmFile = wasmFile;
6
9
  this.config = _config;
7
10
  this.configObj = JSON.parse(_config);
8
11
  this.providerIdentity = identity;
9
12
  this.etherRpcConfig = etherRpcConfig;
13
+ this.executionAppConfig = executionAppConfig;
10
14
  }
11
15
  async load() {
12
16
  const instance = await loadWasm(this.wasmFile, {});
@@ -15,8 +19,9 @@ export class BundleBase {
15
19
  return this.module;
16
20
  }
17
21
  loadSync() {
18
- if (typeof this.wasmFile === 'string')
22
+ if (typeof this.wasmFile === 'string') {
19
23
  throw new Error('Cannot load module synchronously unless wasmFile is of type ArrayBuffer');
24
+ }
20
25
  this.module = loadWasmSync(this.wasmFile, {});
21
26
  return this.module;
22
27
  }
@@ -39,6 +44,26 @@ export class BundleBase {
39
44
  // Call the main function with the response
40
45
  return await this.module.execute(response);
41
46
  }
47
+ // For dynamic job data connector
48
+ async transform() {
49
+ if (!this.executionContext) {
50
+ throw new Error('Execution context missing');
51
+ }
52
+ // If the module is not initialized, try to load it
53
+ if (!this.module) {
54
+ try {
55
+ await this.load();
56
+ }
57
+ catch {
58
+ throw new Error('Module not initialized');
59
+ }
60
+ }
61
+ // If the module is still not initialized, throw an error
62
+ if (!this.module)
63
+ throw new Error('Module not initialized');
64
+ // Call the main function with the response
65
+ return await this.module.transform();
66
+ }
42
67
  async executeBundle(data) {
43
68
  if (!this.executionContext) {
44
69
  throw new Error('Execution context missing');
@@ -58,7 +83,31 @@ export class BundleBase {
58
83
  // Call the main function with the response
59
84
  return this.module.execute(...data);
60
85
  }
61
- setExecutionContextStrategyExecution(executionContext) {
86
+ async executeDynamicJobBundle(data) {
87
+ if (!this.executionContext) {
88
+ throw new Error('Execution context missing');
89
+ }
90
+ // If the module is not initialized, try to load it
91
+ if (!this.module) {
92
+ try {
93
+ await this.load();
94
+ }
95
+ catch {
96
+ throw new Error('Module not initialized');
97
+ }
98
+ }
99
+ // If the module is still not initialized, throw an error
100
+ if (!this.module)
101
+ throw new Error('Module not initialized');
102
+ // Call the main function with the response
103
+ return this.module.execute(...data);
104
+ }
105
+ reset() {
106
+ if (this.module && this.module['reset']) {
107
+ this.module.reset();
108
+ }
109
+ }
110
+ setExecutionContextStrategyExecution(executionContext, forceDeposit) {
62
111
  // Determine the timestamp for epoch
63
112
  const timestamp = this.subtractDate(executionContext.executionTimestamp, Number(executionContext.epochLength)).getTime();
64
113
  // Divide milliseconds data to seconds for transformation bundle
@@ -66,8 +115,10 @@ export class BundleBase {
66
115
  this.executionContext = { ...executionContext, epochTimestamp: timestampInSecs };
67
116
  const completeConfig = { ...JSON.parse(this.config), ...this.executionContext };
68
117
  this.scheduleEpochTimestamp = executionContext.epochTimestamp;
69
- console.log('Complete execution config : ', completeConfig);
70
- this.module?.initialize(JSON.stringify(completeConfig));
118
+ if (completeConfig.triggerStyle && forceDeposit === true) {
119
+ completeConfig.triggerStyle = 'None';
120
+ }
121
+ this.module?.initialize(JSON.stringify(completeConfig, bigIntReplacer));
71
122
  }
72
123
  setExecutionContextDataConnector(executionContext) {
73
124
  // Determine the timestamp for epoch
@@ -77,8 +128,7 @@ export class BundleBase {
77
128
  this.executionContext = { ...executionContext, epochTimestamp: timestampInSecs };
78
129
  const completeConfig = { ...JSON.parse(this.config), executionContext: this.executionContext };
79
130
  this.scheduleEpochTimestamp = executionContext.epochTimestamp;
80
- console.log('Complete execution config : ', completeConfig);
81
- this.module?.initialize(JSON.stringify(completeConfig));
131
+ this.module?.initialize(JSON.stringify(completeConfig, bigIntReplacer));
82
132
  }
83
133
  async executeModule(response) {
84
134
  if (!this.module) {
@@ -90,7 +140,6 @@ export class BundleBase {
90
140
  // The chainId is first checked in the data connector config, and if not found
91
141
  // it is checked in the request config. If the chainId is found in either of
92
142
  // these places, the provider is returned from the etherRpcConfig object
93
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
143
  getProvider(config) {
95
144
  let chainId;
96
145
  // check if chainId is configured in data connector config
@@ -102,8 +151,8 @@ export class BundleBase {
102
151
  chainId = config.chainId;
103
152
  }
104
153
  if (chainId && this.etherRpcConfig && this.etherRpcConfig[chainId]) {
105
- const provider = new ethers.JsonRpcProvider(this.etherRpcConfig[chainId].url);
106
- return provider;
154
+ const rpcConfig = this.etherRpcConfig[chainId];
155
+ return createFallbackRpcProvider(rpcConfig.urls ?? [rpcConfig.url]);
107
156
  }
108
157
  else {
109
158
  return this.providerIdentity;
@@ -1,8 +1,15 @@
1
- import { ethers } from 'ethers';
2
- import { EtherRpcConfig, ViewConfig } from '../types';
3
- import { BundleBase } from './bundleBase';
1
+ import type { ethers } from 'ethers';
2
+ import type { ExecutionAppConfig } from '../execution/executionApp.js';
3
+ import type { EtherRpcConfig, ViewConfig } from '../types.js';
4
+ import { BundleBase } from './bundleBase.js';
4
5
  export declare class DataConnector extends BundleBase {
5
- constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
6
+ constructor(wasmFile: string | ArrayBuffer, _config: string, executionAppConfig: ExecutionAppConfig, identity?: ethers.Provider, etherRpcConfig?: EtherRpcConfig);
6
7
  getRpcUrl(config: any): string | undefined;
7
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;
8
15
  }
@@ -1,11 +1,11 @@
1
- import { Contract } from 'ethers';
2
- import { CENTRALIZE_CONTRACT_INTERACTION_CHAINS } from '../utils/consts';
3
- import { callWithRetry } from '../utils/utils';
4
- import { BundleBase } from './bundleBase';
1
+ import { AbiCoder, Contract, Interface } from 'ethers';
2
+ import { CENTRALIZE_CONTRACT_INTERACTION_CHAINS } from '../utils/consts.js';
3
+ import { callWithRetry } from '../utils/utils.js';
4
+ import { BundleBase } from './bundleBase.js';
5
5
  export class DataConnector extends BundleBase {
6
6
  // Identity should come from the node's IdentityManager.wallet
7
- constructor(wasmFile, _config, identity, etherRpcConfig) {
8
- super(wasmFile, _config, identity, etherRpcConfig);
7
+ constructor(wasmFile, _config, executionAppConfig, identity, etherRpcConfig) {
8
+ super(wasmFile, _config, executionAppConfig, identity, etherRpcConfig);
9
9
  }
10
10
  // get rpc url from configuration
11
11
  getRpcUrl(config) {
@@ -26,19 +26,30 @@ export class DataConnector extends BundleBase {
26
26
  }
27
27
  }
28
28
  // Makes contract instance and calls, returns stringified result
29
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
29
  async view(config) {
31
30
  const provider = this.getProvider(config);
32
31
  if (!provider)
33
32
  throw new Error('Provider not initialized');
34
33
  const contract = new Contract(config.address, config.abi, provider);
35
- // For formatting the parameters if needed
36
34
  const paramsArray = config.arguments;
37
35
  let result;
38
36
  if (CENTRALIZE_CONTRACT_INTERACTION_CHAINS.indexOf(this.configObj.chainId.toString()) === -1) {
39
- result = await contract[config.method](...paramsArray, {
40
- blockTag: this.executionContext?.blockNumber,
41
- }); //@note uncomment for deterministic blocks
37
+ try {
38
+ result = await contract[config.method](...paramsArray, {
39
+ blockTag: this.executionContext?.blockNumber,
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
+ }
42
53
  }
43
54
  else {
44
55
  const viewContractConfig = {
@@ -54,4 +65,28 @@ export class DataConnector extends BundleBase {
54
65
  // This gets stringified before calling main
55
66
  return result;
56
67
  }
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
+ }
57
92
  }
@@ -1,17 +1,62 @@
1
- import { ethers } from 'ethers';
2
- import { EtherRpcConfig } from '../types';
3
- import { ExecutionBase } from './executionBase';
4
- export declare class ExecutionApp extends ExecutionBase {
1
+ import type { ethers } from 'ethers';
2
+ import type { EtherRpcConfig, JobDetails } from '../types.js';
3
+ import { ExecutionBase } from './executionBase.js';
4
+ export interface ExecutionAppConfig {
5
+ /** Vault address used for execution context and subgraph queries. */
6
+ vault: string;
7
+ /** Chain ID used to resolve RPC configuration and on-chain reads. */
8
+ chainId: number;
9
+ /** Subgraph endpoint used for protocol data queries. */
5
10
  steerSubgraph: string;
11
+ poolType: {
12
+ /** Set true when the pool uses Algebra v1 semantics. */
13
+ isAlgebraPool: boolean;
14
+ /** Set true when the pool uses Algebra Integral semantics. */
15
+ isAlgebraIntegralPool: boolean;
16
+ /** Set true when the pool uses directional pool semantics. */
17
+ isDirectionalPool: boolean;
18
+ /** Set true when the pool uses PoolShark semantics. */
19
+ isPoolSharkPool: boolean;
20
+ /** Set true when the pool uses Aerodrome semantics. */
21
+ isAerodromePool: boolean;
22
+ };
23
+ apiKeys: {
24
+ /** API key for The Graph Studio / gateway endpoints. */
25
+ subgraphStudioKey: string;
26
+ /** API key for Sentio endpoints, if applicable. */
27
+ sentioApiKey: string;
28
+ };
29
+ /** Maximum number of retries for execution operations. */
30
+ maxRetries?: number;
31
+ }
32
+ export declare class ExecutionApp extends ExecutionBase {
6
33
  vault: string;
34
+ steerSubgraph: string;
35
+ chainId: number;
7
36
  isAlgebraPool: boolean;
37
+ isAlgebraIntegralPool: boolean;
8
38
  isDirectionalPool: boolean;
9
- chainId: number;
10
- constructor(vault: string, steerSubgraph: string, isAlgebraPool: boolean, isDirectionalPool: boolean, chainId: number, maxRetries?: number);
11
- execute<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig): Promise<Array<T>>;
39
+ isPoolSharkPool: boolean;
40
+ isAerodromePool: boolean;
41
+ subgraphStudioKey: string;
42
+ sentioApiKey: string;
43
+ config: ExecutionAppConfig;
44
+ constructor(config: ExecutionAppConfig);
45
+ execute<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig, forceDeposit?: boolean): Promise<Array<T>>;
46
+ executeStabilityVault<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig, forceDeposit?: boolean): Promise<Array<T>>;
47
+ executeDynamicJobs<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _job: JobDetails, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig, forceDeposit?: boolean): Promise<Array<T>>;
12
48
  private getSmartPoolExecutionContext;
13
49
  private getPoolCurrentTick;
50
+ private getTickSpacing;
51
+ /**
52
+ * Converts a value to string, handling both native bigint and serialized bigint objects
53
+ * from the centralized API
54
+ */
55
+ private convertToString;
56
+ private getTotalAmounts;
14
57
  private getVaultPoolAddress;
15
58
  private getSlot0;
59
+ private getSlot0Aerodrome;
60
+ private getGlobalStateAbi;
16
61
  private getGlobalState;
17
62
  }