@gearbox-protocol/sdk 12.9.8 → 12.10.0

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 (31) hide show
  1. package/dist/cjs/permissionless/utils/price-update/get-prices.js +0 -3
  2. package/dist/cjs/permissionless/utils/price-update/get-updatable-feeds.js +2 -9
  3. package/dist/cjs/sdk/GearboxSDK.js +7 -17
  4. package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +1 -4
  5. package/dist/cjs/sdk/market/pricefeeds/PythPriceFeed.js +3 -27
  6. package/dist/cjs/sdk/market/pricefeeds/index.js +0 -2
  7. package/dist/cjs/sdk/market/pricefeeds/updates/index.js +0 -7
  8. package/dist/cjs/sdk/options.js +0 -4
  9. package/dist/esm/permissionless/utils/price-update/get-prices.js +0 -3
  10. package/dist/esm/permissionless/utils/price-update/get-updatable-feeds.js +2 -10
  11. package/dist/esm/sdk/GearboxSDK.js +7 -17
  12. package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +2 -5
  13. package/dist/esm/sdk/market/pricefeeds/PythPriceFeed.js +4 -28
  14. package/dist/esm/sdk/market/pricefeeds/index.js +0 -2
  15. package/dist/esm/sdk/market/pricefeeds/updates/index.js +0 -4
  16. package/dist/esm/sdk/options.js +1 -8
  17. package/dist/types/sdk/market/pricefeeds/PriceFeedsRegister.d.ts +1 -2
  18. package/dist/types/sdk/market/pricefeeds/PythPriceFeed.d.ts +2 -25
  19. package/dist/types/sdk/market/pricefeeds/index.d.ts +1 -1
  20. package/dist/types/sdk/market/pricefeeds/updates/index.d.ts +0 -2
  21. package/dist/types/sdk/options.d.ts +0 -6
  22. package/package.json +5 -2
  23. package/dist/cjs/sdk/market/pricefeeds/updates/PythAccumulatorUpdateData.js +0 -195
  24. package/dist/cjs/sdk/market/pricefeeds/updates/PythUpdater.js +0 -183
  25. package/dist/cjs/sdk/market/pricefeeds/updates/fetchPythPayloads.js +0 -135
  26. package/dist/esm/sdk/market/pricefeeds/updates/PythAccumulatorUpdateData.js +0 -157
  27. package/dist/esm/sdk/market/pricefeeds/updates/PythUpdater.js +0 -158
  28. package/dist/esm/sdk/market/pricefeeds/updates/fetchPythPayloads.js +0 -115
  29. package/dist/types/sdk/market/pricefeeds/updates/PythAccumulatorUpdateData.d.ts +0 -41
  30. package/dist/types/sdk/market/pricefeeds/updates/PythUpdater.d.ts +0 -26
  31. package/dist/types/sdk/market/pricefeeds/updates/fetchPythPayloads.d.ts +0 -45
