@steerprotocol/data-connector-loader 5.0.0-next.1 → 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.
Files changed (50) hide show
  1. package/README.md +102 -0
  2. package/lib/bundle/bundleBase.d.ts +11 -14
  3. package/lib/bundle/bundleBase.js +56 -88
  4. package/lib/bundle/bundleDataConnector.d.ts +2 -6
  5. package/lib/bundle/bundleDataConnector.js +22 -47
  6. package/lib/esm/bundle/bundleBase.d.ts +11 -14
  7. package/lib/esm/bundle/bundleBase.js +77 -91
  8. package/lib/esm/bundle/bundleDataConnector.d.ts +2 -6
  9. package/lib/esm/bundle/bundleDataConnector.js +26 -49
  10. package/lib/esm/execution/executionApp.d.ts +16 -15
  11. package/lib/esm/execution/executionApp.js +364 -321
  12. package/lib/esm/execution/executionBase.d.ts +7 -7
  13. package/lib/esm/execution/executionBase.js +27 -13
  14. package/lib/esm/execution/executionDataConnector.d.ts +6 -3
  15. package/lib/esm/execution/executionDataConnector.js +128 -69
  16. package/lib/esm/index.d.ts +7 -7
  17. package/lib/esm/index.js +4 -4
  18. package/lib/esm/types.d.ts +20 -24
  19. package/lib/esm/types.js +5 -5
  20. package/lib/esm/utils/blockFinder.d.ts +2 -2
  21. package/lib/esm/utils/blockFinder.js +3 -3
  22. package/lib/esm/utils/consts.js +39 -39
  23. package/lib/esm/utils/pluginManager.d.ts +1 -1
  24. package/lib/esm/utils/pluginManager.js +6 -5
  25. package/lib/esm/utils/replace-old-subgraphs.js +79 -61
  26. package/lib/esm/utils/rpc.d.ts +4 -0
  27. package/lib/esm/utils/rpc.js +32 -0
  28. package/lib/esm/utils/utils.d.ts +8 -11
  29. package/lib/esm/utils/utils.js +61 -55
  30. package/lib/execution/executionApp.d.ts +16 -15
  31. package/lib/execution/executionApp.js +353 -315
  32. package/lib/execution/executionBase.d.ts +7 -7
  33. package/lib/execution/executionBase.js +27 -13
  34. package/lib/execution/executionDataConnector.d.ts +6 -3
  35. package/lib/execution/executionDataConnector.js +130 -64
  36. package/lib/index.d.ts +7 -7
  37. package/lib/index.js +1 -1
  38. package/lib/types.d.ts +20 -24
  39. package/lib/types.js +5 -5
  40. package/lib/utils/blockFinder.d.ts +2 -2
  41. package/lib/utils/blockFinder.js +3 -3
  42. package/lib/utils/consts.js +39 -39
  43. package/lib/utils/pluginManager.d.ts +1 -1
  44. package/lib/utils/pluginManager.js +5 -4
  45. package/lib/utils/replace-old-subgraphs.js +79 -61
  46. package/lib/utils/rpc.d.ts +4 -0
  47. package/lib/utils/rpc.js +47 -0
  48. package/lib/utils/utils.d.ts +8 -11
  49. package/lib/utils/utils.js +55 -60
  50. package/package.json +15 -15
@@ -1,46 +1,46 @@
1
- export const API_BASE_URL = 'https://cvrlulno2m.execute-api.ap-southeast-1.amazonaws.com/dev/contract-view-call';
1
+ export const API_BASE_URL = "https://cvrlulno2m.execute-api.ap-southeast-1.amazonaws.com/dev/contract-view-call";
2
2
  // export const API_BASE_URL = "http://localhost:3000/dev/contract-view-call";
3
3
  export const API_MAX_RETRIES = 3;
4
4
  export const API_INITIAL_DELAY = 1000;
