@steerprotocol/data-connector-loader 2.1.1 → 3.0.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.
Files changed (50) hide show
  1. package/lib/{base → esm/bundle}/bundleBase.d.ts +7 -5
  2. package/lib/esm/bundle/bundleBase.js +127 -0
  3. package/lib/{bundle/bundleExecution.d.ts → esm/bundle/bundleDataConnector.d.ts} +2 -1
  4. package/lib/esm/bundle/bundleDataConnector.js +57 -0
  5. package/lib/esm/execution/executionApp.d.ts +17 -0
  6. package/lib/esm/execution/executionApp.js +304 -0
  7. package/lib/{loader/loaderBase.d.ts → esm/execution/executionBase.d.ts} +2 -2
  8. package/lib/esm/execution/executionBase.js +95 -0
  9. package/lib/esm/execution/executionDataConnector.d.ts +9 -0
  10. package/lib/esm/execution/executionDataConnector.js +90 -0
  11. package/lib/esm/index.d.ts +5 -0
  12. package/lib/esm/index.js +5 -0
  13. package/lib/esm/package.json +1 -0
  14. package/lib/esm/types.d.ts +104 -0
  15. package/lib/esm/types.js +1 -0
  16. package/lib/esm/utils/blockFinder.js +20 -0
  17. package/lib/esm/utils/consts.d.ts +4 -0
  18. package/lib/esm/utils/consts.js +4 -0
  19. package/lib/esm/utils/pluginManager.js +67 -0
  20. package/lib/esm/utils/utils.d.ts +16 -0
  21. package/lib/esm/utils/utils.js +119 -0
  22. package/lib/execution/executionApp.d.ts +3 -3
  23. package/lib/execution/executionApp.js +78 -80
  24. package/lib/execution/executionDataConnector.d.ts +2 -2
  25. package/lib/types.d.ts +1 -1
  26. package/lib/utils/consts.js +2 -2
  27. package/lib/utils/utils.d.ts +5 -5
  28. package/lib/utils/utils.js +5 -5
  29. package/package.json +33 -3
  30. package/lib/base/bundleBase.js +0 -119
  31. package/lib/base/loaderBase.d.ts +0 -14
  32. package/lib/base/loaderBase.js +0 -111
  33. package/lib/blockFinder.js +0 -36
  34. package/lib/bundle/bundleApp.d.ts +0 -6
  35. package/lib/bundle/bundleApp.js +0 -11
  36. package/lib/bundle/bundleExecution.js +0 -42
  37. package/lib/bundleDataConnector.d.ts +0 -7
  38. package/lib/bundleDataConnector.js +0 -42
  39. package/lib/bundleExecution.d.ts +0 -7
  40. package/lib/bundleExecution.js +0 -42
  41. package/lib/dataConnector.d.ts +0 -27
  42. package/lib/dataConnector.js +0 -133
  43. package/lib/execution/executionBundle.d.ts +0 -5
  44. package/lib/execution/executionBundle.js +0 -29
  45. package/lib/loader/loaderBase.js +0 -111
  46. package/lib/pluginManager.js +0 -84
  47. package/lib/utils.d.ts +0 -2
  48. package/lib/utils.js +0 -28
  49. /package/lib/{blockFinder.d.ts → esm/utils/blockFinder.d.ts} +0 -0
  50. /package/lib/{pluginManager.d.ts → esm/utils/pluginManager.d.ts} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { WasmModule } from '@steerprotocol/app-loader';
2
- import { EtherRpcConfig, ExecutionContext } from '../types';
3
2
  import { providers } from 'ethers';
