@gearbox-protocol/sdk 12.6.0-next.3 → 12.6.0-next.4

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.
@@ -31,7 +31,9 @@ async function fetchPythPayloads(options) {
31
31
  ignoreMissingFeeds,
32
32
  historicalTimestampSeconds,
33
33
  logger,
34
- apiProxy
34
+ apiProxy,
35
+ customFetch = fetch,
36
+ returnPrices
35
37
  } = options;
36
38
  const ids = Array.from(new Set(dataFeedsIds));
37
39
  if (ids.length === 0) {
@@ -49,7 +51,7 @@ async function fetchPythPayloads(options) {
49
51
  }
50
52
  const resp = await (0, import_utils.retry)(
51
53
  async () => {
52
- const resp2 = await fetch(url.toString());
54
+ const resp2 = await customFetch(url.toString());
53
55
  if (!resp2.ok) {
54
56
  const body = await resp2.text();
55
57
  throw new Error(
@@ -61,7 +63,7 @@ async function fetchPythPayloads(options) {
61
63
  },
62
64
  { attempts: 3, exponent: 2, interval: 200 }
63
65
  );
64
- const result = respToCalldata(resp);
66
+ const result = respToCalldata(resp, returnPrices);
65
67
  if (result.length !== ids.length) {
66
68
  if (ignoreMissingFeeds) {
67
69
  logger?.warn(`expected ${ids.length} price feeds, got ${result.length}`);
@@ -73,13 +75,23 @@ async function fetchPythPayloads(options) {
73
75
  }
74
76
  return result;
75
77
  }
76
- function respToCalldata(resp) {
78
+ function respToCalldata(resp, returnPrices) {
77
79
  if (resp.binary.data.length === 0) {
78
80
  return [];
79
81
  }
80
82
  const updates = splitAccumulatorUpdates(resp.binary.data[0]);
83
+ const priceMap = /* @__PURE__ */ new Map();
84
+ if (returnPrices && resp.parsed) {
85
+ for (const feed of resp.parsed) {
86
+ const feedId = feed.id.startsWith("0x") ? feed.id : `0x${feed.id}`;
87
+ priceMap.set(feedId.toLowerCase(), {
88
+ price: BigInt(feed.price.price),
89
+ decimals: Math.abs(feed.price.expo)
90
+ });
91
+ }
92
+ }
81
93
  return updates.map(({ data, dataFeedId, timestamp }) => {
82
- return {
94
+ const base = {
83
95
  dataFeedId,
84
96
  data: (0, import_viem.encodeAbiParameters)(
85
97
  [{ type: "uint256" }, { type: "bytes[]" }],
@@ -88,6 +100,18 @@ function respToCalldata(resp) {
88
100
  timestamp,
89
101
  cached: false
90
102
  };
103
+ if (returnPrices) {
104
+ const priceInfo = priceMap.get(dataFeedId.toLowerCase());
105
+ if (!priceInfo) {
106
+ throw new Error(`Price info not found for feed ${dataFeedId}`);
107
+ }
108
+ return {
109
+ ...base,
110
+ price: priceInfo.price,
111
+ decimals: priceInfo.decimals
112
+ };
113
+ }
114
+ return base;
91
115
  });
92
116
  }
93
117
  function splitAccumulatorUpdates(binary) {
@@ -24,8 +24,9 @@ module.exports = __toCommonJS(fetchRedstonePayloads_exports);
24
24
  var import_evm_connector = require("@redstone-finance/evm-connector");
25
25
  var import_protocol = require("@redstone-finance/protocol");
26
26
  var import_sdk = require("@redstone-finance/sdk");
27
+ var import_utils = require("@redstone-finance/utils");
27
28
  var import_viem = require("viem");
28
- var import_utils = require("../../../utils/index.js");
29
+ var import_utils2 = require("../../../utils/index.js");
29
30
  async function fetchRedstonePayloads(options) {
30
31
  const {
31
32
  dataServiceId,
@@ -35,7 +36,8 @@ async function fetchRedstonePayloads(options) {
35
36
  gateways,
36
37
  ignoreMissingFeeds,
37
38
  enableLogging,
38
- logger
39
+ logger,
40
+ returnPrices
39
41
  } = options;
40
42
  const metadataTimestampMs = historicalTimestampMs ?? options.metadataTimestampMs;
41
43
  const dataPackagesIds = Array.from(new Set(dataFeedsIds));
@@ -57,7 +59,7 @@ async function fetchRedstonePayloads(options) {
57
59
  if (metadataTimestampMs) {
58
60
  wrapper.setMetadataTimestamp(metadataTimestampMs);
59
61
  }
60
- const dataPayload = await (0, import_utils.retry)(() => wrapper.prepareRedstonePayload(true), {
62
+ const dataPayload = await (0, import_utils2.retry)(() => wrapper.prepareRedstonePayload(true), {
61
63
  attempts: 5,
62
64
  interval: historicalTimestampMs ? 30500 : 250
63
65
  });
@@ -88,7 +90,8 @@ async function fetchRedstonePayloads(options) {
88
90
  getCalldataWithTimestamp(
89
91
  dataFeedId,
90
92
  signedDataPackages,
91
- wrapper.getUnsignedMetadata()
93
+ wrapper.getUnsignedMetadata(),
94
+ returnPrices
92
95
  )
93
96
  );
94
97
  }
@@ -113,7 +116,7 @@ function groupDataPackages(signedDataPackages) {
113
116
  }
114
117
  return packagesByDataFeedId;
115
118
  }
116
- function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
119
+ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata, returnPrices) {
117
120
  const originalPayload = import_protocol.RedstonePayload.prepare(packages, unsignedMetadata);
118
121
  const originalPayloadLength = originalPayload.length / 2;
119
122
  const bytesToAdd = 32 - originalPayloadLength % 32;
@@ -128,7 +131,7 @@ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
128
131
  throw new Error("Timestamps are not equal");
129
132
  }
130
133
  }
131
- return {
134
+ const base = {
132
135
  dataFeedId,
133
136
  data: (0, import_viem.encodeAbiParameters)(
134
137
  [{ type: "uint256" }, { type: "bytes" }],
@@ -137,6 +140,16 @@ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
137
140
  timestamp,
138
141
  cached: false
139
142
  };
143
+ if (returnPrices) {
144
+ const prices = packages.flatMap((p) => p.dataPackage.dataPoints).map((dp) => BigInt(`0x${Buffer.from(dp.value).toString("hex")}`));
145
+ const medianPrice = BigInt(import_utils.MathUtils.getMedianOfBigNumbers(prices));
146
+ return {
147
+ ...base,
148
+ price: medianPrice,
149
+ decimals: 8
150
+ };
151
+ }
152
+ return base;
140
153
  }
141
154
  // Annotate the CommonJS export names for ESM import in node:
142
155
  0 && (module.exports = {
@@ -12,7 +12,9 @@ async function fetchPythPayloads(options) {
12
12
  ignoreMissingFeeds,
13
13
  historicalTimestampSeconds,
14
14
  logger,
15
- apiProxy
15
+ apiProxy,
16
+ customFetch = fetch,
17
+ returnPrices
16
18
  } = options;
17
19
  const ids = Array.from(new Set(dataFeedsIds));
18
20
  if (ids.length === 0) {
@@ -30,7 +32,7 @@ async function fetchPythPayloads(options) {
30
32
  }
31
33
  const resp = await retry(
32
34
  async () => {
33
- const resp2 = await fetch(url.toString());
35
+ const resp2 = await customFetch(url.toString());
34
36
  if (!resp2.ok) {
35
37
  const body = await resp2.text();
36
38
  throw new Error(
@@ -42,7 +44,7 @@ async function fetchPythPayloads(options) {
42
44
  },
43
45
  { attempts: 3, exponent: 2, interval: 200 }
44
46
  );
45
- const result = respToCalldata(resp);
47
+ const result = respToCalldata(resp, returnPrices);
46
48
  if (result.length !== ids.length) {
47
49
  if (ignoreMissingFeeds) {
48
50
  logger?.warn(`expected ${ids.length} price feeds, got ${result.length}`);
@@ -54,13 +56,23 @@ async function fetchPythPayloads(options) {
54
56
  }
55
57
  return result;
56
58
  }
57
- function respToCalldata(resp) {
59
+ function respToCalldata(resp, returnPrices) {
58
60
  if (resp.binary.data.length === 0) {
59
61
  return [];
60
62
  }
61
63
  const updates = splitAccumulatorUpdates(resp.binary.data[0]);
64
+ const priceMap = /* @__PURE__ */ new Map();
65
+ if (returnPrices && resp.parsed) {
66
+ for (const feed of resp.parsed) {
67
+ const feedId = feed.id.startsWith("0x") ? feed.id : `0x${feed.id}`;
68
+ priceMap.set(feedId.toLowerCase(), {
69
+ price: BigInt(feed.price.price),
70
+ decimals: Math.abs(feed.price.expo)
71
+ });
72
+ }
73
+ }
62
74
  return updates.map(({ data, dataFeedId, timestamp }) => {
63
- return {
75
+ const base = {
64
76
  dataFeedId,
65
77
  data: encodeAbiParameters(
66
78
  [{ type: "uint256" }, { type: "bytes[]" }],
@@ -69,6 +81,18 @@ function respToCalldata(resp) {
69
81
  timestamp,
70
82
  cached: false
71
83
  };
84
+ if (returnPrices) {
85
+ const priceInfo = priceMap.get(dataFeedId.toLowerCase());
86
+ if (!priceInfo) {
87
+ throw new Error(`Price info not found for feed ${dataFeedId}`);
88
+ }
89
+ return {
90
+ ...base,
91
+ price: priceInfo.price,
92
+ decimals: priceInfo.decimals
93
+ };
94
+ }
95
+ return base;
72
96
  });
73
97
  }
74
98
  function splitAccumulatorUpdates(binary) {
@@ -5,6 +5,7 @@ import {
5
5
  import {
6
6
  getSignersForDataServiceId
7
7
  } from "@redstone-finance/sdk";
8
+ import { MathUtils } from "@redstone-finance/utils";
8
9
  import { encodeAbiParameters, toBytes } from "viem";
9
10
  import { retry } from "../../../utils/index.js";
10
11
  async function fetchRedstonePayloads(options) {
@@ -16,7 +17,8 @@ async function fetchRedstonePayloads(options) {
16
17
  gateways,
17
18
  ignoreMissingFeeds,
18
19
  enableLogging,
19
- logger
20
+ logger,
21
+ returnPrices
20
22
  } = options;
21
23
  const metadataTimestampMs = historicalTimestampMs ?? options.metadataTimestampMs;
22
24
  const dataPackagesIds = Array.from(new Set(dataFeedsIds));
@@ -69,7 +71,8 @@ async function fetchRedstonePayloads(options) {
69
71
  getCalldataWithTimestamp(
70
72
  dataFeedId,
71
73
  signedDataPackages,
72
- wrapper.getUnsignedMetadata()
74
+ wrapper.getUnsignedMetadata(),
75
+ returnPrices
73
76
  )
74
77
  );
75
78
  }
@@ -94,7 +97,7 @@ function groupDataPackages(signedDataPackages) {
94
97
  }
95
98
  return packagesByDataFeedId;
96
99
  }
97
- function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
100
+ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata, returnPrices) {
98
101
  const originalPayload = RedstonePayload.prepare(packages, unsignedMetadata);
99
102
  const originalPayloadLength = originalPayload.length / 2;
100
103
  const bytesToAdd = 32 - originalPayloadLength % 32;
@@ -109,7 +112,7 @@ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
109
112
  throw new Error("Timestamps are not equal");
110
113
  }
111
114
  }
112
- return {
115
+ const base = {
113
116
  dataFeedId,
114
117
  data: encodeAbiParameters(
115
118
  [{ type: "uint256" }, { type: "bytes" }],
@@ -118,6 +121,16 @@ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
118
121
  timestamp,
119
122
  cached: false
120
123
  };
124
+ if (returnPrices) {
125
+ const prices = packages.flatMap((p) => p.dataPackage.dataPoints).map((dp) => BigInt(`0x${Buffer.from(dp.value).toString("hex")}`));
126
+ const medianPrice = BigInt(MathUtils.getMedianOfBigNumbers(prices));
127
+ return {
128
+ ...base,
129
+ price: medianPrice,
130
+ decimals: 8
131
+ };
132
+ }
133
+ return base;
121
134
  }
122
135
  export {
123
136
  fetchRedstonePayloads
@@ -1,5 +1,5 @@
1
1
  import type { ILogger } from "../../../types/logger.js";
2
- import type { TimestampedCalldata } from "./types.js";
2
+ import type { TimestampedCalldata, TimestampedCalldataWithPrice } from "./types.js";
3
3
  export interface FetchPythPayloadsOptions {
4
4
  /**
5
5
  * Feeds to fetch
@@ -21,10 +21,25 @@ export interface FetchPythPayloadsOptions {
21
21
  * Logger to use
22
22
  */
23
23
  logger?: ILogger;
24
+ /**
25
+ * Custom fetch function to use instead of global fetch.
26
+ * Can be used to add custom headers, authentication, or use a different HTTP client.
27
+ */
28
+ customFetch?: typeof fetch;
29
+ /**
30
+ * When true, returns the price data for each feed.
31
+ */
32
+ returnPrices?: boolean;
24
33
  }
34
+ /**
35
+ * Fetches pyth payloads from Hermes API with price data
36
+ */
37
+ export declare function fetchPythPayloads(options: FetchPythPayloadsOptions & {
38
+ returnPrices: true;
39
+ }): Promise<TimestampedCalldataWithPrice[]>;
25
40
  /**
26
41
  * Fetches pyth payloads from Hermes API
27
- * @param dataFeedsIds
28
- * @returns
29
42
  */
30
- export declare function fetchPythPayloads(options: FetchPythPayloadsOptions): Promise<TimestampedCalldata[]>;
43
+ export declare function fetchPythPayloads(options: FetchPythPayloadsOptions & {
44
+ returnPrices?: false;
45
+ }): Promise<TimestampedCalldata[]>;
@@ -1,5 +1,5 @@
1
1
  import type { ILogger } from "../../../types/logger.js";
2
- import type { TimestampedCalldata } from "./types.js";
2
+ import type { TimestampedCalldata, TimestampedCalldataWithPrice } from "./types.js";
3
3
  export interface FetchRedstonePayloadsOptions {
4
4
  /**
5
5
  * Redstone data service id
@@ -40,5 +40,20 @@ export interface FetchRedstonePayloadsOptions {
40
40
  * Logger to use
41
41
  */
42
42
  logger?: ILogger;
43
+ /**
44
+ * When true, returns the price data for each feed.
45
+ */
46
+ returnPrices?: boolean;
43
47
  }
44
- export declare function fetchRedstonePayloads(options: FetchRedstonePayloadsOptions): Promise<TimestampedCalldata[]>;
48
+ /**
49
+ * Fetches redstone payloads with price data
50
+ */
51
+ export declare function fetchRedstonePayloads(options: FetchRedstonePayloadsOptions & {
52
+ returnPrices: true;
53
+ }): Promise<TimestampedCalldataWithPrice[]>;
54
+ /**
55
+ * Fetches redstone payloads
56
+ */
57
+ export declare function fetchRedstonePayloads(options: FetchRedstonePayloadsOptions & {
58
+ returnPrices?: false;
59
+ }): Promise<TimestampedCalldata[]>;
@@ -19,3 +19,7 @@ export interface TimestampedCalldata {
19
19
  timestamp: number;
20
20
  cached: boolean;
21
21
  }
22
+ export interface TimestampedCalldataWithPrice extends TimestampedCalldata {
23
+ price: bigint;
24
+ decimals: number;
25
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "12.6.0-next.3",
3
+ "version": "12.6.0-next.4",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "main": "./dist/cjs/sdk/index.js",
@@ -55,6 +55,7 @@
55
55
  "@redstone-finance/evm-connector": "^0.9.0",
56
56
  "@redstone-finance/protocol": "^0.9.0",
57
57
  "@redstone-finance/sdk": "^0.9.0",
58
+ "@redstone-finance/utils": "^0.9.0",
58
59
  "@types/bn.js": "^5.2.0",
59
60
  "abitype": "^1.2.3",
60
61
  "bn.js": "^5.2.2",