@gearbox-protocol/sdk 12.4.0 → 12.6.0-next.1

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 (26) hide show
  1. package/dist/cjs/sdk/core/address-provider/AbstractAddressProviderContract.js +20 -3
  2. package/dist/cjs/sdk/core/address-provider/AddressProviderV300Contract.js +1 -1
  3. package/dist/cjs/sdk/core/address-provider/AddressProviderV310Contract.js +1 -1
  4. package/dist/cjs/sdk/core/address-provider/createAddressProvider.js +18 -2
  5. package/dist/cjs/sdk/market/pricefeeds/updates/PythUpdater.js +16 -74
  6. package/dist/cjs/sdk/market/pricefeeds/updates/RedstoneUpdater.js +9 -96
  7. package/dist/cjs/sdk/market/pricefeeds/updates/fetchPythPayloads.js +111 -0
  8. package/dist/cjs/sdk/market/pricefeeds/updates/fetchRedstonePayloads.js +144 -0
  9. package/dist/cjs/sdk/market/pricefeeds/updates/index.js +6 -1
  10. package/dist/esm/sdk/core/address-provider/AbstractAddressProviderContract.js +20 -3
  11. package/dist/esm/sdk/core/address-provider/AddressProviderV300Contract.js +1 -1
  12. package/dist/esm/sdk/core/address-provider/AddressProviderV310Contract.js +1 -1
  13. package/dist/esm/sdk/core/address-provider/createAddressProvider.js +20 -2
  14. package/dist/esm/sdk/market/pricefeeds/updates/PythUpdater.js +16 -78
  15. package/dist/esm/sdk/market/pricefeeds/updates/RedstoneUpdater.js +10 -99
  16. package/dist/esm/sdk/market/pricefeeds/updates/fetchPythPayloads.js +91 -0
  17. package/dist/esm/sdk/market/pricefeeds/updates/fetchRedstonePayloads.js +124 -0
  18. package/dist/esm/sdk/market/pricefeeds/updates/index.js +2 -0
  19. package/dist/types/sdk/core/address-provider/AbstractAddressProviderContract.d.ts +2 -2
  20. package/dist/types/sdk/core/address-provider/AddressProviderV300Contract.d.ts +2 -2
  21. package/dist/types/sdk/core/address-provider/AddressProviderV310Contract.d.ts +2 -2
  22. package/dist/types/sdk/core/address-provider/types.d.ts +15 -0
  23. package/dist/types/sdk/market/pricefeeds/updates/fetchPythPayloads.d.ts +30 -0
  24. package/dist/types/sdk/market/pricefeeds/updates/fetchRedstonePayloads.d.ts +44 -0
  25. package/dist/types/sdk/market/pricefeeds/updates/index.d.ts +2 -0
  26. package/package.json +1 -1
@@ -3,7 +3,7 @@ import { iAddressProviderV310Abi } from "../../../abi/310/generated.js";
3
3
  import AbstractAddressProviderContract from "./AbstractAddressProviderContract.js";
4
4
  const abi = iAddressProviderV310Abi;