3
+ import { EtherRpcConfig, ExecutionContext } from '../types';
4
4
  export declare class BundleBase {
5
- protected module?: WasmModule;
5
+ module?: WasmModule;
6
6
  protected wasmFile: ArrayBuffer | string;
7
7
  protected config: string;
8
- protected configObj: {
8
+ configObj: {
9
9
  [key: string]: any;
10
10
  };
11
11
  protected etherRpcConfig?: EtherRpcConfig;
@@ -13,12 +13,14 @@ export declare class BundleBase {
13
13
  executionContext?: ExecutionContext & {
14
14
  epochTimestamp: number;
15
15
  };
16
+ protected scheduleEpochTimestamp: number | undefined;
16
17
  constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: providers.Provider, etherRpcConfig?: EtherRpcConfig);
17
18
  load(): Promise<WasmModule>;
18
19
  loadSync(): WasmModule;
19
20
  execute(response: string): Promise<string>;
20
- reset(): void;
21
- setExecutionContext(executionContext: ExecutionContext): void;
21
+ executeBundle(data: Array<any>): Promise<string>;
22
+ setExecutionContextStrategyExecution(executionContext: ExecutionContext): void;
23
+ setExecutionContextDataConnector(executionContext: ExecutionContext): void;
22
24
  protected executeModule(response: string): Promise<string>;
23
25
  getProvider(config: any): providers.Provider | undefined;
24
26
  getResults(): string;
@@ -0,0 +1,127 @@
1
+ import { loadWasm, loadWasmSync } from '@steerprotocol/app-loader';
2
+ import { providers } from 'ethers';
3
+ export class BundleBase {
4
+ constructor(wasmFile, _config, identity, etherRpcConfig) {
5
+ this.wasmFile = wasmFile;
6
+ this.config = _config;
7
+ this.configObj = JSON.parse(_config);
8
+ this.providerIdentity = identity;
9
+ this.etherRpcConfig = etherRpcConfig;
10
+ }
11
+ async load() {
12
+ const instance = await loadWasm(this.wasmFile, {});
13
+ this.module = instance;
14
+ this.module.initialize(this.config);
15
+ return this.module;
16
+ }
17
+ loadSync() {
18
+ if (typeof this.wasmFile === 'string')
19
+ throw new Error('Cannot load module synchronously unless wasmFile is of type ArrayBuffer');
20
+ this.module = loadWasmSync(this.wasmFile, {});
21
+ return this.module;
22
+ }
23
+ async execute(response) {
24
+ if (!this.executionContext) {
25
+ throw new Error('Execution context missing');
26
+ }
27
+ // If the module is not initialized, try to load it
28
+ if (!this.module) {
29
+ try {
30
+ await this.load();
31
+ }
32
+ catch {
33
+ throw new Error('Module not initialized');
34
+ }
35
+ }
36
+ // If the module is still not initialized, throw an error
37
+ if (!this.module)
38
+ throw new Error('Module not initialized');
39
+ // Call the main function with the response
40
+ return await this.module.execute(response);
41
+ }
42
+ async executeBundle(data) {
43
+ if (!this.executionContext) {
44
+ throw new Error('Execution context missing');
45
+ }
46
+ // If the module is not initialized, try to load it
47
+ if (!this.module) {
48
+ try {
49
+ await this.load();
50
+ }
51
+ catch {
52
+ throw new Error('Module not initialized');
53
+ }
54
+ }
55
+ // If the module is still not initialized, throw an error
56
+ if (!this.module)
57
+ throw new Error('Module not initialized');
58
+ // Call the main function with the response
59
+ return this.module.execute(...data);
60
+ }
61
+ setExecutionContextStrategyExecution(executionContext) {
62
+ // Determine the timestamp for epoch
63
+ const timestamp = this.subtractDate(executionContext.executionTimestamp, Number(executionContext.epochLength)).getTime();
64
+ // Divide milliseconds data to seconds for transformation bundle
65
+ const timestampInSecs = Math.floor(timestamp / 1000);
66
+ this.executionContext = { ...executionContext, epochTimestamp: timestampInSecs };
67
+ const completeConfig = { ...JSON.parse(this.config), ...this.executionContext };
68
+ this.scheduleEpochTimestamp = executionContext.epochTimestamp;
69
+ console.log('Complete execution config : ', completeConfig);
70
+ this.module?.initialize(JSON.stringify(completeConfig));
71
+ }
72
+ setExecutionContextDataConnector(executionContext) {
73
+ // Determine the timestamp for epoch
74
+ const timestamp = this.subtractDate(executionContext.executionTimestamp, Number(executionContext.epochLength)).getTime();
75
+ // Divide milliseconds data to seconds for transformation bundle
76
+ const timestampInSecs = Math.floor(timestamp / 1000);
77
+ this.executionContext = { ...executionContext, epochTimestamp: timestampInSecs };
78
+ const completeConfig = { ...JSON.parse(this.config), executionContext: this.executionContext };
79
+ this.scheduleEpochTimestamp = executionContext.epochTimestamp;
80
+ console.log('Complete execution config : ', completeConfig);
81
+ this.module?.initialize(JSON.stringify(completeConfig));
82
+ }
83
+ async executeModule(response) {
84
+ if (!this.module) {
85
+ throw new Error('Module not initialized');
86
+ }
87
+ return await this.module.execute(response);
88
+ }
89
+ // This function returns a provider based on the chainId of the request
90
+ // The chainId is first checked in the data connector config, and if not found
91
+ // it is checked in the request config. If the chainId is found in either of
92
+ // these places, the provider is returned from the etherRpcConfig object
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ getProvider(config) {
95
+ let chainId;
96
+ // check if chainId is configured in data connector config
97
+ if (this.configObj.chainId) {
98
+ chainId = this.configObj.chainId;
99
+ }
100
+ else if (config && config.chainId) {
101
+ // if chainId is in the request config from dataconnector execution
102
+ chainId = config.chainId;
103
+ }
104
+ if (chainId && this.etherRpcConfig && this.etherRpcConfig[chainId]) {
105
+ const provider = new providers.JsonRpcProvider(this.etherRpcConfig[chainId].url);
106
+ return provider;
107
+ }
108
+ else {
109
+ return this.providerIdentity;
110
+ }
111
+ }
112
+ getResults() {
113
+ if (!this.module)
114
+ throw new Error('Module not initialized');
115
+ return this.module.transform();
116
+ }
117
+ version() {
118
+ if (!this.module)
119
+ throw new Error('Module not initialized');
120
+ return Number(this.module.version());
121
+ }
122
+ subtractDate(timestamp, epochLength) {
123
+ const date = new Date(timestamp);
124
+ date.setSeconds(date.getSeconds() - epochLength);
125
+ return date;
126
+ }
127
+ }
@@ -1,7 +1,8 @@
1
1
  import { providers } from 'ethers';
2
- import { BundleBase } from './bundleBase';
3
2
  import { EtherRpcConfig, ViewConfig } from '../types';
3
+ import { BundleBase } from './bundleBase';
4
4
  export declare class DataConnector extends BundleBase {
5
5
  constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: providers.Provider, etherRpcConfig?: EtherRpcConfig);
6
+ getRpcUrl(config: any): string | undefined;
6
7
  view(config: ViewConfig): Promise<string>;
7
8
  }
@@ -0,0 +1,57 @@
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';
5
+ export class DataConnector extends BundleBase {
6
+ // Identity should come from the node's IdentityManager.wallet
7
+ constructor(wasmFile, _config, identity, etherRpcConfig) {
8
+ super(wasmFile, _config, identity, etherRpcConfig);
9
+ }
10
+ // get rpc url from configuration
11
+ getRpcUrl(config) {
12
+ let chainId;
13
+ // check if chainId is configured in data connector config
14
+ if (this.configObj.chainId) {
15
+ chainId = this.configObj.chainId;
16
+ }
17
+ else if (config && config.chainId) {
18
+ // if chainId is in the request config from dataconnector execution
19
+ chainId = config.chainId;
20
+ }
21
+ if (chainId && this.etherRpcConfig && this.etherRpcConfig[chainId]) {
22
+ return this.etherRpcConfig[chainId].url;
23
+ }
24
+ else {
25
+ return undefined;
26
+ }
27
+ }
28
+ // Makes contract instance and calls, returns stringified result
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ async view(config) {
31
+ const provider = this.getProvider(config);
32
+ if (!provider)
33
+ throw new Error('Provider not initialized');
34
+ const contract = new Contract(config.address, config.abi, provider);
35
+ // For formatting the parameters if needed
36
+ const paramsArray = config.arguments;
37
+ let result;
38
+ 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
42
+ }
43
+ else {
44
+ const viewContractConfig = {
45
+ epochTimestamp: this.scheduleEpochTimestamp,
46
+ address: this.configObj.address || config.address,
47
+ abi: config.abi,
48
+ arguments: paramsArray,
49
+ method: config.method,
50
+ rpcUrl: this.getRpcUrl(config),
51
+ };
52
+ result = await callWithRetry(viewContractConfig);
53
+ }
54
+ // This gets stringified before calling main
55
+ return result;
56
+ }
57
+ }
@@ -0,0 +1,17 @@
1
+ import { ethers } from 'ethers';
2
+ import { EtherRpcConfig } from '../types';
3
+ import { ExecutionBase } from './executionBase';
4
+ export declare class ExecutionApp extends ExecutionBase {
5
+ steerSubgraph: string;
6
+ vault: string;
7
+ isAlgebraPool: boolean;
8
+ 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.providers.Provider, _etherRpcConfig?: EtherRpcConfig): Promise<Array<T>>;
12
+ private getSmartPoolExecutionContext;
13
+ private getPoolCurrentTick;
14
+ private getVaultPoolAddress;
15
+ private getSlot0;
16
+ private getGlobalState;
17
+ }
@@ -0,0 +1,304 @@
1
+ import { DataConnector } from '../bundle/bundleDataConnector';
2
+ import { fetchData, readSlot0Contract } from '../utils/utils';
3
+ import { ExecutionBase } from './executionBase';
4
+ export class ExecutionApp extends ExecutionBase {
5
+ constructor(vault, steerSubgraph, isAlgebraPool, isDirectionalPool, chainId, maxRetries = 3) {
6
+ super(maxRetries);
7
+ this.getSlot0 = async (pool, currentExecutionContext, provider, rpc) => {
8
+ const slot0Abi = [
9
+ {
10
+ inputs: [],
11
+ name: 'slot0',
12
+ outputs: [
13
+ { internalType: 'uint160', name: 'sqrtPriceX96', type: 'uint160' },
14
+ { internalType: 'int24', name: 'tick', type: 'int24' },
15
+ { internalType: 'uint16', name: 'observationIndex', type: 'uint16' },
16
+ {
17
+ internalType: 'uint16',
18
+ name: 'observationCardinality',
19
+ type: 'uint16',
20
+ },
21
+ {
22
+ internalType: 'uint16',
23
+ name: 'observationCardinalityNext',
24
+ type: 'uint16',
25
+ },
26
+ { internalType: 'uint8', name: 'feeProtocol', type: 'uint8' },
27
+ { internalType: 'bool', name: 'unlocked', type: 'bool' },
28
+ ],
29
+ stateMutability: 'view',
30
+ type: 'function',
31
+ },
32
+ ];
33
+ const slot0 = await readSlot0Contract({
34
+ address: pool,
35
+ abi: slot0Abi,
36
+ currentExecutionContext,
37
+ functionName: 'slot0',
38
+ provider: provider,
39
+ rpc,
40
+ chainId: this.chainId,
41
+ });
42
+ return {
43
+ sqrtPriceX96: slot0[0],
44
+ tick: slot0[1],
45
+ observationIndex: slot0[2],
46
+ observationCardinality: slot0[3],
47
+ observationCardinalityNext: slot0[4],
48
+ feeProtocol: slot0[5],
49
+ unlocked: slot0[6],
50
+ };
51
+ };
52
+ this.getGlobalState = async (pool, currentExecutionContext, provider, rpc) => {
53
+ const slot0Abi = [
54
+ !this.isDirectionalPool
55
+ ? {
56
+ inputs: [],
57
+ name: 'globalState',
58
+ outputs: [
59
+ {
60
+ internalType: 'uint160',
61
+ name: 'price',
62
+ type: 'uint160',
63
+ },
64
+ {
65
+ internalType: 'int24',
66
+ name: 'tick',
67
+ type: 'int24',
68
+ },
69
+ {
70
+ internalType: 'int24',
71
+ name: 'prevInitializedTick',
72
+ type: 'int24',
73
+ },
74
+ {
75
+ internalType: 'uint16',
76
+ name: 'fee',
77
+ type: 'uint16',
78
+ },
79
+ {
80
+ internalType: 'uint16',
81
+ name: 'timepointIndex',
82
+ type: 'uint16',
83
+ },
84
+ {
85
+ internalType: 'uint8',
86
+ name: 'communityFee',
87
+ type: 'uint8',
88
+ },
89
+ {
90
+ internalType: 'bool',
91
+ name: 'unlocked',
92
+ type: 'bool',
93
+ },
94
+ ],
95
+ stateMutability: 'view',
96
+ type: 'function',
97
+ }
98
+ : {
99
+ inputs: [],
100
+ name: 'globalState',
101
+ outputs: [
102
+ {
103
+ internalType: 'uint160',
104
+ name: 'price',
105
+ type: 'uint160',
106
+ },
107
+ {
108
+ internalType: 'int24',
109
+ name: 'tick',
110
+ type: 'int24',
111
+ },
112
+ {
113
+ internalType: 'uint16',
114
+ name: 'feeZto',
115
+ type: 'uint16',
116
+ },
117
+ {
118
+ internalType: 'uint16',
119
+ name: 'feeOtz',
120
+ type: 'uint16',
121
+ },
122
+ {
123
+ internalType: 'uint16',
124
+ name: 'timepointIndex',
125
+ type: 'uint16',
126
+ },
127
+ {
128
+ internalType: 'uint8',
129
+ name: 'communityFeeToken0',
130
+ type: 'uint8',
131
+ },
132
+ {
133
+ internalType: 'uint8',
134
+ name: 'communityFeeToken1',
135
+ type: 'uint8',
136
+ },
137
+ {
138
+ internalType: 'bool',
139
+ name: 'unlocked',
140
+ type: 'bool',
141
+ },
142
+ ],
143
+ stateMutability: 'view',
144
+ type: 'function',
145
+ },
146
+ ];
147
+ const slot0 = await readSlot0Contract({
148
+ address: pool,
149
+ abi: slot0Abi,
150
+ currentExecutionContext,
151
+ functionName: 'globalState',
152
+ provider: provider,
153
+ rpc,
154
+ chainId: this.chainId,
155
+ });
156
+ return this.isDirectionalPool
157
+ ? {
158
+ price: slot0[0],
159
+ tick: slot0[1],
160
+ observationIndex: slot0[2],
161
+ observationCardinality: slot0[3],
162
+ observationCardinalityNext: slot0[4],
163
+ feeProtocol: slot0[5],
164
+ unlocked: slot0[6],
165
+ }
166
+ : {
167
+ price: slot0[0],
168
+ tick: slot0[1],
169
+ feeProtocol: slot0[2],
170
+ observationIndex: slot0[2],
171
+ observationCardinality: slot0[3],
172
+ observationCardinalityNext: slot0[4],
173
+ unlocked: slot0[6],
174
+ };
175
+ };
176
+ this.steerSubgraph = steerSubgraph;
177
+ this.vault = vault;
178
+ this.isAlgebraPool = isAlgebraPool;
179
+ this.isDirectionalPool = isDirectionalPool;
180
+ this.chainId = chainId;
181
+ }
182
+ async execute(_wasmFile, _vaultConfig, _data, _identity, _etherRpcConfig) {
183
+ const dataConnector = new DataConnector(_wasmFile, _vaultConfig, _identity, _etherRpcConfig);
184
+ await dataConnector.loadSync();
185
+ const executionContext = await this.getExecutionContext(dataConnector, JSON.parse(_vaultConfig));
186
+ let rpc = '';
187
+ if (_etherRpcConfig) {
188
+ rpc = _etherRpcConfig[this.chainId.toString()].url;
189
+ }
190
+ const smartPoolExecutionContext = await this.getSmartPoolExecutionContext(executionContext, dataConnector, JSON.parse(_vaultConfig), rpc);
191
+ dataConnector.setExecutionContextStrategyExecution({
192
+ ...executionContext,
193
+ ...smartPoolExecutionContext,
194
+ });
195
+ _data = _data.map((element) => JSON.stringify(element));
196
+ const result = await dataConnector.executeBundle(_data);
197
+ return JSON.parse(result);
198
+ }
199
+ async getSmartPoolExecutionContext(currentExecutionContext, dataConnector, vaultConfig, rpc) {
200
+ const smartPoolExecutionContext = {};
201
+ const request = {
202
+ method: 'POST',
203
+ url: this.steerSubgraph,
204
+ data: {
205
+ query: `
206
+ {
207
+ vaultPositions(where:{
208
+ vault: "${this.vault}",
209
+ timestamp_lt: "${currentExecutionContext.epochTimestamp}"
210
+ }, orderDirection: desc, orderBy: timestamp, first: 1){
211
+ id
212
+ timestamp
213
+ upperTick
214
+ lowerTick
215
+ relativeWeight
216
+ }
217
+ }
218
+ `,
219
+ },
220
+ };
221
+ const response = await fetchData(request, 4);
222
+ this.log('Subgraph response vault positions :', response);
223
+ const requestSnapshot = {
224
+ method: 'POST',
225
+ url: this.steerSubgraph,
226
+ data: {
227
+ query: `
228
+ {
229
+ vaultSnapshots(where:{
230
+ vaultAddress: "${this.vault}",
231
+ timestamp_lt: "${currentExecutionContext.epochTimestamp}"
232
+ }, orderDirection: desc, orderBy: timestamp, first: 1){
233
+ id
234
+ timestamp
235
+ }
236
+ }
237
+ `,
238
+ },
239
+ };
240
+ const responseSnapshot = await fetchData(requestSnapshot, 4);
241
+ this.log('Subgraph response current snapshot', responseSnapshot);
242
+ const positions = [];
243
+ if (response?.data?.vaultPositions && response?.data?.vaultPositions.length > 0) {
244
+ const positionResponse = response?.data?.vaultPositions[0];
245
+ for (let i = 0; i < positionResponse.upperTick.length; i++) {
246
+ const position = positionResponse;
247
+ positions.push({
248
+ startTick: Number(position.lowerTick[i]),
249
+ endTick: Number(position.upperTick[i]),
250
+ weight: Number(position.relativeWeight[i]),
251
+ });
252
+ }
253
+ }
254
+ let lastSnapshot;
255
+ if (responseSnapshot?.data?.vaultSnapshots && responseSnapshot?.data?.vaultSnapshots.length > 0) {
256
+ lastSnapshot = responseSnapshot?.data?.vaultSnapshots[0];
257
+ }
258
+ this.log('Subgraph response vault positions', positions);
259
+ smartPoolExecutionContext.positions = positions;
260
+ if (lastSnapshot) {
261
+ smartPoolExecutionContext.lastExecutionTime = (Date.now() - Number(lastSnapshot.timestamp) * 1000) / 1000;
262
+ }
263
+ else {
264
+ smartPoolExecutionContext.lastExecutionTime = currentExecutionContext.epochTimestamp;
265
+ }
266
+ const provider = dataConnector.getProvider(vaultConfig);
267
+ if (!provider) {
268
+ throw new Error('Provider configuration issue, unable to process Smart Pool execution context.');
269
+ }
270
+ const poolAddress = await this.getVaultPoolAddress();
271
+ const currentTick = await this.getPoolCurrentTick(poolAddress, provider, currentExecutionContext, rpc);
272
+ smartPoolExecutionContext.currentTick = currentTick;
273
+ // "currentTick": 10,
274
+ return smartPoolExecutionContext;
275
+ }
276
+ async getPoolCurrentTick(poolAddress, provider, currentExecutionContext, rpc) {
277
+ if (!this.isAlgebraPool) {
278
+ const slot0 = await this.getSlot0(poolAddress, currentExecutionContext, provider, rpc);
279
+ return slot0.tick;
280
+ }
281
+ else {
282
+ const slot0 = await this.getGlobalState(poolAddress, currentExecutionContext, provider, rpc);
283
+ return slot0.tick;
284
+ }
285
+ }
286
+ async getVaultPoolAddress() {
287
+ const requestSnapshot = {
288
+ method: 'POST',
289
+ url: this.steerSubgraph,
290
+ data: {
291
+ query: `
292
+ {
293
+ vault(id: "${this.vault}"){
294
+ id
295
+ pool
296
+ }
297
+ }
298
+ `,
299
+ },
300
+ };
301
+ const response = await fetchData(requestSnapshot, 4);
302
+ return response.data.vault.pool;
303
+ }
304
+ }
@@ -1,13 +1,13 @@
1
1
  import { ethers } from 'ethers';