5
5
  export const CENTRALIZE_CONTRACT_INTERACTION_CHAINS = [
6
- '999',
7
- '43114',
8
- '6900',
9
- '5464',
10
- '2020',
11
- '747474',
12
- '1116',
13
- '43111',
14
- '80094',
15
- '129399',
16
- '130',
17
- '146',
18
- '1868',
19
- '1',
20
- '80084',
21
- '2222',
22
- '1329',
23
- '1284',
24
- '42161',
25
- '9001',
26
- '137',
27
- '56',
28
- '5000',
29
- '250',
30
- '3776',
31
- '81457',
32
- '592',
33
- '1088',
34
- '34443',
6
+ "999",
7
+ "43114",
8
+ "6900",
9
+ "5464",
10
+ "2020",
11
+ "747474",
12
+ "1116",
13
+ "43111",
14
+ "80094",
15
+ "129399",
16
+ "130",
17
+ "146",
18
+ "1868",
19
+ "1",
20
+ "80084",
21
+ "2222",
22
+ "1329",
23
+ "1284",
24
+ "42161",
25
+ "9001",
26
+ "137",
27
+ "56",
28
+ "5000",
29
+ "250",
30
+ "3776",
31
+ "81457",
32
+ "592",
33
+ "1088",
34
+ "34443",
35
35
  // "8453",
36
- '30',
36
+ "30",
37
37
  // "8453",
38
- '167000',
39
- '196',
40
- '810180',
41
- '137',
42
- '314',
43
- '33139',
44
- '7000',
45
- '3338',
38
+ "167000",
39
+ "196",
40
+ "810180",
41
+ "137",
42
+ "314",
43
+ "33139",
44
+ "7000",
45
+ "3338",
46
46
  ];
