@steerprotocol/data-connector-loader 4.1.0 → 5.0.0-next.10
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 +136 -20
- package/lib/bundle/bundleBase.d.ts +11 -14
- package/lib/bundle/bundleBase.js +58 -90
- package/lib/bundle/bundleDataConnector.d.ts +2 -6
- package/lib/bundle/bundleDataConnector.js +22 -47
- package/lib/esm/bundle/bundleBase.d.ts +11 -14
- package/lib/esm/bundle/bundleBase.js +79 -93
- package/lib/esm/bundle/bundleDataConnector.d.ts +2 -6
- package/lib/esm/bundle/bundleDataConnector.js +26 -49
- package/lib/esm/execution/executionApp.d.ts +18 -17
- package/lib/esm/execution/executionApp.js +390 -370
- package/lib/esm/execution/executionBase.d.ts +6 -6
- package/lib/esm/execution/executionBase.js +27 -13
- package/lib/esm/execution/executionDataConnector.d.ts +7 -4
- package/lib/esm/execution/executionDataConnector.js +143 -76
- package/lib/esm/index.d.ts +7 -7
- package/lib/esm/index.js +4 -4
- package/lib/esm/types.d.ts +23 -25
- package/lib/esm/types.js +5 -5
- package/lib/esm/utils/blockFinder.d.ts +2 -2
- package/lib/esm/utils/blockFinder.js +3 -3
- package/lib/esm/utils/consts.js +39 -39
- package/lib/esm/utils/pluginManager.d.ts +1 -1
- package/lib/esm/utils/pluginManager.js +6 -5
- package/lib/esm/utils/replace-old-subgraphs.js +79 -61
- package/lib/esm/utils/rpc.d.ts +4 -0
- package/lib/esm/utils/rpc.js +32 -0
- package/lib/esm/utils/utils.d.ts +8 -11
- package/lib/esm/utils/utils.js +61 -55
- package/lib/execution/executionApp.d.ts +18 -17
- package/lib/execution/executionApp.js +379 -364
- package/lib/execution/executionBase.d.ts +6 -6
- package/lib/execution/executionBase.js +27 -13
- package/lib/execution/executionDataConnector.d.ts +7 -4
- package/lib/execution/executionDataConnector.js +146 -71
- package/lib/index.d.ts +7 -7
- package/lib/index.js +1 -1
- package/lib/package.json +1 -0
- package/lib/types.d.ts +23 -25
- package/lib/types.js +5 -5
- package/lib/utils/blockFinder.d.ts +2 -2
- package/lib/utils/blockFinder.js +3 -3
- package/lib/utils/consts.js +39 -39
- package/lib/utils/pluginManager.d.ts +1 -1
- package/lib/utils/pluginManager.js +5 -4
- package/lib/utils/replace-old-subgraphs.js +79 -61
- package/lib/utils/rpc.d.ts +4 -0
- package/lib/utils/rpc.js +47 -0
- package/lib/utils/utils.d.ts +8 -11
- package/lib/utils/utils.js +55 -60
- package/package.json +22 -17
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { DataConnector } from
|
|
3
|
-
import type {
|
|
1
|
+
import type { PublicClient } from "viem";
|
|
2
|
+
import type { DataConnector } from "../bundle/bundleDataConnector.js";
|
|
3
|
+
import type { ExecutionContext, RpcAccess, VaultConfigPayload } from "../types.js";
|
|
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: Array<any>): void;
|
|
9
9
|
protected getExecutionContext(dataConnector: DataConnector, vaultConfig: VaultConfigPayload): Promise<ExecutionContext>;
|
|
10
|
-
execute<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>,
|
|
10
|
+
execute<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, rpc?: RpcAccess): Promise<T | Array<T> | "continue">;
|
|
11
11
|
protected getDataConnectorVersion(dataConnector: DataConnector): Promise<number>;
|
|
12
|
-
getAverageBlockTime(provider:
|
|
13
|
-
getBlockNumberFromAvgBlockTime(provider:
|
|
12
|
+
getAverageBlockTime(provider: PublicClient, blockCount?: number): Promise<number>;
|
|
13
|
+
getBlockNumberFromAvgBlockTime(provider: PublicClient, targetTimestamp: number, avgBlockTime: number): Promise<number>;
|
|
14
14
|
}
|
|
@@ -7,12 +7,18 @@ export class ExecutionBase {
|
|
|
7
7
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
8
|
}
|
|
9
9
|
log(...args) {
|
|
10
|
-
if (process.env.DEBUG ===
|
|
10
|
+
if (process.env.DEBUG === "true") {
|
|
11
11
|
console.log(...args);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
async getExecutionContext(dataConnector, vaultConfig) {
|
|
15
|
-
const
|
|
15
|
+
const chainId = dataConnector.executionAppConfig.chainId;
|
|
16
|
+
if (!Number.isSafeInteger(chainId))
|
|
17
|
+
throw new Error("Invalid execution chain ID");
|
|
18
|
+
const provider = dataConnector.getClient();
|
|
19
|
+
if (provider && (await provider.getChainId()) !== chainId) {
|
|
20
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: provider chain does not match supplied context.");
|
|
21
|
+
}
|
|
16
22
|
let blockTime = 0;
|
|
17
23
|
let blockNumber = 9;
|
|
18
24
|
// Use anchorBlockNumber if provided, otherwise calculate from average block time
|
|
@@ -28,6 +34,7 @@ export class ExecutionBase {
|
|
|
28
34
|
blockNumber);
|
|
29
35
|
}
|
|
30
36
|
const context = {
|
|
37
|
+
chainId,
|
|
31
38
|
executionTimestamp: new Date().getTime(),
|
|
32
39
|
epochTimestamp: vaultConfig.epochTimestamp,
|
|
33
40
|
epochLength: Number(vaultConfig.strategyConfigData.epochLength),
|
|
@@ -37,8 +44,8 @@ export class ExecutionBase {
|
|
|
37
44
|
};
|
|
38
45
|
return context;
|
|
39
46
|
}
|
|
40
|
-
async execute(_wasmFile, _vaultConfig, _data,
|
|
41
|
-
throw new Error(
|
|
47
|
+
async execute(_wasmFile, _vaultConfig, _data, rpc) {
|
|
48
|
+
throw new Error("Not implemented");
|
|
42
49
|
}
|
|
43
50
|
async getDataConnectorVersion(dataConnector) {
|
|
44
51
|
let version = 1;
|
|
@@ -51,20 +58,27 @@ export class ExecutionBase {
|
|
|
51
58
|
return version;
|
|
52
59
|
}
|
|
53
60
|
async getAverageBlockTime(provider, blockCount = 5) {
|
|
54
|
-
const latestBlock = await provider.getBlock(
|
|
61
|
+
const latestBlock = await provider.getBlock({ blockTag: "latest" });
|
|
55
62
|
if (latestBlock) {
|
|
56
|
-
const startBlockNumber = Math.max(0, latestBlock.number - blockCount + 1);
|
|
63
|
+
const startBlockNumber = Math.max(0, Number(latestBlock.number) - blockCount + 1);
|
|
57
64
|
let totalTimeDiff = 0;
|
|
58
|
-
let previousBlock = await provider.getBlock(
|
|
65
|
+
let previousBlock = await provider.getBlock({
|
|
66
|
+
blockNumber: BigInt(startBlockNumber),
|
|
67
|
+
});
|
|
59
68
|
if (!previousBlock) {
|
|
60
69
|
return 0;
|
|
61
70
|
}
|
|
62
71
|
for (let i = startBlockNumber + 1; i <= latestBlock.number; i++) {
|
|
63
|
-
const currentBlock = await provider.getBlock(
|
|
64
|
-
|
|
72
|
+
const currentBlock = await provider.getBlock({
|
|
73
|
+
blockNumber: BigInt(i),
|
|
74
|
+
});
|
|
75
|
+
if (!currentBlock ||
|
|
76
|
+
!previousBlock ||
|
|
77
|
+
!currentBlock.timestamp ||
|
|
78
|
+
!previousBlock.timestamp) {
|
|
65
79
|
continue;
|
|
66
80
|
}
|
|
67
|
-
const timeDiff = currentBlock.timestamp - previousBlock.timestamp;
|
|
81
|
+
const timeDiff = Number(currentBlock.timestamp - previousBlock.timestamp);
|
|
68
82
|
totalTimeDiff += timeDiff;
|
|
69
83
|
previousBlock = currentBlock;
|
|
70
84
|
}
|
|
@@ -76,19 +90,19 @@ export class ExecutionBase {
|
|
|
76
90
|
}
|
|
77
91
|
}
|
|
78
92
|
async getBlockNumberFromAvgBlockTime(provider, targetTimestamp, avgBlockTime) {
|
|
79
|
-
const latestBlock = await provider.getBlock(
|
|
93
|
+
const latestBlock = await provider.getBlock({ blockTag: "latest" });
|
|
80
94
|
const currentTime = Math.floor(Date.now() / 1000);
|
|
81
95
|
const timeDifference = currentTime - targetTimestamp;
|
|
82
96
|
if (!latestBlock) {
|
|
83
97
|
return 0;
|
|
84
98
|
}
|
|
85
99
|
if (avgBlockTime === 0) {
|
|
86
|
-
return latestBlock.number;
|
|
100
|
+
return Number(latestBlock.number);
|
|
87
101
|
}
|
|
88
102
|
// Calculate the estimated number of blocks based on the average block time
|
|
89
103
|
const estimatedBlockCount = Math.floor(timeDifference / avgBlockTime);
|
|
90
104
|
// Calculate the estimated block number
|
|
91
|
-
const estimatedBlockNumber = latestBlock.number - estimatedBlockCount;
|
|
105
|
+
const estimatedBlockNumber = Number(latestBlock.number) - estimatedBlockCount;
|
|
92
106
|
return Math.max(0, estimatedBlockNumber);
|
|
93
107
|
}
|
|
94
108
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { DataConnector } from
|
|
2
|
-
import type
|
|
3
|
-
import { ExecutionBase } from
|
|
1
|
+
import type { DataConnector } from "../bundle/bundleDataConnector.js";
|
|
2
|
+
import { type ExecutionContext } from "../types.js";
|
|
3
|
+
import { ExecutionBase } from "./executionBase.js";
|
|
4
4
|
export declare class DataConnectorExecution extends ExecutionBase {
|
|
5
5
|
private dataConnectors;
|
|
6
6
|
constructor(dataConnectors: Array<DataConnector>, maxRetries?: number);
|
|
@@ -10,8 +10,11 @@ export declare class DataConnectorExecution extends ExecutionBase {
|
|
|
10
10
|
* Chain reads receive its exact blockNumber; HTTP and subgraph responses are
|
|
11
11
|
* intentionally not represented as block-pinned data.
|
|
12
12
|
*/
|
|
13
|
-
executeWithContext<T>(_vaultConfig: string, context:
|
|
13
|
+
executeWithContext<T>(_vaultConfig: string, context: ExecutionContext): Promise<Array<T>>;
|
|
14
14
|
private executeV2Bundle;
|
|
15
|
+
private getConnectorVersion;
|
|
16
|
+
private executeInitializedV2Bundle;
|
|
17
|
+
private executeV1Bundle;
|
|
15
18
|
executeDynamicJob<T>(_vaultConfig: string): Promise<Array<T>>;
|
|
16
19
|
private handleRequestResponse;
|
|
17
20
|
private transformData;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { changeUrlIfOld } from
|
|
4
|
-
import { extendOHLCV, fetchData } from
|
|
5
|
-
import { ExecutionBase } from
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { DataConnectorTransportError, } from "../types.js";
|
|
3
|
+
import { changeUrlIfOld } from "../utils/replace-old-subgraphs.js";
|
|
4
|
+
import { extendOHLCV, fetchData } from "../utils/utils.js";
|
|
5
|
+
import { ExecutionBase } from "./executionBase.js";
|
|
6
6
|
export class DataConnectorExecution extends ExecutionBase {
|
|
7
7
|
constructor(dataConnectors, maxRetries = 3) {
|
|
8
8
|
super(maxRetries);
|
|
@@ -11,39 +11,16 @@ export class DataConnectorExecution extends ExecutionBase {
|
|
|
11
11
|
async execute(_vaultConfig) {
|
|
12
12
|
const vaultConfig = JSON.parse(_vaultConfig);
|
|
13
13
|
const transformationData = [];
|
|
14
|
-
const pluginManager = new PluginManager();
|
|
15
|
-
await pluginManager.registerFromPublicConfig();
|
|
16
14
|
for (const dataConnector of this.dataConnectors) {
|
|
17
|
-
if (!dataConnector.module)
|
|
15
|
+
if (!dataConnector.module)
|
|
18
16
|
await dataConnector.load();
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
version = dataConnector.version();
|
|
23
|
-
}
|
|
24
|
-
catch (e) {
|
|
25
|
-
version = 1;
|
|
26
|
-
}
|
|
27
|
-
if (version >= 2) {
|
|
28
|
-
const transformData = await this.executeV2Bundle(dataConnector, vaultConfig);
|
|
29
|
-
transformationData.push(transformData);
|
|
17
|
+
if (this.getConnectorVersion(dataConnector) >= 2) {
|
|
18
|
+
transformationData.push(await this.executeV2Bundle(dataConnector, vaultConfig));
|
|
30
19
|
}
|
|
31
20
|
else {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const initialRequest = await dataConnector.execute();
|
|
36
|
-
if (initialRequest === null) {
|
|
37
|
-
throw new Error('Data connector returned null request');
|
|
38
|
-
}
|
|
39
|
-
const finalResponse = await this.handleRequestResponse(dataConnector, pluginManager, initialRequest);
|
|
40
|
-
const transformedData = await this.transformData(dataConnector, finalResponse);
|
|
41
|
-
transformationData.push(transformedData);
|
|
42
|
-
}
|
|
43
|
-
catch (e) {
|
|
44
|
-
const transformData = await this.executeV2Bundle(dataConnector, vaultConfig);
|
|
45
|
-
transformationData.push(transformData);
|
|
46
|
-
}
|
|
21
|
+
const executionContext = await this.getExecutionContext(dataConnector, vaultConfig);
|
|
22
|
+
dataConnector.setExecutionContextDataConnector(executionContext);
|
|
23
|
+
transformationData.push(await this.executeV1Bundle(dataConnector));
|
|
47
24
|
}
|
|
48
25
|
}
|
|
49
26
|
return transformationData;
|
|
@@ -55,52 +32,88 @@ export class DataConnectorExecution extends ExecutionBase {
|
|
|
55
32
|
*/
|
|
56
33
|
async executeWithContext(_vaultConfig, context) {
|
|
57
34
|
const vaultConfig = JSON.parse(_vaultConfig);
|
|
58
|
-
if (!context ||
|
|
59
|
-
|
|
35
|
+
if (!context ||
|
|
36
|
+
!Number.isSafeInteger(context.chainId) ||
|
|
37
|
+
!Number.isSafeInteger(context.blockNumber) ||
|
|
38
|
+
context.blockNumber < 0 ||
|
|
39
|
+
!Number.isSafeInteger(context.epochTimestamp) ||
|
|
40
|
+
context.epochTimestamp < 0 ||
|
|
41
|
+
!Number.isSafeInteger(context.executionTimestamp) ||
|
|
42
|
+
context.executionTimestamp < 0 ||
|
|
43
|
+
context.executionTimestamp !== context.epochTimestamp * 1000 ||
|
|
44
|
+
!Number.isFinite(context.epochLength) ||
|
|
45
|
+
!Number.isFinite(context.blockTime) ||
|
|
46
|
+
typeof context.vaultAddress !== "string" ||
|
|
47
|
+
context.vaultAddress.length === 0) {
|
|
48
|
+
throw new Error("INVALID_EXECUTION_CONTEXT: supplied execution context is malformed.");
|
|
60
49
|
}
|
|
61
|
-
if (context.vaultAddress.toLowerCase() !==
|
|
62
|
-
|
|
50
|
+
if (context.vaultAddress.toLowerCase() !==
|
|
51
|
+
vaultConfig.vaultAddress.toLowerCase()) {
|
|
52
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: supplied context vault does not match vaultConfig.vaultAddress.");
|
|
63
53
|
}
|
|
64
54
|
const requestChainId = vaultConfig.chainId;
|
|
65
55
|
if (requestChainId !== undefined && requestChainId !== context.chainId) {
|
|
66
|
-
throw new Error(
|
|
56
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: supplied context chain does not match vaultConfig.chainId.");
|
|
57
|
+
}
|
|
58
|
+
if (vaultConfig.anchorBlockNumber !== undefined &&
|
|
59
|
+
String(vaultConfig.anchorBlockNumber) !== String(context.blockNumber)) {
|
|
60
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: supplied context block does not match anchorBlockNumber.");
|
|
67
61
|
}
|
|
68
|
-
if (
|
|
69
|
-
|
|
62
|
+
if (Number(vaultConfig.strategyConfigData?.epochLength) !==
|
|
63
|
+
context.epochLength) {
|
|
64
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: supplied context epoch length does not match vaultConfig.");
|
|
70
65
|
}
|
|
71
|
-
const
|
|
72
|
-
executionTimestamp: Number(context.epochTimestamp) * 1000,
|
|
73
|
-
epochTimestamp: Number(context.epochTimestamp),
|
|
74
|
-
epochLength: Number(vaultConfig.strategyConfigData.epochLength),
|
|
75
|
-
vaultAddress: context.vaultAddress,
|
|
76
|
-
blockTime: 0,
|
|
77
|
-
blockNumber: Number(context.blockNumber),
|
|
78
|
-
};
|
|
66
|
+
const pinnedContext = Object.freeze({ ...context });
|
|
79
67
|
const transformationData = [];
|
|
80
68
|
for (const dataConnector of this.dataConnectors) {
|
|
81
|
-
if (dataConnector.executionAppConfig.chainId !==
|
|
82
|
-
throw new Error(
|
|
69
|
+
if (dataConnector.executionAppConfig.chainId !== pinnedContext.chainId) {
|
|
70
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: supplied context chain does not match connector configuration.");
|
|
71
|
+
}
|
|
72
|
+
if (dataConnector.configObj.chainId !== undefined &&
|
|
73
|
+
Number(dataConnector.configObj.chainId) !== pinnedContext.chainId) {
|
|
74
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: supplied context chain does not match connector settings.");
|
|
83
75
|
}
|
|
84
76
|
if (!dataConnector.module)
|
|
85
77
|
await dataConnector.load();
|
|
86
|
-
dataConnector.
|
|
87
|
-
|
|
88
|
-
|
|
78
|
+
dataConnector.initializeDataConnectorWithContext(pinnedContext);
|
|
79
|
+
if (this.getConnectorVersion(dataConnector) >= 2) {
|
|
80
|
+
transformationData.push(await this.executeInitializedV2Bundle(dataConnector));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
transformationData.push(await this.executeV1Bundle(dataConnector, pinnedContext));
|
|
84
|
+
}
|
|
89
85
|
}
|
|
90
86
|
return transformationData;
|
|
91
87
|
}
|
|
92
88
|
async executeV2Bundle(dataConnector, vaultConfig) {
|
|
93
89
|
const executionContext = await this.getExecutionContext(dataConnector, vaultConfig);
|
|
94
90
|
dataConnector.setExecutionContextDataConnector(executionContext);
|
|
91
|
+
return this.executeInitializedV2Bundle(dataConnector);
|
|
92
|
+
}
|
|
93
|
+
getConnectorVersion(dataConnector) {
|
|
94
|
+
if (typeof dataConnector.module?.version !== "function")
|
|
95
|
+
return 1;
|
|
96
|
+
const version = dataConnector.version();
|
|
97
|
+
if (!Number.isInteger(version) || version < 1)
|
|
98
|
+
throw new Error("Invalid data connector version");
|
|
99
|
+
return version;
|
|
100
|
+
}
|
|
101
|
+
async executeInitializedV2Bundle(dataConnector) {
|
|
95
102
|
await dataConnector.execute();
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
return JSON.parse(await dataConnector.transform());
|
|
104
|
+
}
|
|
105
|
+
async executeV1Bundle(dataConnector, context) {
|
|
106
|
+
const initialRequest = await dataConnector.execute("");
|
|
107
|
+
if (initialRequest === null)
|
|
108
|
+
throw new Error("Data connector returned null request");
|
|
109
|
+
const result = await this.handleRequestResponse(dataConnector, initialRequest, context);
|
|
110
|
+
if (context)
|
|
111
|
+
return typeof result === "string" ? JSON.parse(result) : result;
|
|
112
|
+
return this.transformData(dataConnector, result);
|
|
98
113
|
}
|
|
99
114
|
async executeDynamicJob(_vaultConfig) {
|
|
100
115
|
const vaultConfig = JSON.parse(_vaultConfig);
|
|
101
116
|
const transformationData = [];
|
|
102
|
-
const pluginManager = new PluginManager();
|
|
103
|
-
await pluginManager.registerFromPublicConfig();
|
|
104
117
|
for (const dataConnector of this.dataConnectors) {
|
|
105
118
|
if (!dataConnector.module) {
|
|
106
119
|
await dataConnector.load();
|
|
@@ -113,57 +126,111 @@ export class DataConnectorExecution extends ExecutionBase {
|
|
|
113
126
|
}
|
|
114
127
|
return transformationData;
|
|
115
128
|
}
|
|
116
|
-
async handleRequestResponse(dataConnector,
|
|
129
|
+
async handleRequestResponse(dataConnector, initialRequest, context) {
|
|
117
130
|
let request = initialRequest;
|
|
118
131
|
let response;
|
|
119
132
|
try {
|
|
120
|
-
while (request !==
|
|
121
|
-
if (dataConnector.configObj.isChainRead
|
|
122
|
-
|
|
133
|
+
while (request !== "true") {
|
|
134
|
+
if (dataConnector.configObj.isChainRead === true) {
|
|
135
|
+
const view = JSON.parse(request);
|
|
136
|
+
if (context &&
|
|
137
|
+
view.chainId !== undefined &&
|
|
138
|
+
Number(view.chainId) !== context.chainId) {
|
|
139
|
+
throw new Error("EXECUTION_CONTEXT_MISMATCH: contract request chain does not match supplied context.");
|
|
140
|
+
}
|
|
141
|
+
response = await dataConnector.view(view);
|
|
123
142
|
}
|
|
124
143
|
else {
|
|
125
|
-
|
|
126
|
-
const
|
|
144
|
+
let parsedRequest = typeof request === "string" ? JSON.parse(request) : request;
|
|
145
|
+
const graphApiKey = dataConnector.executionAppConfig.apiKeys?.subgraphStudioKey;
|
|
146
|
+
const url = changeUrlIfOld(parsedRequest.url, graphApiKey ? undefined : dataConnector.configObj.subgraphStudioKey);
|
|
127
147
|
parsedRequest.url = url;
|
|
148
|
+
let sentio = false;
|
|
149
|
+
let graph = false;
|
|
150
|
+
try {
|
|
151
|
+
const destination = new URL(axios.getUri(parsedRequest));
|
|
152
|
+
const hostname = destination.hostname.toLowerCase();
|
|
153
|
+
graph =
|
|
154
|
+
(destination.origin === "https://gateway.thegraph.com" ||
|
|
155
|
+
destination.origin ===
|
|
156
|
+
"https://gateway-arbitrum.network.thegraph.com") &&
|
|
157
|
+
/^\/api\/(subgraphs|deployments)\/id\/[a-zA-Z0-9]+$/.test(destination.pathname) &&
|
|
158
|
+
!destination.username &&
|
|
159
|
+
!destination.password;
|
|
160
|
+
sentio =
|
|
161
|
+
destination.protocol === "https:" &&
|
|
162
|
+
(hostname === "sentio.xyz" || hostname.endsWith(".sentio.xyz"));
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
/* Axios will report an invalid URL when sending the request. */
|
|
166
|
+
}
|
|
167
|
+
const sentioApiKey = dataConnector.executionAppConfig.apiKeys?.sentioApiKey;
|
|
128
168
|
parsedRequest.headers = {
|
|
129
|
-
|
|
130
|
-
|
|
169
|
+
"Content-Type": url && !url.includes("subgraph-proxy-server")
|
|
170
|
+
? "application/json"
|
|
171
|
+
: "text/plain;charset=UTF-8",
|
|
172
|
+
...(sentio && sentioApiKey
|
|
173
|
+
? {
|
|
174
|
+
"api-key": sentioApiKey,
|
|
175
|
+
}
|
|
176
|
+
: {}),
|
|
177
|
+
...(graph && graphApiKey
|
|
178
|
+
? { Authorization: `Bearer ${graphApiKey}` }
|
|
179
|
+
: {}),
|
|
180
|
+
...parsedRequest.headers,
|
|
131
181
|
};
|
|
182
|
+
if (sentio || (graph && graphApiKey)) {
|
|
183
|
+
const { url, baseURL, method, params, data, headers, timeout, responseType, allowAbsoluteUrls, } = parsedRequest;
|
|
184
|
+
parsedRequest = {
|
|
185
|
+
url,
|
|
186
|
+
baseURL,
|
|
187
|
+
method,
|
|
188
|
+
params,
|
|
189
|
+
data,
|
|
190
|
+
headers,
|
|
191
|
+
timeout,
|
|
192
|
+
responseType,
|
|
193
|
+
allowAbsoluteUrls,
|
|
194
|
+
proxy: false,
|
|
195
|
+
maxRedirects: 0,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
132
198
|
await this.delay(1000);
|
|
133
199
|
try {
|
|
134
200
|
response = await fetchData(parsedRequest, 0);
|
|
135
201
|
}
|
|
136
202
|
catch (error) {
|
|
137
203
|
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
-
throw new DataConnectorTransportError(message.replace(/https?:\/\/[^\s@/]+(?::[^\s@/]+)?@/gi,
|
|
204
|
+
throw new DataConnectorTransportError(message.replace(/https?:\/\/[^\s@/]+(?::[^\s@/]+)?@/gi, "https://[REDACTED]@"));
|
|
139
205
|
}
|
|
140
206
|
}
|
|
141
|
-
const nextRequest = await dataConnector.execute(JSON.stringify(response));
|
|
207
|
+
const nextRequest = await dataConnector.execute(JSON.stringify(response, (_key, value) => typeof value === "bigint" ? value.toString() : value));
|
|
142
208
|
if (nextRequest === null) {
|
|
143
|
-
throw new Error(
|
|
209
|
+
throw new Error("Data connector returned null request");
|
|
144
210
|
}
|
|
145
211
|
request = nextRequest;
|
|
146
212
|
}
|
|
147
213
|
}
|
|
148
214
|
catch (e) {
|
|
149
215
|
// process.env.SILENT_ERRORS
|
|
150
|
-
if (process.env.DATA_LOADER_SILENT_ERRORS !==
|
|
151
|
-
console.error(
|
|
216
|
+
if (process.env.DATA_LOADER_SILENT_ERRORS !== "true") {
|
|
217
|
+
console.error("Data connector failed to process.", e);
|
|
152
218
|
}
|
|
153
219
|
throw e;
|
|
154
220
|
}
|
|
155
221
|
return dataConnector.getResults();
|
|
156
222
|
}
|
|
157
223
|
async transformData(dataConnector, rawData) {
|
|
158
|
-
let transformedData = typeof rawData ===
|
|
159
|
-
|
|
160
|
-
|
|
224
|
+
let transformedData = typeof rawData === "string" ? JSON.parse(rawData) : rawData;
|
|
225
|
+
if (Array.isArray(transformedData) &&
|
|
226
|
+
transformedData.length > 0 &&
|
|
227
|
+
transformedData[0] != null) {
|
|
161
228
|
const keys = Object.keys(transformedData[0]);
|
|
162
|
-
const requiredKeys = [
|
|
229
|
+
const requiredKeys = ["timestamp", "open", "high", "low", "close"];
|
|
163
230
|
const hasAllKeys = requiredKeys.every((key) => keys.includes(key));
|
|
164
231
|
// has the 'lookback' key
|
|
165
232
|
const lookback = dataConnector?.configObj?.lookback;
|
|
166
|
-
if (hasAllKeys &&
|
|
233
|
+
if (hasAllKeys && lookback) {
|
|
167
234
|
// Now that we have identified a v1 data connector, we need to transform the data so that the data is up to the current execution epoch timestamp
|
|
168
235
|
if (dataConnector?.executionContext?.epochTimestamp) {
|
|
169
236
|
const extended = extendOHLCV(transformedData, lookback, dataConnector?.executionContext?.epochTimestamp * 1000);
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { DataConnector } from
|
|
2
|
-
import { ExecutionApp, type ExecutionAppConfig } from
|
|
3
|
-
import { DataConnectorExecution } from
|
|
4
|
-
import type { ExecuteWithContextOptions, VaultConfigPayload } from
|
|
5
|
-
export type * from
|
|
1
|
+
import { DataConnector } from "./bundle/bundleDataConnector.js";
|
|
2
|
+
import { ExecutionApp, type ExecutionAppConfig } from "./execution/executionApp.js";
|
|
3
|
+
import { DataConnectorExecution } from "./execution/executionDataConnector.js";
|
|
4
|
+
import type { ExecuteWithContextOptions, VaultConfigPayload } from "./types.js";
|
|
5
|
+
export type * from "./types.js";
|
|
6
|
+
export { DataConnectorTransportError, ExecutionContextError, StrategyExecutionError, } from "./types.js";
|
|
7
|
+
export type { ExecuteWithContextOptions, ExecutionAppConfig, VaultConfigPayload, };
|
|
6
8
|
export { DataConnector, DataConnectorExecution, ExecutionApp };
|
|
7
|
-
export { DataConnectorTransportError, ExecutionContextError, StrategyExecutionError } from './types.js';
|
|
8
|
-
export type { ExecuteWithContextOptions, ExecutionAppConfig, VaultConfigPayload };
|
package/lib/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DataConnector } from
|
|
2
|
-
import { ExecutionApp } from
|
|
3
|
-
import { DataConnectorExecution } from
|
|
1
|
+
import { DataConnector } from "./bundle/bundleDataConnector.js";
|
|
2
|
+
import { ExecutionApp, } from "./execution/executionApp.js";
|
|
3
|
+
import { DataConnectorExecution } from "./execution/executionDataConnector.js";
|
|
4
|
+
export { DataConnectorTransportError, ExecutionContextError, StrategyExecutionError, } from "./types.js";
|
|
4
5
|
export { DataConnector, DataConnectorExecution, ExecutionApp };
|
|
5
|
-
export { DataConnectorTransportError, ExecutionContextError, StrategyExecutionError } from './types.js';
|
package/lib/esm/types.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { Abi, PublicClient } from "viem";
|
|
2
|
+
import type { ExecutionAppConfig } from "./execution/executionApp.js";
|
|
3
3
|
/** Error raised before a strategy is invoked when its supplied SDK anchor is unusable. */
|
|
4
4
|
export declare class ExecutionContextError extends Error {
|
|
5
|
-
readonly code:
|
|
6
|
-
constructor(code: ExecutionContextError[
|
|
5
|
+
readonly code: "INVALID_EXECUTION_CONTEXT" | "EXECUTION_CONTEXT_MISMATCH";
|
|
6
|
+
constructor(code: ExecutionContextError["code"], message: string);
|
|
7
7
|
}
|
|
8
8
|
/** Error classification for failures in a connector transport request. */
|
|
9
9
|
export declare class DataConnectorTransportError extends Error {
|
|
@@ -20,10 +20,8 @@ export interface ExecuteWithContextOptions {
|
|
|
20
20
|
wasmFile: string | ArrayBuffer;
|
|
21
21
|
vaultConfig: string;
|
|
22
22
|
data: Array<unknown>;
|
|
23
|
-
/**
|
|
24
|
-
executionContext:
|
|
25
|
-
identity?: ethers.Provider;
|
|
26
|
-
etherRpcConfig?: EtherRpcConfig;
|
|
23
|
+
/** Resolved strategy execution context. */
|
|
24
|
+
executionContext: SmartPoolExecutionContext;
|
|
27
25
|
forceDeposit?: boolean;
|
|
28
26
|
}
|
|
29
27
|
export type VaultInput = {
|
|
@@ -77,6 +75,7 @@ export interface ConfigData {
|
|
|
77
75
|
[key: string]: string | number;
|
|
78
76
|
}
|
|
79
77
|
export interface ExecutionContext {
|
|
78
|
+
chainId: number;
|
|
80
79
|
executionTimestamp: number;
|
|
81
80
|
epochLength: number;
|
|
82
81
|
vaultAddress: string;
|
|
@@ -97,17 +96,25 @@ export interface SmartPoolExecutionContext extends ExecutionContext {
|
|
|
97
96
|
totalAmount1: string;
|
|
98
97
|
tickSpacing: number;
|
|
99
98
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
/** RPC access for one execution chain. URL endpoints are validated individually. */
|
|
100
|
+
export type RpcAccess = {
|
|
101
|
+
client: PublicClient;
|
|
102
|
+
urls?: never;
|
|
103
|
+
} | {
|
|
104
|
+
urls: readonly string[];
|
|
105
|
+
client?: never;
|
|
107
106
|
};
|
|
107
|
+
export interface DataConnectorOptions {
|
|
108
|
+
wasmFile: string | ArrayBuffer;
|
|
109
|
+
config: string;
|
|
110
|
+
executionConfig: ExecutionAppConfig;
|
|
111
|
+
rpc?: RpcAccess;
|
|
112
|
+
}
|
|
113
|
+
export type ContractAbi = Abi | readonly string[] | string;
|
|
108
114
|
export interface ViewConfig {
|
|
115
|
+
chainId?: number;
|
|
109
116
|
address: string;
|
|
110
|
-
abi:
|
|
117
|
+
abi: ContractAbi;
|
|
111
118
|
method: string;
|
|
112
119
|
arguments: Array<unknown>;
|
|
113
120
|
}
|
|
@@ -125,15 +132,6 @@ export interface Slot0 {
|
|
|
125
132
|
timepointIndex?: number;
|
|
126
133
|
communityFee?: number;
|
|
127
134
|
}
|
|
128
|
-
export type ViewContractConfig = {
|
|
129
|
-
epochTimestamp?: number;
|
|
130
|
-
blockNumber?: number;
|
|
131
|
-
address: string;
|
|
132
|
-
abi: any;
|
|
133
|
-
arguments: Array<any>;
|
|
134
|
-
method: string;
|
|
135
|
-
rpcUrl?: string;
|
|
136
|
-
};
|
|
137
135
|
export type JobDetails = {
|
|
138
136
|
id: string;
|
|
139
137
|
name: string;
|
package/lib/esm/types.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
export class ExecutionContextError extends Error {
|
|
3
3
|
constructor(code, message) {
|
|
4
4
|
super(message);
|
|
5
|
-
this.name =
|
|
5
|
+
this.name = "ExecutionContextError";
|
|
6
6
|
this.code = code;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -10,15 +10,15 @@ export class ExecutionContextError extends Error {
|
|
|
10
10
|
export class DataConnectorTransportError extends Error {
|
|
11
11
|
constructor(message) {
|
|
12
12
|
super(message);
|
|
13
|
-
this.code =
|
|
14
|
-
this.name =
|
|
13
|
+
this.code = "DATA_CONNECTOR_TRANSPORT_ERROR";
|
|
14
|
+
this.name = "DataConnectorTransportError";
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
/** Error classification for a WASM strategy failure. */
|
|
18
18
|
export class StrategyExecutionError extends Error {
|
|
19
19
|
constructor(message) {
|
|
20
20
|
super(message);
|
|
21
|
-
this.code =
|
|
22
|
-
this.name =
|
|
21
|
+
this.code = "STRATEGY_EXECUTION_ERROR";
|
|
22
|
+
this.name = "StrategyExecutionError";
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PublicClient } from "viem";
|
|
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:
|
|
8
|
+
export declare function getBlockFromTimestamp(timestamp: number, provider: PublicClient): Promise<number>;
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* @param Idenity
|
|
6
6
|
*/
|
|
7
7
|
export async function getBlockFromTimestamp(timestamp, provider) {
|
|
8
|
-
let currentBlock = (await provider.getBlockNumber()) - 1;
|
|
9
|
-
let runningTimestamp = (await provider.getBlock(currentBlock))?.timestamp;
|
|
8
|
+
let currentBlock = Number(await provider.getBlockNumber()) - 1;
|
|
9
|
+
let runningTimestamp = (await provider.getBlock({ blockNumber: BigInt(currentBlock) }))?.timestamp;
|
|
10
10
|
if (!runningTimestamp)
|
|
11
11
|
return currentBlock;
|
|
12
12
|
while (runningTimestamp > timestamp) {
|
|
13
13
|
currentBlock -= 1;
|
|
14
|
-
runningTimestamp = (await provider.getBlock(currentBlock))?.timestamp;
|
|
14
|
+
runningTimestamp = (await provider.getBlock({ blockNumber: BigInt(currentBlock) }))?.timestamp;
|
|
15
15
|
if (!runningTimestamp)
|
|
16
16
|
return currentBlock;
|
|
17
17
|
}
|