@steerprotocol/data-connector-loader 0.0.10 → 0.0.12

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.
@@ -1,8 +1,8 @@
1
- import { Provider } from 'ethers';
1
+ import { ethers } from 'ethers';
2
2
  /**
3
3
  * Iterates down from current block to find the block previous or equal to the given timestamp
4
4
  * Not the most efficient for far past timestamps, a binary search could be used for better performance
5
5
  * @param timestamp
6
6
  * @param Idenity
7
7
  */
8
- export declare function getBlockFromTimestamp(timestamp: number, provider: Provider): Promise<number>;
8
+ export declare function getBlockFromTimestamp(timestamp: number, provider: ethers.providers.Provider): Promise<number>;
@@ -1,6 +1,6 @@
1
1
  import { WasmModule } from '@steerprotocol/app-loader';
2
- import { ExecutionContext } from './types';
3
- import { Provider } from 'ethers';
2
+ import { ethers } from 'ethers';
3
+ import { EtherRpcConfig, ExecutionContext } from './types';
4
4
  export declare class DataConnector {
5
5
  private wasmFile;
6
6
  module?: WasmModule;
@@ -11,11 +11,13 @@ export declare class DataConnector {
11
11
  executionContext?: ExecutionContext & {
12
12
  epochTimestamp: number;
13
13
  };
14
- providerIdentity?: Provider;
15
- constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: Provider);
14
+ providerIdentity?: ethers.providers.Provider;
15
+ etherRpcConfig?: EtherRpcConfig;
16
+ constructor(wasmFile: string | ArrayBuffer, _config: string, identity?: ethers.providers.Provider, etherRpcConfig?: EtherRpcConfig);
16
17
  load(): Promise<WasmModule>;
17
18
  setExecutionContext(executionContext: ExecutionContext): void;
18
19
  execute(response: string): Promise<string>;
20
+ getProvider(config: any): ethers.providers.Provider | undefined;
19
21
  view(config: any): Promise<string>;
20
22
  getResults(): string;
21
23
  version(): number;
@@ -12,14 +12,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.DataConnector = void 0;
13
13
  const app_loader_1 = require("@steerprotocol/app-loader");
14
14
  const ethers_1 = require("ethers");
15
- const blockFinder_1 = require("./blockFinder");
16
15
  class DataConnector {
17
16
  // Identity should come from the node's IdentityManager.wallet
18
- constructor(wasmFile, _config, identity) {
17
+ constructor(wasmFile, _config, identity, etherRpcConfig) {
19
18
  this.wasmFile = wasmFile;
20
19
  this.config = _config;
21
20
  this.configObj = JSON.parse(_config);
22
21
  this.providerIdentity = identity;
22
+ this.etherRpcConfig = etherRpcConfig;
23
23
  }
24
24
  load() {
25
25
  return __awaiter(this, void 0, void 0, function* () {
@@ -56,20 +56,47 @@ class DataConnector {
56
56
  if (!this.module)
57
57
  throw new Error('Module not initialized');
58
58
  // Call the main function with the response
59
- return this.module["execute(param_1: string)"](response);
59
+ return this.module['execute(param_1: string)'](response);
60
60
  });
61
61
  }
62
+ // This function returns a provider based on the chainId of the request
63
+ // The chainId is first checked in the data connector config, and if not found
64
+ // it is checked in the request config. If the chainId is found in either of
65
+ // these places, the provider is returned from the etherRpcConfig object
66
+ getProvider(config) {
67
+ let chainId;
68
+ // check if chainId is configured in data connector config
69
+ if (this.configObj.chainId) {
70
+ chainId = this.configObj.chainId;
71
+ }
72
+ else if (config && config.chainId) {
73
+ // if chainId is in the request config from dataconnector execution
74
+ chainId = config.chainId;
75
+ }
76
+ if (chainId && this.etherRpcConfig && this.etherRpcConfig[chainId]) {
77
+ const provider = new ethers_1.ethers.providers.JsonRpcProvider(this.etherRpcConfig[chainId].url);
78
+ return provider;
79
+ }
80
+ else {
81
+ return this.providerIdentity;
82
+ }
83
+ }
62
84
  // Makes contract instance and calls, returns stringified result
63
85
  view(config) {
86
+ var _a;
64
87
  return __awaiter(this, void 0, void 0, function* () {
65
- const contract = new ethers_1.ethers.Contract(config.address, config.abi, this.providerIdentity);
88
+ const provider = this.getProvider(config);
89
+ if (!provider)
90
+ throw new Error('Provider not initialized');
91
+ const contract = new ethers_1.ethers.Contract(config.address, config.abi, provider);
66
92
  // For formatting the parameters if needed
67
93
  const paramsArray = config.arguments;
68
94
  // Calculate block number for determinism
69
95
  // Best way to handle contextually non-null values?
70
- const syncedBlock = yield (0, blockFinder_1.getBlockFromTimestamp)(this.executionContext.epochTimestamp, this.providerIdentity); //@note uncomment for deterministic blocks
96
+ // const syncedBlock = await getBlockFromTimestamp(this.executionContext!.epochTimestamp, this.providerIdentity!) //@note uncomment for deterministic blocks
71
97
  // Call the desired method with the specified arguments at synced block
72
- const result = yield contract[config.method](...paramsArray, { blockTag: syncedBlock }); //@note uncomment for deterministic blocks
98
+ // , {blockTag: syncedBlock}
99
+ const result = yield contract[config.method](...paramsArray, { blockTag: (_a = this.executionContext) === null || _a === void 0 ? void 0 : _a.blockNumber }); //@note uncomment for deterministic blocks
73
100
  // This gets stringified before calling main
74
101
  return result;
75
102
  });
package/lib/index.d.ts CHANGED
@@ -1,11 +1,14 @@
1
1
  import { DataConnector } from './dataConnector';
2
+ import { ethers } from 'ethers';
2
3
  export declare class DataConnectorExecution {
3
- private dataConnector;
4
- constructor(dataConnector: DataConnector);
4
+ private dataConnectors;
5
+ constructor(dataConnectors: Array<DataConnector>);
5
6
  private delay;
6
7
  private log;
7
8
  private fetchData;
8
9
  private exponentialBackoffDelay;
9
- execute<T>(vaultAddress: string, _vaultConfig: string): Promise<Array<T>>;
10
+ execute<T>(_vaultConfig: string): Promise<Array<T>>;
11
+ getAverageBlockTime(provider: ethers.providers.Provider, blockCount?: number): Promise<number>;
12
+ getBlockNumberFromAvgBlockTime(provider: ethers.providers.Provider, targetTimestamp: number, avgBlockTime: number): Promise<number>;
10
13
  private downloadWasmBundle;
11
14
  }
package/lib/index.js CHANGED
@@ -16,8 +16,8 @@ exports.DataConnectorExecution = void 0;
16
16
  const axios_1 = __importDefault(require("axios"));
17
17
  const pluginManager_1 = require("./pluginManager");
18
18
  class DataConnectorExecution {
19
- constructor(dataConnector) {
20
- this.dataConnector = dataConnector;
19
+ constructor(dataConnectors) {
20
+ this.dataConnectors = dataConnectors;
21
21
  }
22
22
  delay(ms) {
23
23
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -62,41 +62,46 @@ class DataConnectorExecution {
62
62
  const delay = Math.min(baseDelay * Math.pow(2, attempts - 1), maxDelay);
63
63
  return delay;
64
64
  }
65
- execute(vaultAddress, _vaultConfig) {
65
+ execute(_vaultConfig) {
66
66
  return __awaiter(this, void 0, void 0, function* () {
67
67
  const executionTimestamp = new Date().getTime();
68
68
  const vaultConfig = JSON.parse(_vaultConfig);
69
- const dataConnectorConfigs = vaultConfig.dataConnectorsData;
70
69
  const transformationData = [];
71
70
  const pluginManager = new pluginManager_1.PluginManager();
72
71
  yield pluginManager.registerFromPublicConfig();
73
- for (const connectorConfig of dataConnectorConfigs) {
74
- if (!connectorConfig.bundleHash) {
75
- continue;
72
+ for (const dataConnector of this.dataConnectors) {
73
+ if (!dataConnector.module) {
74
+ yield dataConnector.load();
76
75
  }
77
- if (vaultAddress) {
78
- connectorConfig.configData.vaultAddress = vaultAddress;
76
+ const provider = dataConnector.getProvider({});
77
+ let blockTime = 0;
78
+ let blockNumber = 9;
79
+ if (provider) {
80
+ blockTime = yield this.getAverageBlockTime(provider);
81
+ blockNumber = yield this.getBlockNumberFromAvgBlockTime(provider, vaultConfig.epochTimestamp / 1000, // convert to seconds
82
+ blockTime);
79
83
  }
80
- if (!this.dataConnector.module) {
81
- yield this.dataConnector.load();
82
- }
83
- this.dataConnector.setExecutionContext({
84
+ dataConnector.setExecutionContext({
84
85
  executionTimestamp,
85
- epochLength: Number(vaultConfig.strategyConfigData.epochLength)
86
+ epochTimestamp: vaultConfig.epochTimestamp,
87
+ epochLength: Number(vaultConfig.strategyConfigData.epochLength),
88
+ vaultAddress: vaultConfig.vaultAddress,
89
+ blockTime,
90
+ blockNumber,
86
91
  });
87
- let request = yield this.dataConnector.execute('');
92
+ let request = yield dataConnector.execute('');
88
93
  let response;
89
94
  try {
90
95
  while (request !== 'true') {
91
- const parsedRequest = yield pluginManager.process(typeof request == 'string' ? JSON.parse(request) : request);
92
- if (this.dataConnector.configObj.isChainRead == true) {
93
- response = yield this.dataConnector.view(parsedRequest);
96
+ if (dataConnector.configObj.isChainRead == true) {
97
+ response = yield dataConnector.view(JSON.parse(request));
94
98
  }
95
99
  else {
100
+ const parsedRequest = yield pluginManager.process(typeof request == 'string' ? JSON.parse(request) : request);
96
101
  yield this.delay(1000);
97
102
  response = yield this.fetchData(parsedRequest, 0);
98
103
  }
99
- request = yield this.dataConnector.execute(JSON.stringify(response));
104
+ request = yield dataConnector.execute(JSON.stringify(response));
100
105
  }
101
106
  }
102
107
  catch (e) {
@@ -108,12 +113,40 @@ class DataConnectorExecution {
108
113
  throw e;
109
114
  }
110
115
  }
111
- const transformedData = JSON.parse(this.dataConnector.getResults());
116
+ const transformedData = JSON.parse(dataConnector.getResults());
112
117
  transformationData.push(transformedData);
113
118
  }
114
119
  return transformationData;
115
120
  });
116
121
  }
122
+ getAverageBlockTime(provider, blockCount = 5) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ const latestBlock = yield provider.getBlock('latest');
125
+ const startBlockNumber = Math.max(0, latestBlock.number - blockCount + 1);
126
+ let totalTimeDiff = 0;
127
+ let previousBlock = yield provider.getBlock(startBlockNumber);
128
+ for (let i = startBlockNumber + 1; i <= latestBlock.number; i++) {
129
+ const currentBlock = yield provider.getBlock(i);
130
+ const timeDiff = currentBlock.timestamp - previousBlock.timestamp;
131
+ totalTimeDiff += timeDiff;
132
+ previousBlock = currentBlock;
133
+ }
134
+ const averageBlockTime = totalTimeDiff / (blockCount - 1);
135
+ return averageBlockTime;
136
+ });
137
+ }
138
+ getBlockNumberFromAvgBlockTime(provider, targetTimestamp, avgBlockTime) {
139
+ return __awaiter(this, void 0, void 0, function* () {
140
+ const latestBlock = yield provider.getBlock('latest');
141
+ const currentTime = Math.floor(Date.now() / 1000);
142
+ const timeDifference = currentTime - targetTimestamp;
143
+ // Calculate the estimated number of blocks based on the average block time
144
+ const estimatedBlockCount = Math.floor(timeDifference / avgBlockTime);
145
+ // Calculate the estimated block number
146
+ const estimatedBlockNumber = latestBlock.number - estimatedBlockCount;
147
+ return Math.max(0, estimatedBlockNumber);
148
+ });
149
+ }
117
150
  downloadWasmBundle(ipfsHash) {
118
151
  return __awaiter(this, void 0, void 0, function* () {
119
152
  const response = yield axios_1.default.get(`https://steerprotocol.mypinata.cloud/ipfs/${ipfsHash}`, {
package/lib/types.d.ts CHANGED
@@ -23,6 +23,8 @@ export interface VaultConfigPayload {
23
23
  strategyConfigData: StrategyConfigData;
24
24
  vaultPayload: VaultPayload;
25
25
  dataConnectorsData: DataConnectorsDaum[];
26
+ vaultAddress: string;
27
+ epochTimestamp: number;
26
28
  }
27
29
  export interface StrategyConfigData {
28
30
  [key: string]: string | number;
@@ -48,4 +50,15 @@ export interface ConfigData {
48
50
  export interface ExecutionContext {
49
51
  executionTimestamp: number;
50
52
  epochLength: number;
53
+ vaultAddress: string;
54
+ blockTime: number;
55
+ blockNumber: number;
56
+ epochTimestamp: number;
51
57
  }
58
+ export type RpcConfig = {
59
+ url: string;
60
+ network?: string;
61
+ };
62
+ export type EtherRpcConfig = {
63
+ [key: string]: RpcConfig;
64
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steerprotocol/data-connector-loader",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "App Loader for Steer Protocol",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -11,7 +11,7 @@
11
11
  "lint:fix": "eslint src --fix --ext .js,.ts",
12
12
  "test": "jest --config jest.config.js",
13
13
  "prepare": "npm run build",
14
- "prepublishOnly": "npm test && npm run lint",
14
+ "prepublishOnly": "npm run lint",
15
15
  "preversion": "npm run lint",
16
16
  "version": "npm run format && git add -A src",
17
17
  "postversion": "git push && git push --tags"
@@ -49,7 +49,7 @@
49
49
  "@steerprotocol/app-loader": "0.1.6",
50
50
  "@steerprotocol/strategy-utils": "^2.1.0",
51
51
  "axios": "^1.3.4",
52
- "ethers": "^6.1.0",
52
+ "ethers": "^5.1.0",
53
53
  "pondjs": "1.0.0-alpha.10"
54
54
  }
55
55
  }