2
2
  import { DataConnector } from '../bundle/bundleDataConnector';
3
- import { VaultConfigPayload, ExecutionContext } from '../types';
3
+ import { VaultConfigPayload, ExecutionContext, EtherRpcConfig } from '../types';
4
4
  export declare class ExecutionBase {
5
5
  maxRetries: number;
6
6
  constructor(maxRetries?: number);
7
7
  protected delay(ms: number): Promise<void>;
8
8
  protected log(...args: any[]): void;
9
9
  protected getExecutionContext(dataConnector: DataConnector, vaultConfig: VaultConfigPayload): Promise<ExecutionContext>;
10
- execute<T>(_vaultConfig: string): Promise<Array<T>>;
10
+ execute<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _identity?: ethers.providers.Provider, _etherRpcConfig?: EtherRpcConfig): Promise<Array<T>>;
11
11
  protected getDataConnectorVersion(dataConnector: DataConnector): Promise<number>;
12
12
  getAverageBlockTime(provider: ethers.providers.Provider, blockCount?: number): Promise<number>;
13
13
  getBlockNumberFromAvgBlockTime(provider: ethers.providers.Provider, targetTimestamp: number, avgBlockTime: number): Promise<number>;
@@ -0,0 +1,95 @@
1
+ export class ExecutionBase {
2
+ constructor(maxRetries = 3) {
3
+ this.maxRetries = 0;
4
+ this.maxRetries = maxRetries;
5
+ }
6
+ delay(ms) {
7
+ return new Promise((resolve) => setTimeout(resolve, ms));
8
+ }
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ log(...args) {
11
+ if (process.env.DEBUG === 'true') {
12
+ console.log(...args);
13
+ }
14
+ }
15
+ async getExecutionContext(dataConnector, vaultConfig) {
16
+ const provider = dataConnector.getProvider({});
17
+ let blockTime = 0;
18
+ let blockNumber = 9;
19
+ const anchorBlockNumber = vaultConfig.anchorBlockNumber;
20
+ const anchorProvided = typeof anchorBlockNumber === 'number' && anchorBlockNumber >= 0;
21
+ if (provider) {
22
+ blockTime = await this.getAverageBlockTime(provider);
23
+ if (!anchorProvided) {
24
+ blockNumber = await this.getBlockNumberFromAvgBlockTime(provider, vaultConfig.epochTimestamp / 1000, // convert to seconds
25
+ blockTime);
26
+ }
27
+ }
28
+ if (anchorProvided) {
29
+ blockNumber = anchorBlockNumber;
30
+ }
31
+ const context = {
32
+ executionTimestamp: new Date().getTime(),
33
+ epochTimestamp: vaultConfig.epochTimestamp,
34
+ epochLength: Number(vaultConfig.strategyConfigData.epochLength),
35
+ vaultAddress: vaultConfig.vaultAddress,
36
+ blockTime: blockTime,
37
+ blockNumber: blockNumber,
38
+ };
39
+ return context;
40
+ }
41
+ async execute(_wasmFile, _vaultConfig, _data, _identity, _etherRpcConfig) {
42
+ throw new Error('Not implemented');
43
+ }
44
+ async getDataConnectorVersion(dataConnector) {
45
+ let version = 1;
46
+ try {
47
+ version = await dataConnector.version();
48
+ }
49
+ catch (e) {
50
+ // Data connector is missing version function, fallback to v1 logic
51
+ }
52
+ return version;
53
+ }
54
+ async getAverageBlockTime(provider, blockCount = 5) {
55
+ const latestBlock = await provider.getBlock('latest');
56
+ if (latestBlock) {
57
+ const startBlockNumber = Math.max(0, latestBlock.number - blockCount + 1);
58
+ let totalTimeDiff = 0;
59
+ let previousBlock = await provider.getBlock(startBlockNumber);
60
+ if (!previousBlock) {
61
+ return 0;
62
+ }
63
+ for (let i = startBlockNumber + 1; i <= latestBlock.number; i++) {
64
+ const currentBlock = await provider.getBlock(i);
65
+ if (!currentBlock || !previousBlock || !currentBlock.timestamp || !previousBlock.timestamp) {
66
+ continue;
67
+ }
68
+ const timeDiff = currentBlock.timestamp - previousBlock.timestamp;
69
+ totalTimeDiff += timeDiff;
70
+ previousBlock = currentBlock;
71
+ }
72
+ const averageBlockTime = totalTimeDiff / (blockCount - 1);
73
+ return averageBlockTime;
74
+ }
75
+ else {
76
+ return 0;
77
+ }
78
+ }
79
+ async getBlockNumberFromAvgBlockTime(provider, targetTimestamp, avgBlockTime) {
80
+ const latestBlock = await provider.getBlock('latest');
81
+ const currentTime = Math.floor(Date.now() / 1000);
82
+ const timeDifference = currentTime - targetTimestamp;
83
+ if (!latestBlock) {
84
+ return 0;
85
+ }
86
+ if (avgBlockTime === 0) {
87
+ return latestBlock.number;
88
+ }
89
+ // Calculate the estimated number of blocks based on the average block time
90
+ const estimatedBlockCount = Math.floor(timeDifference / avgBlockTime);
91
+ // Calculate the estimated block number
92
+ const estimatedBlockNumber = latestBlock.number - estimatedBlockCount;
93
+ return Math.max(0, estimatedBlockNumber);
94
+ }
95
+ }
@@ -0,0 +1,9 @@
1
+ import { ExecutionBase } from './executionBase';
2
+ import { DataConnector } from '../bundle/bundleDataConnector';
3
+ export declare class DataConnectorExecution extends ExecutionBase {
4
+ private dataConnectors;
5
+ constructor(dataConnectors: Array<DataConnector>, maxRetries?: number);
6
+ execute<T>(_vaultConfig: string): Promise<Array<T>>;
7
+ private handleRequestResponse;
8
+ private transformData;
9
+ }