@@ -1,4 +1,4 @@
1
- import type { AxiosRequestConfig } from 'axios';
1
+ import type { AxiosRequestConfig } from "axios";
2
2
  export declare class PluginManager {
3
3
  private registeredPluginConfigs;
4
4
  constructor();
@@ -1,10 +1,10 @@
1
- import axios from 'axios';
1
+ import axios from "axios";
2
2
  export class PluginManager {
3
3
  constructor() {
4
4
  this.registeredPluginConfigs = [];
5
5
  }
6
6
  async registerFromPublicConfig() {
7
- const { data: dataConnectorPlugins } = await axios.get('https://ro81h8hq6b.execute-api.us-east-1.amazonaws.com/data-connector-plugins');
7
+ const { data: dataConnectorPlugins } = await axios.get("https://ro81h8hq6b.execute-api.us-east-1.amazonaws.com/data-connector-plugins");
8
8
  for (const plugin of dataConnectorPlugins) {
9
9
  this.registerPluginConfig(plugin.name, plugin.domain, plugin.headers);
10
10
  }
@@ -26,7 +26,7 @@ export class PluginManager {
26
26
  const envValue = process.env[envVar];
27
27
  if (envValue === undefined) {
28
28
  console.log(`Environment variable '${envVar}' not found.`);
29
- return '';
29
+ return "";
30
30
  }
31
31
  return envValue;
32
32
  });
@@ -34,13 +34,14 @@ export class PluginManager {
34
34
  interpolateHeaders(headers) {
35
35
  const interpolatedHeaders = {};
36
36
  for (const [key, value] of Object.entries(headers)) {
37
- interpolatedHeaders[key] = typeof value === 'string' ? this.interpolateEnvVars(value) : value;
37
+ interpolatedHeaders[key] =
38
+ typeof value === "string" ? this.interpolateEnvVars(value) : value;
38
39
  }
39
40
  return interpolatedHeaders;
40
41
  }
41
42
  async process(config) {
42
43
  if (!config.url) {
43
- throw new Error('Request URL is not provided');
44
+ throw new Error("Request URL is not provided");
44
45
  }
45
46
  const matchingHeaders = this.findMatchingPluginConfigs(config.url);
46
47
  const interpolatedHeaders = this.interpolateHeaders(matchingHeaders);
@@ -1,6 +1,6 @@
1
1
  export class SubgraphUrlReplacer {
2
2
  constructor(config) {
3
- this.subgraphStudioKey = config?.subgraphStudioKey ?? '';
3
+ this.subgraphStudioKey = config?.subgraphStudioKey ?? "";
4
4
  this.subgraphUrlConfigs = config?.customConfigs || this.getDefaultConfigs();
5
5
  }
6
6
  changeUrlIfOld(url) {
@@ -8,108 +8,126 @@ export class SubgraphUrlReplacer {
8
8
  if (subgraphUrl) {
9
9
  return subgraphUrl.newUrl;
10
10
  }
11
+ // This retired Arbitrum Uniswap subgraph also appears in credential-bearing
12
+ // gateway URLs. Replace only its exact ID; never carry the embedded key over.
13
+ if (url) {
14
+ try {
15
+ const source = new URL(url);
16
+ if ((source.origin === "https://gateway.thegraph.com" ||
17
+ source.origin ===
18
+ "https://gateway-arbitrum.network.thegraph.com") &&
19
+ !source.username &&
20
+ !source.password &&
21
+ /^\/api\/(?:[^/]+\/)?subgraphs\/id\/Fo8QBLpEGfXHWkGMD3jSM4vVLk4JxvxxQD3v3U4fsrbh$/.test(source.pathname)) {
22
+ return this.getArbitrumSubgraphUrl("FbCGRftH4a3yZugY7TnbYgPJVEv2LvMT6oF1fxPe9aJM", false);
23
+ }
24
+ }
25
+ catch {
26
+ // Leave malformed or relative URLs for the request handler to process.
27
+ }
28
+ }
11
29
  return url;
12
30
  }
13
31
  getArbitrumSubgraphUrl(subgraphId, isDeploymentId) {
14
- return `https://gateway-arbitrum.network.thegraph.com/api/${this.subgraphStudioKey}/${isDeploymentId ? 'deployments' : 'subgraphs'}/id/${subgraphId}`;
32
+ return `https://gateway-arbitrum.network.thegraph.com/api/${this.subgraphStudioKey ? `${this.subgraphStudioKey}/` : ""}${isDeploymentId ? "deployments" : "subgraphs"}/id/${subgraphId}`;
15
33
  }
16
34
  getDefaultConfigs() {
17
35
  return [
18
36
  {
19
- chain: 'polygon',
20
- protocol: 'quickswap',
37
+ chain: "polygon",
38
+ protocol: "quickswap",
21
39
  newUrl: this.getArbitrumSubgraphUrl(`FqsRcH1XqSjqVx9GRTvEJe959aCbKrcyGgDWBrUkG24g`, false),
22
- oldUrl: 'https://api.thegraph.com/subgraphs/name/sameepsi/quickswap-v3',
40
+ oldUrl: "https://api.thegraph.com/subgraphs/name/sameepsi/quickswap-v3",
23
41
  },
24
42
  {
25
- chain: 'polygon',
26
- protocol: 'uniswap',
43
+ chain: "polygon",
44
+ protocol: "uniswap",
27
45
  newUrl: this.getArbitrumSubgraphUrl(`3hCPRGf4z88VC5rsBKU5AA9FBBq5nF3jbKJG7VZCbhjm`, false),
28
- oldUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon',
46
+ oldUrl: "https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-polygon",
29
47
  },
30
48
  {
31
- chain: 'optimism',
32
- protocol: 'uniswap',
49
+ chain: "optimism",
50
+ protocol: "uniswap",
33
51
  newUrl: this.getArbitrumSubgraphUrl(`Cghf4LfVqPiFw6fp6Y5X5Ubc8UpmUhSfJL82zwiBFLaj`, false),
34
- oldUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/optimism-post-regenesis',
52
+ oldUrl: "https://api.thegraph.com/subgraphs/name/ianlapham/optimism-post-regenesis",
35
53
  },
36
54
  {
37
- chain: 'arbitrum',
38
- protocol: 'uniswap',
55
+ chain: "arbitrum",
56
+ protocol: "uniswap",
39
57
  newUrl: this.getArbitrumSubgraphUrl(`FbCGRftH4a3yZugY7TnbYgPJVEv2LvMT6oF1fxPe9aJM`, false),
40
- oldUrl: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-dev',
58
+ oldUrl: "https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-dev",
41
59
  },
42
60
  {
43
- chain: 'celo',
44
- protocol: 'uniswap',
61
+ chain: "celo",
62
+ protocol: "uniswap",
45
63
  newUrl: this.getArbitrumSubgraphUrl(`ESdrTJ3twMwWVoQ1hUE2u7PugEHX3QkenudD6aXCkDQ4`, false),
46
- oldUrl: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo',
64
+ oldUrl: "https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo",
47
65
  },
48
66
  {
49
- chain: 'base',
50
- protocol: 'baseswap',
51
- newUrl: 'https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/v3-base/prod/gn',
52
- oldUrl: 'https://api.thegraph.com/subgraphs/name/harleen-m/basex',
67
+ chain: "base",
68
+ protocol: "baseswap",
69
+ newUrl: "https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/v3-base/prod/gn",
70
+ oldUrl: "https://api.thegraph.com/subgraphs/name/harleen-m/basex",
53
71
  },
54
72
  {
55
- chain: 'arbitrum',
56
- protocol: 'sushi',
57
- newUrl: this.getArbitrumSubgraphUrl('QmevuQAmgiou1UX7Z2BQf6RKdX1WunQjH8VtawhkzSLj4V', true),
58
- oldUrl: 'https://api.thegraph.com/subgraphs/name/sushi-v3/v3-arbitrum',
73
+ chain: "arbitrum",
74
+ protocol: "sushi",
75
+ newUrl: this.getArbitrumSubgraphUrl("QmevuQAmgiou1UX7Z2BQf6RKdX1WunQjH8VtawhkzSLj4V", true),
76
+ oldUrl: "https://api.thegraph.com/subgraphs/name/sushi-v3/v3-arbitrum",
59
77
  },
60
78
  {
61
- chain: 'avalanche',
62
- protocol: 'sushi',
63
- newUrl: this.getArbitrumSubgraphUrl('Qmcdd4SGVwG9VY4itrXBnBPWBVsQvsxfzaib9bVny9C8jT', true),
64
- oldUrl: 'https://api.thegraph.com/subgraphs/name/sushi-v3/v3-avalanche',
79
+ chain: "avalanche",
80
+ protocol: "sushi",
81
+ newUrl: this.getArbitrumSubgraphUrl("Qmcdd4SGVwG9VY4itrXBnBPWBVsQvsxfzaib9bVny9C8jT", true),
82
+ oldUrl: "https://api.thegraph.com/subgraphs/name/sushi-v3/v3-avalanche",
65
83
  },
66
84
  {
67
- chain: 'bsc',
68
- protocol: 'sushi',
69
- newUrl: this.getArbitrumSubgraphUrl('QmXsPN4TD4PUhT1ZWd5d1mdQPePFNMdJwUr6guSh1z9ZzA', true),
70
- oldUrl: 'https://api.thegraph.com/subgraphs/name/sushi-v3/v3-bsc',
85
+ chain: "bsc",
86
+ protocol: "sushi",
87
+ newUrl: this.getArbitrumSubgraphUrl("FiJDXMFCBv88GP17g2TtPh8BcA8jZozn5WRW7hCN7cUT", false),
88
+ oldUrl: "https://api.thegraph.com/subgraphs/name/sushi-v3/v3-bsc",
71
89
  },
72
90
  {
73
- chain: 'base',
74
- protocol: 'sushi',
75
- newUrl: this.getArbitrumSubgraphUrl('QmZ2R9ABG9ienaZdGyPLcDWDNDkG187RhXmh6fFuEtUaaS', true),
76
- oldUrl: 'https://api.studio.thegraph.com/query/32073/v3-base/v0.0.1',
91
+ chain: "base",
92
+ protocol: "sushi",
93
+ newUrl: this.getArbitrumSubgraphUrl("QmZ2R9ABG9ienaZdGyPLcDWDNDkG187RhXmh6fFuEtUaaS", true),
94
+ oldUrl: "https://api.studio.thegraph.com/query/32073/v3-base/v0.0.1",
77
95
  },
78
96
  {
79
- chain: 'optimism',
80
- protocol: 'sushi',
81
- newUrl: this.getArbitrumSubgraphUrl('QmbT6ZsxJEZKUrbzLrAWV5EnQfSKZeYtZ265mQUaB552vK', true),
82
- oldUrl: 'https://api.thegraph.com/subgraphs/name/sushi-v3/v3-optimism',
97
+ chain: "optimism",
98
+ protocol: "sushi",
99
+ newUrl: this.getArbitrumSubgraphUrl("QmbT6ZsxJEZKUrbzLrAWV5EnQfSKZeYtZ265mQUaB552vK", true),
100
+ oldUrl: "https://api.thegraph.com/subgraphs/name/sushi-v3/v3-optimism",
83
101
  },
84
102
  {
85
- chain: 'polygon',
86
- protocol: 'sushi',
87
- newUrl: this.getArbitrumSubgraphUrl('QmPbbjK9vtY69kSxMJRVLVz1dRzUBNwYbWTRYMiFzp9Tzm', true),
88
- oldUrl: 'https://api.thegraph.com/subgraphs/name/sushi-v3/v3-polygon',
103
+ chain: "polygon",
104
+ protocol: "sushi",
105
+ newUrl: this.getArbitrumSubgraphUrl("QmPbbjK9vtY69kSxMJRVLVz1dRzUBNwYbWTRYMiFzp9Tzm", true),
106
+ oldUrl: "https://api.thegraph.com/subgraphs/name/sushi-v3/v3-polygon",
89
107
  },
90
108
  {
91
- chain: 'zkevm',
92
- protocol: 'sushi',
93
- newUrl: this.getArbitrumSubgraphUrl('QmWH5ChjmF4Yp5Yhiaxczh5QwbG6HFSEi8bRwbKaUrJA6C', true),
94
- oldUrl: 'https://api.studio.thegraph.com/query/32073/v3-polygon-zkevm/v0.0.2',
109
+ chain: "zkevm",
110
+ protocol: "sushi",
111
+ newUrl: this.getArbitrumSubgraphUrl("QmWH5ChjmF4Yp5Yhiaxczh5QwbG6HFSEi8bRwbKaUrJA6C", true),
112
+ oldUrl: "https://api.studio.thegraph.com/query/32073/v3-polygon-zkevm/v0.0.2",
95
113
  },
96
114
  {
97
- chain: 'arbitrum',
98
- protocol: 'camelot',
99
- newUrl: 'https://subgraph-proxy-server-xf2uthetka-as.a.run.app/gateway-arbitrum/3utanEBA9nqMjPnuQP1vMCCys6enSM3EawBpKTVwnUw2',
100
- oldUrl: 'https://api.thegraph.com/subgraphs/name/camelotlabs/camelot-amm-v3',
115
+ chain: "arbitrum",
116
+ protocol: "camelot",
117
+ newUrl: "https://subgraph-proxy-server-xf2uthetka-as.a.run.app/gateway-arbitrum/3utanEBA9nqMjPnuQP1vMCCys6enSM3EawBpKTVwnUw2",
118
+ oldUrl: "https://api.thegraph.com/subgraphs/name/camelotlabs/camelot-amm-v3",
101
119
  },
102
120
  {
103
- chain: 'mode',
104
- protocol: 'swapmode',
105
- newUrl: 'https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/swapmode-v3/prod/gn',
106
- oldUrl: 'https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/swapmode-v3/1.0.0/gn',
121
+ chain: "mode",
122
+ protocol: "swapmode",
123
+ newUrl: "https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/swapmode-v3/prod/gn",
124
+ oldUrl: "https://api.goldsky.com/api/public/project_cltceeuudv1ij01x7ekxhfl46/subgraphs/swapmode-v3/1.0.0/gn",
107
125
  },
108
126
  {
109
- chain: 'linea',
110
- protocol: 'lynex',
111
- newUrl: 'https://api.goldsky.com/api/public/project_cltyhthusbmxp01s95k9l8a1u/subgraphs/lynex-cl/v1.0.2/gn',
112
- oldUrl: 'https://graph-query.linea.build/subgraphs/name/cryptoalgebra/analytics',
127
+ chain: "linea",
128
+ protocol: "lynex",
129
+ newUrl: "https://api.goldsky.com/api/public/project_cltyhthusbmxp01s95k9l8a1u/subgraphs/lynex-cl/v1.0.2/gn",
130
+ oldUrl: "https://graph-query.linea.build/subgraphs/name/cryptoalgebra/analytics",
113
131
  },
114
132
  ];
115
133
  }
@@ -0,0 +1,4 @@
1
+ import { type PublicClient } from "viem";
2
+ import type { RpcAccess } from "../types.js";
3
+ /** Each URL is checked on the same transport that will serve its reads. */
4
+ export declare function createRpcClient(access: RpcAccess, chainId: number): PublicClient;
@@ -0,0 +1,32 @@
1
+ import { createPublicClient, custom, fallback, http, } from "viem";
2
+ /** Each URL is checked on the same transport that will serve its reads. */
3
+ export function createRpcClient(access, chainId) {
4
+ if (!Number.isSafeInteger(chainId) || chainId <= 0)
5
+ throw new Error("Invalid execution chain ID");
6
+ if (access.client)
7
+ return access.client;
8
+ const urls = [
9
+ ...new Set(access.urls.map((url) => url.trim()).filter(Boolean)),
10
+ ];
11
+ if (!urls.length)
12
+ throw new Error("No RPC URLs configured");
13
+ const transports = urls.map((url) => {
14
+ const endpoint = createPublicClient({
15
+ transport: http(url, { retryCount: 0 }),
16
+ });
17
+ return custom({
18
+ async request({ method, params }) {
19
+ const actualChain = await endpoint.getChainId();
20
+ if (actualChain !== chainId) {
21
+ throw new Error("EXECUTION_CONTEXT_MISMATCH: provider chain does not match supplied context.");
22
+ }
23
+ if (method === "eth_chainId")
24
+ return `0x${actualChain.toString(16)}`;
25
+ return endpoint.request({ method, params });
26
+ },
27
+ }, { retryCount: 0 });
28
+ });
29
+ return createPublicClient({
30
+ transport: fallback(transports, { rank: false, retryCount: 0 }),
31
+ });
32
+ }
@@ -1,17 +1,14 @@
1
- import type { Candle } from '@steerprotocol/app-loader';
2
- import type { AxiosRequestConfig } from 'axios';
3
- import { type Provider } from 'ethers';
4
- import type { LegacyExecutionContext, ViewContractConfig } from '../types.js';
1
+ import type { Candle } from "@steerprotocol/app-loader";
2
+ import type { AxiosRequestConfig } from "axios";
3
+ import { type PublicClient } from "viem";
4
+ import type { ContractAbi, ExecutionContext } from "../types.js";
5
5
  export declare const extendOHLCV: (rawData: Array<Candle>, period: number, endTimestamp: number) => Array<Candle>;
6
6
  export declare function fetchData(request: AxiosRequestConfig, attempts: number): Promise<any>;
7
- export declare function readContract({ abi, address, chainId, contractArguments, currentExecutionContext, functionName, provider, rpc, }: {
7
+ export declare function readContract({ abi, address, contractArguments, currentExecutionContext, functionName, provider, }: {
8
8
  address: string;
9
- abi: any;
10
- currentExecutionContext: LegacyExecutionContext;
9
+ abi: ContractAbi;
10
+ currentExecutionContext?: Pick<ExecutionContext, "blockNumber">;
11
11
  functionName: string;
12
- provider: Provider;
13
- rpc: string;
12
+ provider: PublicClient;
14
13
  contractArguments?: Array<any>;
15
- chainId: number;
16
14
  }): Promise<any>;
17
- export declare function callWithRetry(config: ViewContractConfig): Promise<any>;
@@ -1,6 +1,5 @@
1
- import axios from 'axios';
2
- import { Contract } from 'ethers';
3
- import { API_BASE_URL, API_INITIAL_DELAY, API_MAX_RETRIES, CENTRALIZE_CONTRACT_INTERACTION_CHAINS } from './consts.js';
1
+ import axios from "axios";
2
+ import { getAbiItem, parseAbi, parseAbiItem, toFunctionSelector, } from "viem";
4
3
  // The purpose of this function is to look at the end timestamp and extend the current candle array so that it backfills any missing candles up to the end timestamp
5
4
  export const extendOHLCV = (rawData, period, endTimestamp) => {
6
5
  // Sort rawData by timestamp
@@ -31,22 +30,25 @@ async function delay(ms) {
31
30
  function exponentialBackoffDelay(attempts) {
32
31
  const baseDelay = 1000; // 1 second
33
32
  const maxDelay = 30000; // 30 seconds
34
- const delay = Math.min(baseDelay * Math.pow(2, attempts - 1), maxDelay);
33
+ const delay = Math.min(baseDelay * 2 ** (attempts - 1), maxDelay);
35
34
  return delay;
36
35
  }
37
36
  export async function fetchData(request, attempts) {
38
- log('Request payload: =============', request);
37
+ log("Request payload: =============", request);
39
38
  attempts = attempts + 1;
40
39
  try {
41
40
  const response = (await axios(request)).data;
42
41
  // this.log('API Response: =============', response);
43
- if ('errors' in response && response['errors'].length > 0) {
42
+ if (response !== null &&
43
+ typeof response === "object" &&
44
+ Array.isArray(response.errors) &&
45
+ response.errors.length > 0) {
44
46
  if (attempts < 3) {
45
47
  await delay(exponentialBackoffDelay(attempts));
46
48
  return await fetchData(request, attempts);
47
49
  }
48
50
  else {
49
- throw new Error('Maximum retry attempts reached');
51
+ throw new Error("Maximum retry attempts reached");
50
52
  }
51
53
  }
52
54
  return response;
@@ -61,59 +63,63 @@ export async function fetchData(request, attempts) {
61
63
  }
62
64
  }
63
65
  }
64
- export async function readContract({ abi, address, chainId, contractArguments = [], currentExecutionContext, functionName, provider, rpc, }) {
65
- // Create a new contract instance
66
- if (!provider)
67
- throw new Error('Provider not initialized');
68
- const contract = new Contract(address, abi, provider);
69
- // For formatting the parameters if needed
70
- const paramsArray = contractArguments || [];
71
- // Calculate block number for determinism
72
- // Best way to handle contextually non-null values?
73
- // const syncedBlock = await getBlockFromTimestamp(this.executionContext!.epochTimestamp, this.providerIdentity!) //@note uncomment for deterministic blocks
74
- // Call the desired method with the specified arguments at synced block
75
- // , {blockTag: syncedBlock}
76
- let result;
77
- if (CENTRALIZE_CONTRACT_INTERACTION_CHAINS.indexOf(chainId.toString()) === -1) {
78
- result = await contract[functionName](...paramsArray, {
79
- blockTag: currentExecutionContext?.blockNumber,
80
- }); // @note uncomment for deterministic blocks
81
- }
82
- else {
83
- console.log('Calling the centralized view');
84
- const viewContractConfig = {
85
- epochTimestamp: currentExecutionContext.epochTimestamp,
86
- blockNumber: currentExecutionContext.blockNumber,
87
- address,
88
- abi,
89
- arguments: paramsArray,
90
- method: functionName,
91
- rpcUrl: rpc,
66
+ function positionalTuple(value, parameter) {
67
+ if (/\[[0-9]*\]$/.test(parameter.type)) {
68
+ const item = {
69
+ ...parameter,
70
+ type: parameter.type.replace(/\[[0-9]*\]$/, ""),
92
71
  };
93
- result = await callWithRetry(viewContractConfig);
72
+ return value.map((entry) => positionalTuple(entry, item));
94
73
  }
95
- // This gets stringified before calling main
96
- return result;
74
+ if (parameter.type !== "tuple" || !("components" in parameter))
75
+ return value;
76
+ return parameter.components.map((component, index) => positionalTuple(Array.isArray(value) ? value[index] : value[component.name], component));
97
77
  }
98
- export async function callWithRetry(config) {
99
- let retries = 0;
100
- let delay = API_INITIAL_DELAY;
101
- while (retries < API_MAX_RETRIES) {
102
- try {
103
- const response = await axios.post(API_BASE_URL, config);
104
- return JSON.parse(response.data); // Return the data if the call was successful
105
- }
106
- catch (error) {
107
- console.error(`Attempt ${retries + 1} failed. Retrying in to fetch the contract method ${config.method} ${delay / 1000} seconds...`, error);
108
- await new Promise((resolve) => setTimeout(resolve, delay));
109
- delay *= 2; // Double the delay for the next retry
110
- retries++;
111
- }
112
- }
113
- throw new Error(`Failed after ${API_MAX_RETRIES} attempts. to call method ${config.method}`);
78
+ export async function readContract({ abi, address, contractArguments = [], currentExecutionContext, functionName, provider, }) {
79
+ if (!provider)
80
+ throw new Error("Provider not initialized");
81
+ const input = typeof abi === "string" ? JSON.parse(abi) : abi;
82
+ // Existing bundles may use ethers' optional tuple keyword.
83
+ const normalizeSignature = (signature) => signature.replace(/\btuple\s*\(/g, "(");
84
+ const normalizedAbi = (input.every((item) => typeof item === "string")
85
+ ? parseAbi(input.map(normalizeSignature))
86
+ : input);
87
+ const explicit = functionName.includes("(")
88
+ ? parseAbiItem(`function ${normalizeSignature(functionName)}`)
89
+ : undefined;
90
+ if (explicit && explicit.type !== "function")
91
+ throw new Error("Expected a function signature");
92
+ const selectedAbi = explicit
93
+ ? normalizedAbi.filter((item) => item.type === "function" &&
94
+ toFunctionSelector(item) === toFunctionSelector(explicit))
95
+ : normalizedAbi;
96
+ if (explicit && !selectedAbi.length)
97
+ throw new Error(`Function ${functionName} not found in ABI`);
98
+ const resolvedName = explicit && "name" in explicit ? explicit.name : functionName;
99
+ const result = await provider.readContract({
100
+ address: address,
101
+ abi: selectedAbi,
102
+ functionName: resolvedName,
103
+ args: contractArguments,
104
+ ...(currentExecutionContext?.blockNumber !== undefined
105
+ ? { blockNumber: BigInt(currentExecutionContext.blockNumber) }
106
+ : {}),
107
+ });
108
+ const item = getAbiItem({
109
+ abi: selectedAbi,
110
+ name: resolvedName,
111
+ args: contractArguments,
112
+ });
113
+ if (!item || item.type !== "function")
114
+ return result;
115
+ if (!item.outputs?.length)
116
+ return [];
117
+ return item.outputs.length === 1
118
+ ? positionalTuple(result, item.outputs[0])
119
+ : item.outputs.map((output, index) => positionalTuple(result[index], output));
114
120
  }
115
121
  function log(...args) {
116
- if (process.env.DEBUG === 'true') {
122
+ if (process.env.DEBUG === "true") {
117
123
  console.log(...args);
118
124
  }
119
125
  }
@@ -1,14 +1,14 @@
1
- import type { ethers } from 'ethers';
2
- import type { EtherRpcConfig, ExecuteWithContextOptions, JobDetails } from '../types.js';
3
- import { ExecutionBase } from './executionBase.js';
1
+ import type { ExecuteWithContextOptions, JobDetails, RpcAccess } from "../types.js";
2
+ import { ExecutionBase } from "./executionBase.js";
4
3
  export interface ExecutionAppConfig {
5
4
  /** Vault address used for execution context and subgraph queries. */
6
5
  vault: string;
7
6
  /** Chain ID used to resolve RPC configuration and on-chain reads. */
8
7
  chainId: number;
9
- /** Subgraph endpoint used for protocol data queries. */
10
- steerSubgraph: string;
11
- poolType: {
8
+ /** Required by execute() for protocol discovery queries. */
9
+ steerSubgraph?: string;
10
+ /** Required by execute() for pool discovery; unused by executeWithContext(). */
11
+ poolType?: {
12
12
  /** Set true when the pool uses Algebra v1 semantics. */
13
13
  isAlgebraPool: boolean;
14
14
  /** Set true when the pool uses Algebra Integral semantics. */
@@ -20,11 +20,11 @@ export interface ExecutionAppConfig {
20
20
  /** Set true when the pool uses Aerodrome semantics. */
21
21
  isAerodromePool: boolean;
22
22
  };
23
- apiKeys: {
24
- /** API key for The Graph Studio / gateway endpoints. */
25
- subgraphStudioKey: string;
23
+ apiKeys?: {
24
+ /** Host-only Graph credential; never added to WASM configuration. */
25
+ subgraphStudioKey?: string;
26
26
  /** API key for Sentio endpoints, if applicable. */
27
- sentioApiKey: string;
27
+ sentioApiKey?: string;
28
28
  };
29
29
  /** Maximum number of retries for execution operations. */
30
30
  maxRetries?: number;
@@ -38,22 +38,23 @@ export declare class ExecutionApp extends ExecutionBase {
38
38
  isDirectionalPool: boolean;
39
39
  isPoolSharkPool: boolean;
40
40
  isAerodromePool: boolean;
41
- subgraphStudioKey: string;
42
41
  sentioApiKey: string;
43
42
  config: ExecutionAppConfig;
44
43
  constructor(config: ExecutionAppConfig);
45
- execute<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig, forceDeposit?: boolean): Promise<Array<T>>;
44
+ execute<T = unknown>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, rpc?: RpcAccess, forceDeposit?: boolean): Promise<T | "continue">;
46
45
  /**
47
46
  * Executes a strategy against a supplied execution context.
48
47
  * This is the recommended API for new consumers. It intentionally bypasses
49
48
  * all legacy vault, pool, subgraph, clock, and block-estimation reads.
50
49
  */
51
- executeWithContext<T>(options: ExecuteWithContextOptions): Promise<Array<T>>;
50
+ executeWithContext<T = unknown>(options: ExecuteWithContextOptions): Promise<T | "continue">;
51
+ /** T is the complete decoded JSON result. Only the exact sentinel skips JSON decoding. */
52
+ private parseStrategyResult;
52
53
  private parseVaultConfig;
53
54
  private validateExecutionContext;
54
55
  private redactError;
55
- executeStabilityVault<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig, forceDeposit?: boolean): Promise<Array<T>>;
56
- executeDynamicJobs<T>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _job: JobDetails, _identity?: ethers.Provider, _etherRpcConfig?: EtherRpcConfig, forceDeposit?: boolean): Promise<Array<T>>;
56
+ executeStabilityVault<T = unknown>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, rpc?: RpcAccess, forceDeposit?: boolean): Promise<T | "continue">;
57
+ executeDynamicJobs<T = unknown>(_wasmFile: string | ArrayBuffer, _vaultConfig: string, _data: Array<any>, _job: JobDetails, rpc?: RpcAccess, forceDeposit?: boolean): Promise<T | "continue">;
57
58
  private getSmartPoolExecutionContext;
58
59
  private getPoolCurrentTick;
59
60
  private getTickSpacing;