5
5
  class AddressProviderV310Contract extends AbstractAddressProviderContract {
6
- constructor(options, address, version = 310, addresses = {}) {
6
+ constructor(options, address, version = 310, addresses) {
7
7
  super(
8
8
  options,
9
9
  {
@@ -1,12 +1,26 @@
1
1
  import { iVersionAbi } from "../../../abi/iVersion.js";
2
2
  import {
3
3
  ADDRESS_PROVIDER_V310,
4
+ AP_MARKET_COMPRESSOR,
5
+ AP_PRICE_FEED_COMPRESSOR,
4
6
  isV300,
5
7
  isV310
6
8
  } from "../../constants/index.js";
7
9
  import { hexEq } from "../../utils/hex.js";
8
10
  import { AddressProviderV300Contract } from "./AddressProviderV300Contract.js";
9
11
  import { AddressProviderV310Contract } from "./AddressProviderV310Contract.js";
12
+ const OVERRIDE_ADDRESSES = {
13
+ // Override price feed compressor and market feed compressor
14
+ // we urgently deployed fix and it has not been added to the address provider yet
15
+ Mainnet: {
16
+ [AP_PRICE_FEED_COMPRESSOR]: {
17
+ 311: "0x1fA2637B9fab0CD14290A7EE908DDc9688a15120"
18
+ },
19
+ [AP_MARKET_COMPRESSOR]: {
20
+ 311: "0x0C27F242f6e9F2A9AD3261bE6e439De3B948bcA2"
21
+ }
22
+ }
23
+ };
10
24
  async function createAddressProvider(sdk, address) {
11
25
  let v;
12
26
  if (hexEq(address, ADDRESS_PROVIDER_V310)) {
@@ -25,11 +39,15 @@ function hydrateAddressProvider(sdk, state) {
25
39
  return newAddressProvider(sdk, addr, Number(version), state.addresses);
26
40
  }
27
41
  function newAddressProvider(sdk, address, version, addresses) {
42
+ const addrOptions = {
43
+ addresses,
44
+ overrides: OVERRIDE_ADDRESSES[sdk.networkType]
45
+ };
28
46
  if (isV300(version)) {
29
- return new AddressProviderV300Contract(sdk, address, version, addresses);
47
+ return new AddressProviderV300Contract(sdk, address, version, addrOptions);
30
48
  }
31
49
  if (isV310(version)) {
32
- return new AddressProviderV310Contract(sdk, address, version, addresses);
50
+ return new AddressProviderV310Contract(sdk, address, version, addrOptions);
33
51
  }
34
52
  throw new Error(`unsupported address provider version: ${version}`);
35
53
  }
@@ -1,15 +1,8 @@
1
- import { Buffer } from "buffer";
2
- import { encodeAbiParameters, toHex } from "viem";
3
1
  import { z } from "zod/v4";
4
2
  import { SDKConstruct } from "../../../base/index.js";
5
- import { retry } from "../../../utils/index.js";
3
+ import { fetchPythPayloads } from "./fetchPythPayloads.js";
6
4
  import { PriceUpdatesCache } from "./PriceUpdatesCache.js";
7
5
  import { PriceUpdateTx } from "./PriceUpdateTx.js";
8
- import {
9
- parseAccumulatorUpdateData,
10
- parsePriceFeedMessage,
11
- sliceAccumulatorUpdateData
12
- } from "./PythAccumulatorUpdateData.js";
13
6
  class PythUpdateTx extends PriceUpdateTx {
14
7
  name = "pyth";
15
8
  }
@@ -38,16 +31,15 @@ const PythOptions = z.object({
38
31
  class PythUpdater extends SDKConstruct {
39
32
  #cache;
40
33
  #historicalTimestamp;
41
- #api;
34
+ #apiProxy;
42
35
  #ignoreMissingFeeds;
43
36
  constructor(sdk, opts = {}) {
44
37
  super(sdk);
45
- this.#ignoreMissingFeeds = opts.ignoreMissingFeeds;
46
- this.#api = opts.apiProxy ?? "https://hermes.pyth.network/v2/updates/price/";
47
- this.#api = this.#api.endsWith("/") ? this.#api : `${this.#api}/`;
48
- const ts = opts.historicTimestamp;
49
- if (ts) {
50
- this.#historicalTimestamp = ts === true ? Number(this.sdk.timestamp) : ts;
38
+ const { apiProxy, cacheTTL, ignoreMissingFeeds, historicTimestamp } = opts;
39
+ this.#ignoreMissingFeeds = ignoreMissingFeeds;
40
+ this.#apiProxy = apiProxy;
41
+ if (historicTimestamp) {
42
+ this.#historicalTimestamp = historicTimestamp === true ? Number(this.sdk.timestamp) : historicTimestamp;
51
43
  this.logger?.debug(
52
44
  `using historical timestamp ${this.#historicalTimestamp}`
53
45
  );
@@ -56,8 +48,8 @@ class PythUpdater extends SDKConstruct {
56
48
  // currently staleness period is 240 seconds on all networks, add some buffer
57
49
  // this period of 4 minutes is selected based on time that is required for user to sign transaction with wallet
58
50
  // so it's unlikely to decrease
59
- ttl: opts.cacheTTL ?? 225 * 1e3,
60
- historical: !!ts
51
+ ttl: cacheTTL ?? 225 * 1e3,
52
+ historical: !!historicTimestamp
61
53
  });
62
54
  }
63
55
  async getUpdateTxs(feeds) {
@@ -148,72 +140,18 @@ class PythUpdater extends SDKConstruct {
148
140
  this.logger?.debug(
149
141
  `fetching pyth payloads for ${dataFeedsIds.size} price feeds: ${ids.join(", ")}${tsStr}`
150
142
  );
151
- const url = new URL(this.#api + (this.#historicalTimestamp ?? "latest"));
152
- url.searchParams.append("parsed", "false");
153
- if (this.#ignoreMissingFeeds) {
154
- url.searchParams.append("ignore_invalid_price_ids", "true");
155
- }
156
- for (const id of dataFeedsIds) {
157
- url.searchParams.append("ids[]", id);
158
- }
159
- const resp = await retry(
160
- async () => {
161
- const resp2 = await fetch(url.toString());
162
- if (!resp2.ok) {
163
- const body = await resp2.text();
164
- throw new Error(
165
- `failed to fetch pyth payloads: ${resp2.statusText}: ${body}`
166
- );
167
- }
168
- const data = await resp2.json();
169
- return data;
170
- },
171
- { attempts: 3, exponent: 2, interval: 200 }
172
- );
173
- const result = respToCalldata(resp);
174
- if (!this.#ignoreMissingFeeds && result.length !== dataFeedsIds.size) {
175
- throw new Error(
176
- `expected ${dataFeedsIds.size} price feeds, got ${result.length}`
177
- );
178
- }
179
- return result;
143
+ return fetchPythPayloads({
144
+ dataFeedsIds,
145
+ historicalTimestampSeconds: this.#historicalTimestamp,
146
+ apiProxy: this.#apiProxy,
147
+ ignoreMissingFeeds: this.#ignoreMissingFeeds,
148
+ logger: this.logger
149
+ });
180
150
  }
181
151
  }
182
152
  function isPyth(pf) {
183
153
  return pf.contractType === "PRICE_FEED::PYTH";
184
154
  }
185
- function respToCalldata(resp) {
186
- if (resp.binary.data.length === 0) {
187
- return [];
188
- }
189
- const updates = splitAccumulatorUpdates(resp.binary.data[0]);
190
- return updates.map(({ data, dataFeedId, timestamp }) => {
191
- return {
192
- dataFeedId,
193
- data: encodeAbiParameters(
194
- [{ type: "uint256" }, { type: "bytes[]" }],
195
- [BigInt(timestamp), [data]]
196
- ),
197
- timestamp,
198
- cached: false
199
- };
200
- });
201
- }
202
- function splitAccumulatorUpdates(binary) {
203
- const data = Buffer.from(binary, "hex");
204
- const parsed = parseAccumulatorUpdateData(data);
205
- const results = [];
206
- for (let i = 0; i < parsed.updates.length; i++) {
207
- const upd = parsed.updates[i].message;
208
- const msg = parsePriceFeedMessage(upd);
209
- results.push({
210
- dataFeedId: toHex(msg.feedId),
211
- timestamp: msg.publishTime.toNumber(),
212
- data: toHex(sliceAccumulatorUpdateData(data, i, i + 1))
213
- });
214
- }
215
- return results;
216
- }
217
155
  export {
218
156
  PythOptions,
219
157
  PythUpdater
@@ -1,12 +1,7 @@
1
- import { DataServiceWrapper } from "@redstone-finance/evm-connector";
2
- import { RedstonePayload } from "@redstone-finance/protocol";
3
- import {
4
- getSignersForDataServiceId
5
- } from "@redstone-finance/sdk";
6
- import { encodeAbiParameters, toBytes } from "viem";
7
1
  import { z } from "zod/v4";
8
2
  import { SDKConstruct } from "../../../base/index.js";
9
- import { AddressMap, retry } from "../../../utils/index.js";
3
+ import { AddressMap } from "../../../utils/index.js";
4
+ import { fetchRedstonePayloads } from "./fetchRedstonePayloads.js";
10
5
  import { PriceUpdatesCache } from "./PriceUpdatesCache.js";
11
6
  import { PriceUpdateTx } from "./PriceUpdateTx.js";
12
7
  class RedstoneUpdateTx extends PriceUpdateTx {
@@ -222,102 +217,18 @@ class RedstoneUpdater extends SDKConstruct {
222
217
  this.logger?.debug(
223
218
  `fetching redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${dataPackagesIds.join(", ")}${tsStr}`
224
219
  );
225
- const wrapper = new DataServiceWrapper({
220
+ return fetchRedstonePayloads({
226
221
  dataServiceId,
227
- dataPackagesIds,
222
+ dataFeedsIds,
228
223
  uniqueSignersCount,
229
- authorizedSigners: getSignersForDataServiceId(
230
- dataServiceId
231
- ),
232
- historicalTimestamp: this.#historicalTimestampMs,
233
- urls: this.#gateways,
234
- ignoreMissingFeed: this.#ignoreMissingFeeds,
235
- enableEnhancedLogs: this.#enableLogging
224
+ historicalTimestampMs: this.#historicalTimestampMs,
225
+ gateways: this.#gateways,
226
+ ignoreMissingFeeds: this.#ignoreMissingFeeds,
227
+ enableLogging: this.#enableLogging,
228
+ logger: this.logger,
229
+ metadataTimestampMs: Number(this.sdk.timestamp) * 1e3
236
230
  });
237
- wrapper.setMetadataTimestamp(
238
- this.#historicalTimestampMs ?? Number(this.sdk.timestamp) * 1e3
239
- );
240
- const dataPayload = await retry(
241
- () => wrapper.prepareRedstonePayload(true),
242
- { attempts: 5, interval: this.#historicalTimestampMs ? 30500 : 250 }
243
- );
244
- const parsed = RedstonePayload.parse(toBytes(`0x${dataPayload}`));
245
- const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
246
- const result = [];
247
- for (const dataFeedId of dataFeedsIds) {
248
- const signedDataPackages = packagesByDataFeedId[dataFeedId];
249
- if (!signedDataPackages) {
250
- if (this.#ignoreMissingFeeds) {
251
- this.logger?.warn(`cannot find data packages for ${dataFeedId}`);
252
- continue;
253
- }
254
- throw new Error(`cannot find data packages for ${dataFeedId}`);
255
- }
256
- if (signedDataPackages.length !== uniqueSignersCount) {
257
- if (this.#ignoreMissingFeeds) {
258
- this.logger?.warn(
259
- `got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
260
- );
261
- continue;
262
- }
263
- throw new Error(
264
- `got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
265
- );
266
- }
267
- result.push(
268
- getCalldataWithTimestamp(
269
- dataFeedId,
270
- signedDataPackages,
271
- wrapper.getUnsignedMetadata()
272
- )
273
- );
274
- }
275
- return result;
276
- }
277
- }
278
- function groupDataPackages(signedDataPackages) {
279
- const packagesByDataFeedId = {};
280
- for (const p of signedDataPackages) {
281
- const { dataPoints } = p.dataPackage;
282
- const dataFeedId0 = dataPoints[0].dataFeedId;
283
- for (const dp of dataPoints) {
284
- if (dp.dataFeedId !== dataFeedId0) {
285
- throw new Error(
286
- `data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`
287
- );
288
- }
289
- }
290
- if (!packagesByDataFeedId[dataFeedId0]) {
291
- packagesByDataFeedId[dataFeedId0] = [];
292
- }
293
- packagesByDataFeedId[dataFeedId0].push(p);
294
- }
295
- return packagesByDataFeedId;
296
- }
297
- function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
298
- const originalPayload = RedstonePayload.prepare(packages, unsignedMetadata);
299
- const originalPayloadLength = originalPayload.length / 2;
300
- const bytesToAdd = 32 - originalPayloadLength % 32;
301
- const newUnsignedMetadata = unsignedMetadata + "_".repeat(bytesToAdd);
302
- const payload = RedstonePayload.prepare(packages, newUnsignedMetadata);
303
- let timestamp = 0;
304
- for (const p of packages) {
305
- const newTimestamp = p.dataPackage.timestampMilliseconds / 1e3;
306
- if (timestamp === 0) {
307
- timestamp = newTimestamp;
308
- } else if (timestamp !== newTimestamp) {
309
- throw new Error("Timestamps are not equal");
310
- }
311
231
  }
312
- return {
313
- dataFeedId,
314
- data: encodeAbiParameters(
315
- [{ type: "uint256" }, { type: "bytes" }],
316
- [BigInt(timestamp), `0x${payload}`]
317
- ),
318
- timestamp,
319
- cached: false
320
- };
321
232
  }
322
233
  function isRedstone(pf) {
323
234
  return pf.contractType === "PRICE_FEED::REDSTONE";
@@ -0,0 +1,91 @@
1
+ import { Buffer } from "buffer";
2
+ import { encodeAbiParameters, toHex } from "viem";
3
+ import { retry } from "../../../utils/index.js";
4
+ import {
5
+ parseAccumulatorUpdateData,
6
+ parsePriceFeedMessage,
7
+ sliceAccumulatorUpdateData
8
+ } from "./PythAccumulatorUpdateData.js";
9
+ async function fetchPythPayloads(options) {
10
+ const {
11
+ dataFeedsIds,
12
+ ignoreMissingFeeds,
13
+ historicalTimestampSeconds,
14
+ logger,
15
+ apiProxy
16
+ } = options;
17
+ const ids = Array.from(new Set(dataFeedsIds));
18
+ if (ids.length === 0) {
19
+ return [];
20
+ }
21
+ let api = apiProxy ?? "https://hermes.pyth.network/v2/updates/price/";
22
+ api = api.endsWith("/") ? api : `${api}/`;
23
+ const url = new URL(api + (historicalTimestampSeconds ?? "latest"));
24
+ url.searchParams.append("parsed", "false");
25
+ if (ignoreMissingFeeds) {
26
+ url.searchParams.append("ignore_invalid_price_ids", "true");
27
+ }
28
+ for (const id of dataFeedsIds) {
29
+ url.searchParams.append("ids[]", id);
30
+ }
31
+ const resp = await retry(
32
+ async () => {
33
+ const resp2 = await fetch(url.toString());
34
+ if (!resp2.ok) {
35
+ const body = await resp2.text();
36
+ throw new Error(
37
+ `failed to fetch pyth payloads: ${resp2.statusText}: ${body}`
38
+ );
39
+ }
40
+ const data = await resp2.json();
41
+ return data;
42
+ },
43
+ { attempts: 3, exponent: 2, interval: 200 }
44
+ );
45
+ const result = respToCalldata(resp);
46
+ if (result.length !== ids.length) {
47
+ if (ignoreMissingFeeds) {
48
+ logger?.warn(`expected ${ids.length} price feeds, got ${result.length}`);
49
+ } else {
50
+ throw new Error(
51
+ `expected ${ids.length} price feeds, got ${result.length}`
52
+ );
53
+ }
54
+ }
55
+ return result;
56
+ }
57
+ function respToCalldata(resp) {
58
+ if (resp.binary.data.length === 0) {
59
+ return [];
60
+ }
61
+ const updates = splitAccumulatorUpdates(resp.binary.data[0]);
62
+ return updates.map(({ data, dataFeedId, timestamp }) => {
63
+ return {
64
+ dataFeedId,
65
+ data: encodeAbiParameters(
66
+ [{ type: "uint256" }, { type: "bytes[]" }],
67
+ [BigInt(timestamp), [data]]
68
+ ),
69
+ timestamp,
70
+ cached: false
71
+ };
72
+ });
73
+ }
74
+ function splitAccumulatorUpdates(binary) {
75
+ const data = Buffer.from(binary, "hex");
76
+ const parsed = parseAccumulatorUpdateData(data);
77
+ const results = [];
78
+ for (let i = 0; i < parsed.updates.length; i++) {
79
+ const upd = parsed.updates[i].message;
80
+ const msg = parsePriceFeedMessage(upd);
81
+ results.push({
82
+ dataFeedId: toHex(msg.feedId),
83
+ timestamp: msg.publishTime.toNumber(),
84
+ data: toHex(sliceAccumulatorUpdateData(data, i, i + 1))
85
+ });
86
+ }
87
+ return results;
88
+ }
89
+ export {
90
+ fetchPythPayloads
91
+ };
@@ -0,0 +1,124 @@
1
+ import { DataServiceWrapper } from "@redstone-finance/evm-connector";
2
+ import {
3
+ RedstonePayload
4
+ } from "@redstone-finance/protocol";
5
+ import {
6
+ getSignersForDataServiceId
7
+ } from "@redstone-finance/sdk";
8
+ import { encodeAbiParameters, toBytes } from "viem";
9
+ import { retry } from "../../../utils/index.js";
10
+ async function fetchRedstonePayloads(options) {
11
+ const {
12
+ dataServiceId,
13
+ dataFeedsIds,
14
+ uniqueSignersCount,
15
+ historicalTimestampMs,
16
+ gateways,
17
+ ignoreMissingFeeds,
18
+ enableLogging,
19
+ logger
20
+ } = options;
21
+ const metadataTimestampMs = historicalTimestampMs ?? options.metadataTimestampMs;
22
+ const dataPackagesIds = Array.from(new Set(dataFeedsIds));
23
+ if (dataPackagesIds.length === 0) {
24
+ return [];
25
+ }
26
+ const wrapper = new DataServiceWrapper({
27
+ dataServiceId,
28
+ dataPackagesIds,
29
+ uniqueSignersCount,
30
+ authorizedSigners: getSignersForDataServiceId(
31
+ dataServiceId
32
+ ),
33
+ historicalTimestamp: historicalTimestampMs,
34
+ urls: gateways,
35
+ ignoreMissingFeed: ignoreMissingFeeds,
36
+ enableEnhancedLogs: enableLogging
37
+ });
38
+ if (metadataTimestampMs) {
39
+ wrapper.setMetadataTimestamp(metadataTimestampMs);
40
+ }
41
+ const dataPayload = await retry(() => wrapper.prepareRedstonePayload(true), {
42
+ attempts: 5,
43
+ interval: historicalTimestampMs ? 30500 : 250
44
+ });
45
+ const parsed = RedstonePayload.parse(toBytes(`0x${dataPayload}`));
46
+ const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
47
+ const result = [];
48
+ for (const dataFeedId of dataFeedsIds) {
49
+ const signedDataPackages = packagesByDataFeedId[dataFeedId];
50
+ if (!signedDataPackages) {
51
+ if (ignoreMissingFeeds) {
52
+ logger?.warn(`cannot find data packages for ${dataFeedId}`);
53
+ continue;
54
+ }
55
+ throw new Error(`cannot find data packages for ${dataFeedId}`);
56
+ }
57
+ if (signedDataPackages.length !== uniqueSignersCount) {
58
+ if (ignoreMissingFeeds) {
59
+ logger?.warn(
60
+ `got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
61
+ );
62
+ continue;
63
+ }
64
+ throw new Error(
65
+ `got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
66
+ );
67
+ }
68
+ result.push(
69
+ getCalldataWithTimestamp(
70
+ dataFeedId,
71
+ signedDataPackages,
72
+ wrapper.getUnsignedMetadata()
73
+ )
74
+ );
75
+ }
76
+ return result;
77
+ }
78
+ function groupDataPackages(signedDataPackages) {
79
+ const packagesByDataFeedId = {};
80
+ for (const p of signedDataPackages) {
81
+ const { dataPoints } = p.dataPackage;
82
+ const dataFeedId0 = dataPoints[0].dataFeedId;
83
+ for (const dp of dataPoints) {
84
+ if (dp.dataFeedId !== dataFeedId0) {
85
+ throw new Error(
86
+ `data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`
87
+ );
88
+ }
89
+ }
90
+ if (!packagesByDataFeedId[dataFeedId0]) {
91
+ packagesByDataFeedId[dataFeedId0] = [];
92
+ }
93
+ packagesByDataFeedId[dataFeedId0].push(p);
94
+ }
95
+ return packagesByDataFeedId;
96
+ }
97
+ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
98
+ const originalPayload = RedstonePayload.prepare(packages, unsignedMetadata);
99
+ const originalPayloadLength = originalPayload.length / 2;
100
+ const bytesToAdd = 32 - originalPayloadLength % 32;
101
+ const newUnsignedMetadata = unsignedMetadata + "_".repeat(bytesToAdd);
102
+ const payload = RedstonePayload.prepare(packages, newUnsignedMetadata);
103
+ let timestamp = 0;
104
+ for (const p of packages) {
105
+ const newTimestamp = p.dataPackage.timestampMilliseconds / 1e3;
106
+ if (timestamp === 0) {
107
+ timestamp = newTimestamp;
108
+ } else if (timestamp !== newTimestamp) {
109
+ throw new Error("Timestamps are not equal");
110
+ }
111
+ }
112
+ return {
113
+ dataFeedId,
114
+ data: encodeAbiParameters(
115
+ [{ type: "uint256" }, { type: "bytes" }],
116
+ [BigInt(timestamp), `0x${payload}`]
117
+ ),
118
+ timestamp,
119
+ cached: false
120
+ };
121
+ }
122
+ export {
123
+ fetchRedstonePayloads
124
+ };
@@ -1,3 +1,5 @@
1
+ export * from "./fetchPythPayloads.js";
2
+ export * from "./fetchRedstonePayloads.js";
1
3
  import { PythOptions, PythUpdater } from "./PythUpdater.js";
2
4
  import { RedstoneOptions, RedstoneUpdater } from "./RedstoneUpdater.js";
3
5
  export {
@@ -3,10 +3,10 @@ import type { BaseContractArgs } from "../../base/BaseContract.js";
3
3
  import { BaseContract, type ConstructOptions } from "../../base/index.js";
4
4
  import type { VersionRange } from "../../constants/index.js";
5
5
  import type { AddressProviderV3StateHuman } from "../../types/index.js";
6
- import type { AddressProviderState } from "./types.js";
6
+ import type { AddressProviderAddresses, AddressProviderState } from "./types.js";
7
7
  export default abstract class AbstractAddressProviderContract<abi extends Abi | readonly unknown[]> extends BaseContract<abi> {
8
8
  #private;
9
- constructor(options: ConstructOptions, args: BaseContractArgs<abi>, addresses?: Record<string, Record<number, Address>>);
9
+ constructor(options: ConstructOptions, args: BaseContractArgs<abi>, addresses?: AddressProviderAddresses);
10
10
  protected setInternalAddress(key: string, address: Address, version: number): void;
11
11
  getAddress(contract: string, version?: number): Address;
12
12
  getLatest(contract: string, range: VersionRange): [address: Address, version: number] | undefined;
@@ -1,7 +1,7 @@
1
1
  import type { Address, ContractEventName, DecodeFunctionDataReturnType, Log } from "viem";
2
2
  import type { ConstructOptions } from "../../base/Construct.js";
3
3
  import AbstractAddressProviderContract from "./AbstractAddressProviderContract.js";
4
- import type { IAddressProviderContract } from "./types.js";
4
+ import type { AddressProviderAddresses, IAddressProviderContract } from "./types.js";
5
5
  declare const abi: readonly [{
6
6
  readonly type: "function";
7
7
  readonly name: "addresses";
@@ -89,7 +89,7 @@ declare const abi: readonly [{
89
89
  }];
90
90
  type abi = typeof abi;
91
91
  export declare class AddressProviderV300Contract extends AbstractAddressProviderContract<abi> implements IAddressProviderContract {
92
- constructor(options: ConstructOptions, address: Address, version: number, addresses?: Record<string, Record<number, Address>>);
92
+ constructor(options: ConstructOptions, address: Address, version: number, addresses?: AddressProviderAddresses);
93
93
  protected stringifyFunctionParams(params: DecodeFunctionDataReturnType<abi>): string[];
94
94
  processLog(log: Log<bigint, number, false, undefined, undefined, abi, ContractEventName<abi>>): void;
95
95
  syncState(blockNumber?: bigint): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import type { Address, ContractEventName, DecodeFunctionDataReturnType, Log } from "viem";
2
2
  import type { ConstructOptions } from "../../base/Construct.js";
3
3
  import AbstractAddressProviderContract from "./AbstractAddressProviderContract.js";
4
- import type { IAddressProviderContract } from "./types.js";
4
+ import type { AddressProviderAddresses, IAddressProviderContract } from "./types.js";
5
5
  declare const abi: readonly [{
6
6
  readonly type: "function";
7
7
  readonly inputs: readonly [];
@@ -254,7 +254,7 @@ declare const abi: readonly [{
254
254
  }];
255
255
  type abi = typeof abi;
256
256
  export declare class AddressProviderV310Contract extends AbstractAddressProviderContract<abi> implements IAddressProviderContract {
257
- constructor(options: ConstructOptions, address: Address, version?: number, addresses?: Record<string, Record<number, Address>>);
257
+ constructor(options: ConstructOptions, address: Address, version?: number, addresses?: AddressProviderAddresses);
258
258
  protected stringifyFunctionParams(params: DecodeFunctionDataReturnType<abi>): string[];
259
259
  processLog(log: Log<bigint, number, false, undefined, undefined, abi, ContractEventName<abi>>): void;
260
260
  syncState(blockNumber?: bigint): Promise<void>;
@@ -2,6 +2,21 @@ import type { Address } from "viem";
2
2
  import type { BaseParams, IBaseContract } from "../../base/index.js";
3
3
  import type { VersionRange } from "../../constants/versions.js";
4
4
  import type { AddressProviderV3StateHuman } from "../../types/index.js";
5
+ export interface AddressProviderAddresses {
6
+ /**
7
+ * Initialize address provider with these addresses
8
+ * Used in hydration
9
+ */
10
+ addresses?: Record<string, Record<number, Address>>;
11
+ /**
12
+ * Override addresses for this address provider
13
+ * These addresses will precede over addresses loaded from chain
14
+ *
15
+ * This is an escape hatch.
16
+ * We used it when we need to fix price feed compressor/market compressor urgently
17
+ */
18
+ overrides?: Record<string, Record<number, Address>>;
19
+ }
5
20
  export interface AddressProviderState {
6
21
  baseParams: BaseParams;
7
22
  addresses: Record<string, Record<number, Address>>;
@@ -0,0 +1,30 @@
1
+ import type { ILogger } from "../../../types/logger.js";
2
+ import type { TimestampedCalldata } from "./types.js";
3
+ export interface FetchPythPayloadsOptions {
4
+ /**
5
+ * Feeds to fetch
6
+ */
7
+ dataFeedsIds: Iterable<string>;
8
+ /**
9
+ * When true, will not throw an error if pyth is unable to fetch data for some feeds
10
+ */
11
+ ignoreMissingFeeds?: boolean;
12
+ /**
13
+ * Historical timestamp in seconds
14
+ */
15
+ historicalTimestampSeconds?: number;
16
+ /**
17
+ * Override Hermes API with this proxy. Can be used to set caching proxies, to avoid rate limiting
18
+ */
19
+ apiProxy?: string;
20
+ /**
21
+ * Logger to use
22
+ */
23
+ logger?: ILogger;
24
+ }
25
+ /**
26
+ * Fetches pyth payloads from Hermes API
27
+ * @param dataFeedsIds
28
+ * @returns
29
+ */
30
+ export declare function fetchPythPayloads(options: FetchPythPayloadsOptions): Promise<TimestampedCalldata[]>;