@steerprotocol/data-connector-loader 0.0.11 → 0.0.13
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/lib/blockFinder.d.ts +2 -2
- package/lib/dataConnector.d.ts +6 -4
- package/lib/dataConnector.js +33 -6
- package/lib/index.d.ts +6 -3
- package/lib/index.js +53 -20
- package/lib/types.d.ts +13 -0
- package/package.json +3 -3
package/lib/blockFinder.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
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>;
|
package/lib/dataConnector.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WasmModule } from '@steerprotocol/app-loader';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
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;
|
package/lib/dataConnector.js
CHANGED
|
@@ -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[
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
4
|
-
constructor(
|
|
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>(
|
|
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(
|
|
20
|
-
this.
|
|
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(
|
|
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
|
|
74
|
-
if (!
|
|
75
|
-
|
|
72
|
+
for (const dataConnector of this.dataConnectors) {
|
|
73
|
+
if (!dataConnector.module) {
|
|
74
|
+
yield dataConnector.load();
|
|
76
75
|
}
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
81
|
-
yield this.dataConnector.load();
|
|
82
|
-
}
|
|
83
|
-
this.dataConnector.setExecutionContext({
|
|
84
|
+
dataConnector.setExecutionContext({
|
|
84
85
|
executionTimestamp,
|
|
85
|
-
|
|
86
|
+
epochTimestamp: vaultConfig.epochTimestamp,
|
|
87
|
+
epochLength: Number(vaultConfig.strategyConfigData.epochLength),
|
|
88
|
+
vaultAddress: vaultConfig.vaultAddress,
|
|
89
|
+
blockTime,
|
|
90
|
+
blockNumber,
|
|
86
91
|
});
|
|
87
|
-
let request = yield
|
|
92
|
+
let request = yield dataConnector.execute('');
|
|
88
93
|
let response;
|
|
89
94
|
try {
|
|
90
95
|
while (request !== 'true') {
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
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(
|
|
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.
|
|
3
|
+
"version": "0.0.13",
|
|
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
|
|
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": "^
|
|
52
|
+
"ethers": "^5.1.0",
|
|
53
53
|
"pondjs": "1.0.0-alpha.10"
|
|
54
54
|
}
|
|
55
55
|
}
|