@@ -1,158 +0,0 @@
1
- import { z } from "zod/v4";
2
- import { SDKConstruct } from "../../../base/index.js";
3
- import { fetchPythPayloads } from "./fetchPythPayloads.js";
4
- import { PriceUpdatesCache } from "./PriceUpdatesCache.js";
5
- import { PriceUpdateTx } from "./PriceUpdateTx.js";
6
- class PythUpdateTx extends PriceUpdateTx {
7
- name = "pyth";
8
- }
9
- const PythOptions = z.object({
10
- /**
11
- * Fixed pyth historic timestamp in seconds
12
- * Set to true to enable pyth historical mode using timestamp from attach block
13
- */
14
- historicTimestamp: z.union([z.number().nonnegative(), z.literal(true)]).optional(),
15
- /**
16
- * Override Hermes API with this proxy. Can be used to set caching proxies, to avoid rate limiting
17
- */
18
- apiProxy: z.url().optional(),
19
- /**
20
- * TTL for pyth cache in milliseconds
21
- * If 0, disables caching
22
- * If not set, uses some default value
23
- * Cache is always enabled in historical mode
24
- */
25
- cacheTTL: z.number().nonnegative().optional(),
26
- /**
27
- * When true, no error will be thrown when pyth is unable to fetch data for some feeds
28
- */
29
- ignoreMissingFeeds: z.boolean().optional()
30
- });
31
- class PythUpdater extends SDKConstruct {
32
- #cache;
33
- #historicalTimestamp;
34
- #apiProxy;
35
- #ignoreMissingFeeds;
36
- constructor(sdk, opts = {}) {
37
- super(sdk);
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;
43
- this.logger?.debug(
44
- `using historical timestamp ${this.#historicalTimestamp}`
45
- );
46
- }
47
- this.#cache = PriceUpdatesCache.get("pyth", {
48
- // currently staleness period is 240 seconds on all networks, add some buffer
49
- // this period of 4 minutes is selected based on time that is required for user to sign transaction with wallet
50
- // so it's unlikely to decrease
51
- ttl: cacheTTL ?? 225 * 1e3,
52
- historical: !!historicTimestamp
53
- });
54
- }
55
- async getUpdateTxs(feeds) {
56
- if (feeds.length === 0) {
57
- return [];
58
- }
59
- this.logger?.debug(
60
- `generating update transactions for ${feeds.length} pyth price feeds`
61
- );
62
- const pythFeeds = new Map(
63
- feeds.filter(isPyth).map((f) => [f.priceFeedId, f])
64
- );
65
- const payloads = await this.#getPayloads(new Set(pythFeeds.keys()));
66
- let [minTimestamp, maxTimestamp] = [Number.POSITIVE_INFINITY, 0];
67
- const results = [];
68
- for (const p of payloads) {
69
- const priceFeed = pythFeeds.get(p.dataFeedId);
70
- if (!priceFeed) {
71
- throw new Error(`cannot find price feed for ${p.dataFeedId}`);
72
- }
73
- const { dataFeedId, timestamp, cached, data } = p;
74
- minTimestamp = Math.min(minTimestamp, timestamp);
75
- maxTimestamp = Math.max(maxTimestamp, timestamp);
76
- results.push(
77
- new PythUpdateTx(priceFeed.createPriceUpdateTx(data), {
78
- dataFeedId,
79
- priceFeed: priceFeed.address,
80
- timestamp,
81
- cached
82
- })
83
- );
84
- }
85
- let tsRange = "";
86
- if (results.length) {
87
- const minDelta = BigInt(minTimestamp) - this.sdk.timestamp;
88
- tsRange = `, timestamps ${minTimestamp} (${minDelta})`;
89
- if (minTimestamp !== maxTimestamp) {
90
- const maxDelta = BigInt(maxTimestamp) - this.sdk.timestamp;
91
- tsRange = `${tsRange} - ${maxTimestamp} (${maxDelta})`;
92
- }
93
- }
94
- this.logger?.debug(
95
- `generated ${results.length} update transactions for pyth price feeds: ${Array.from(pythFeeds.keys()).join(", ")}${tsRange}`
96
- );
97
- return results;
98
- }
99
- /**
100
- * Gets pyth payloads
101
- * @param dataFeedsIds
102
- * @returns
103
- */
104
- async #getPayloads(dataFeedsIds) {
105
- this.logger?.debug(
106
- `getting pyth payloads for ${dataFeedsIds.size} price feeds: ${Array.from(dataFeedsIds).join(", ")}`
107
- );
108
- const fromCache = [];
109
- const uncached = [];
110
- for (const priceFeedsId of dataFeedsIds) {
111
- const cached = this.#cache.get(priceFeedsId);
112
- if (cached) {
113
- fromCache.push({ ...cached, cached: true });
114
- } else {
115
- uncached.push(priceFeedsId);
116
- }
117
- }
118
- const fromPyth = await this.#fetchPayloads(
119
- new Set(uncached)
120
- );
121
- for (const resp of fromPyth) {
122
- this.#cache.set(resp, resp.dataFeedId);
123
- }
124
- this.logger?.debug(
125
- `got ${fromPyth.length} new pyth updates and ${fromCache.length} from cache`
126
- );
127
- return [...fromCache, ...fromPyth];
128
- }
129
- /**
130
- * Fetches pyth payloads from Hermes API
131
- * @param dataFeedsIds
132
- * @returns
133
- */
134
- async #fetchPayloads(dataFeedsIds) {
135
- if (dataFeedsIds.size === 0) {
136
- return [];
137
- }
138
- const ids = Array.from(dataFeedsIds);
139
- const tsStr = this.#historicalTimestamp ? ` with historical timestamp ${this.#historicalTimestamp}` : "";
140
- this.logger?.debug(
141
- `fetching pyth payloads for ${dataFeedsIds.size} price feeds: ${ids.join(", ")}${tsStr}`
142
- );
143
- return fetchPythPayloads({
144
- dataFeedsIds,
145
- historicalTimestampSeconds: this.#historicalTimestamp,
146
- apiProxy: this.#apiProxy,
147
- ignoreMissingFeeds: this.#ignoreMissingFeeds,
148
- logger: this.logger
149
- });
150
- }
151
- }
152
- function isPyth(pf) {
153
- return pf.contractType === "PRICE_FEED::PYTH";
154
- }
155
- export {
156
- PythOptions,
157
- PythUpdater
158
- };
@@ -1,115 +0,0 @@
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
- customFetch = fetch,
17
- returnPrices
18
- } = options;
19
- const ids = Array.from(new Set(dataFeedsIds));
20
- if (ids.length === 0) {
21
- return [];
22
- }
23
- let api = apiProxy ?? "https://hermes.pyth.network/v2/updates/price/";
24
- api = api.endsWith("/") ? api : `${api}/`;
25
- const url = new URL(api + (historicalTimestampSeconds ?? "latest"));
26
- url.searchParams.append("parsed", returnPrices ? "true" : "false");
27
- if (ignoreMissingFeeds) {
28
- url.searchParams.append("ignore_invalid_price_ids", "true");
29
- }
30
- for (const id of dataFeedsIds) {
31
- url.searchParams.append("ids[]", id);
32
- }
33
- const resp = await retry(
34
- async () => {
35
- const resp2 = await customFetch(url.toString());
36
- if (!resp2.ok) {
37
- const body = await resp2.text();
38
- throw new Error(
39
- `failed to fetch pyth payloads: ${resp2.statusText}: ${body}`
40
- );
41
- }
42
- const data = await resp2.json();
43
- return data;
44
- },
45
- { attempts: 3, exponent: 2, interval: 200 }
46
- );
47
- const result = respToCalldata(resp, returnPrices);
48
- if (result.length !== ids.length) {
49
- if (ignoreMissingFeeds) {
50
- logger?.warn(`expected ${ids.length} price feeds, got ${result.length}`);
51
- } else {
52
- throw new Error(
53
- `expected ${ids.length} price feeds, got ${result.length}`
54
- );
55
- }
56
- }
57
- return result;
58
- }
59
- function respToCalldata(resp, returnPrices) {
60
- if (resp.binary.data.length === 0) {
61
- return [];
62
- }
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
- }
74
- return updates.map(({ data, dataFeedId, timestamp }) => {
75
- const base = {
76
- dataFeedId,
77
- data: encodeAbiParameters(
78
- [{ type: "uint256" }, { type: "bytes[]" }],
79
- [BigInt(timestamp), [data]]
80
- ),
81
- timestamp,
82
- cached: false
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;
96
- });
97
- }
98
- function splitAccumulatorUpdates(binary) {
99
- const data = Buffer.from(binary, "hex");
100
- const parsed = parseAccumulatorUpdateData(data);
101
- const results = [];
102
- for (let i = 0; i < parsed.updates.length; i++) {
103
- const upd = parsed.updates[i].message;
104
- const msg = parsePriceFeedMessage(upd);
105
- results.push({
106
- dataFeedId: toHex(msg.feedId),
107
- timestamp: msg.publishTime.toNumber(),
108
- data: toHex(sliceAccumulatorUpdateData(data, i, i + 1))
109
- });
110
- }
111
- return results;
112
- }
113
- export {
114
- fetchPythPayloads
115
- };
@@ -1,41 +0,0 @@
1
- /**
2
- * This is https://github.com/pyth-network/pyth-crosschain/blob/main/price_service/sdk/js/src/AccumulatorUpdateData.ts
3
- * modified to use buffer from npm package
4
- */
5
- import BN from "bn.js";
6
- import { Buffer } from "buffer";
7
- export type AccumulatorUpdateData = {
8
- vaa: Buffer;
9
- updates: {
10
- message: Buffer;
11
- proof: number[][];
12
- }[];
13
- };
14
- export type PriceFeedMessage = {
15
- feedId: Buffer;
16
- price: BN;
17
- confidence: BN;
18
- exponent: number;
19
- publishTime: BN;
20
- prevPublishTime: BN;
21
- emaPrice: BN;
22
- emaConf: BN;
23
- };
24
- export type TwapMessage = {
25
- feedId: Buffer;
26
- cumulativePrice: BN;
27
- cumulativeConf: BN;
28
- numDownSlots: BN;
29
- exponent: number;
30
- publishTime: BN;
31
- prevPublishTime: BN;
32
- publishSlot: BN;
33
- };
34
- export declare function isAccumulatorUpdateData(updateBytes: Buffer): boolean;
35
- export declare function parsePriceFeedMessage(message: Buffer): PriceFeedMessage;
36
- export declare function parseTwapMessage(message: Buffer): TwapMessage;
37
- /**
38
- * An AccumulatorUpdateData contains a VAA and a list of updates. This function returns a new serialized AccumulatorUpdateData with only the updates in the range [start, end).
39
- */
40
- export declare function sliceAccumulatorUpdateData(data: Buffer, start?: number, end?: number): Buffer;
41
- export declare function parseAccumulatorUpdateData(data: Buffer): AccumulatorUpdateData;
@@ -1,26 +0,0 @@
1
- import { z } from "zod/v4";
2
- import { SDKConstruct } from "../../../base/index.js";
3
- import type { GearboxSDK } from "../../../GearboxSDK.js";
4
- import type { IPriceFeedContract } from "../types.js";
5
- import { PriceUpdateTx } from "./PriceUpdateTx.js";
6
- import type { IPriceUpdater, IPriceUpdateTask } from "./types.js";
7
- export type PythUpdateTask = IPriceUpdateTask;
8
- declare class PythUpdateTx extends PriceUpdateTx<PythUpdateTask> {
9
- readonly name = "pyth";
10
- }
11
- export declare const PythOptions: z.ZodObject<{
12
- historicTimestamp: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<true>]>>;
13
- apiProxy: z.ZodOptional<z.ZodURL>;
14
- cacheTTL: z.ZodOptional<z.ZodNumber>;
15
- ignoreMissingFeeds: z.ZodOptional<z.ZodBoolean>;
16
- }, z.core.$strip>;
17
- export type PythOptions = z.infer<typeof PythOptions>;
18
- /**
19
- * Class to update multiple pyth price feeds at once
20
- */
21
- export declare class PythUpdater extends SDKConstruct implements IPriceUpdater<PythUpdateTask> {
22
- #private;
23
- constructor(sdk: GearboxSDK, opts?: PythOptions);
24
- getUpdateTxs(feeds: IPriceFeedContract[]): Promise<PythUpdateTx[]>;
25
- }
26
- export {};
@@ -1,45 +0,0 @@
1
- import type { ILogger } from "../../../types/logger.js";
2
- import type { TimestampedCalldata, TimestampedCalldataWithPrice } 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
- * 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;
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[]>;
40
- /**
41
- * Fetches pyth payloads from Hermes API
42
- */
43
- export declare function fetchPythPayloads(options: FetchPythPayloadsOptions & {
44
- returnPrices?: false;
45
- }): Promise<TimestampedCalldata[]>;