@oddmaki-protocol/sdk 1.10.0 → 1.10.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.
- package/dist/index.d.mts +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +107 -27
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -9705,11 +9705,37 @@ declare class PriceMarketModule extends BaseModule {
|
|
|
9705
9705
|
*/
|
|
9706
9706
|
fetchProjectedOpenPrice(marketId: bigint): Promise<ProjectedOpenPrice | null>;
|
|
9707
9707
|
/**
|
|
9708
|
-
* Fetch historical Pyth price update data
|
|
9709
|
-
*
|
|
9710
|
-
*
|
|
9708
|
+
* Fetch historical Pyth price update data covering the window
|
|
9709
|
+
* `[publishTime, publishTime + windowSeconds]`.
|
|
9710
|
+
*
|
|
9711
|
+
* Hermes serves a VAA AT the exact requested second when one exists, and
|
|
9712
|
+
* 404s when no publish landed in that second. For low-volume feeds or
|
|
9713
|
+
* markets resolving deep in the past this means a single request at
|
|
9714
|
+
* `publishTime` is fragile. This helper walks a few sample points across
|
|
9715
|
+
* the window until it finds a VAA, transparently retrying with exponential
|
|
9716
|
+
* backoff on 429.
|
|
9717
|
+
*
|
|
9718
|
+
* The on-chain `pickEarliestInWindow` accepts any VAA whose `publishTime`
|
|
9719
|
+
* falls in the same window, so returning an offset VAA is correct as long
|
|
9720
|
+
* as it's still in range.
|
|
9711
9721
|
*/
|
|
9712
9722
|
private fetchPythHistoricalData;
|
|
9723
|
+
/**
|
|
9724
|
+
* Hermes parsed+binary fetch shared by {@link fetchPythHistoricalData} and
|
|
9725
|
+
* {@link fetchProjectedOpenPrice}. Returns the first in-window VAA whose
|
|
9726
|
+
* Hermes response includes a `parsed[0].price` entry, walking a few sample
|
|
9727
|
+
* timestamps across the window before giving up. Returns `null` on
|
|
9728
|
+
* complete miss so the caller can decide how to surface the failure
|
|
9729
|
+
* (resolution throws; UI projection returns null gracefully).
|
|
9730
|
+
*/
|
|
9731
|
+
private fetchPythHistoricalParsed;
|
|
9732
|
+
private fetchPythHistoricalRaw;
|
|
9733
|
+
/**
|
|
9734
|
+
* Fetch a Hermes URL with exponential backoff on 429. Returns the response
|
|
9735
|
+
* for 2xx, `null` for 404 (treated as "no VAA at this timestamp, try
|
|
9736
|
+
* another"), and throws for other errors.
|
|
9737
|
+
*/
|
|
9738
|
+
private hermesFetchWithBackoff;
|
|
9713
9739
|
}
|
|
9714
9740
|
|
|
9715
9741
|
declare class OddMakiClient {
|
package/dist/index.d.ts
CHANGED
|
@@ -9705,11 +9705,37 @@ declare class PriceMarketModule extends BaseModule {
|
|
|
9705
9705
|
*/
|
|
9706
9706
|
fetchProjectedOpenPrice(marketId: bigint): Promise<ProjectedOpenPrice | null>;
|
|
9707
9707
|
/**
|
|
9708
|
-
* Fetch historical Pyth price update data
|
|
9709
|
-
*
|
|
9710
|
-
*
|
|
9708
|
+
* Fetch historical Pyth price update data covering the window
|
|
9709
|
+
* `[publishTime, publishTime + windowSeconds]`.
|
|
9710
|
+
*
|
|
9711
|
+
* Hermes serves a VAA AT the exact requested second when one exists, and
|
|
9712
|
+
* 404s when no publish landed in that second. For low-volume feeds or
|
|
9713
|
+
* markets resolving deep in the past this means a single request at
|
|
9714
|
+
* `publishTime` is fragile. This helper walks a few sample points across
|
|
9715
|
+
* the window until it finds a VAA, transparently retrying with exponential
|
|
9716
|
+
* backoff on 429.
|
|
9717
|
+
*
|
|
9718
|
+
* The on-chain `pickEarliestInWindow` accepts any VAA whose `publishTime`
|
|
9719
|
+
* falls in the same window, so returning an offset VAA is correct as long
|
|
9720
|
+
* as it's still in range.
|
|
9711
9721
|
*/
|
|
9712
9722
|
private fetchPythHistoricalData;
|
|
9723
|
+
/**
|
|
9724
|
+
* Hermes parsed+binary fetch shared by {@link fetchPythHistoricalData} and
|
|
9725
|
+
* {@link fetchProjectedOpenPrice}. Returns the first in-window VAA whose
|
|
9726
|
+
* Hermes response includes a `parsed[0].price` entry, walking a few sample
|
|
9727
|
+
* timestamps across the window before giving up. Returns `null` on
|
|
9728
|
+
* complete miss so the caller can decide how to surface the failure
|
|
9729
|
+
* (resolution throws; UI projection returns null gracefully).
|
|
9730
|
+
*/
|
|
9731
|
+
private fetchPythHistoricalParsed;
|
|
9732
|
+
private fetchPythHistoricalRaw;
|
|
9733
|
+
/**
|
|
9734
|
+
* Fetch a Hermes URL with exponential backoff on 429. Returns the response
|
|
9735
|
+
* for 2xx, `null` for 404 (treated as "no VAA at this timestamp, try
|
|
9736
|
+
* another"), and throws for other errors.
|
|
9737
|
+
*/
|
|
9738
|
+
private hermesFetchWithBackoff;
|
|
9713
9739
|
}
|
|
9714
9740
|
|
|
9715
9741
|
declare class OddMakiClient {
|
package/dist/index.js
CHANGED
|
@@ -11575,15 +11575,18 @@ var PriceMarketModule = class extends BaseModule {
|
|
|
11575
11575
|
);
|
|
11576
11576
|
}
|
|
11577
11577
|
const isDeferred = pm.strikePrice === BigInt(0);
|
|
11578
|
+
const windowSeconds = Number(pm.resolutionWindow);
|
|
11578
11579
|
const closeVAA = await this.fetchPythHistoricalData(
|
|
11579
11580
|
pm.feedId,
|
|
11580
|
-
Number(pm.closeTime)
|
|
11581
|
+
Number(pm.closeTime),
|
|
11582
|
+
windowSeconds
|
|
11581
11583
|
);
|
|
11582
11584
|
let pythUpdateData;
|
|
11583
11585
|
if (isDeferred) {
|
|
11584
11586
|
const openVAA = await this.fetchPythHistoricalData(
|
|
11585
11587
|
pm.feedId,
|
|
11586
|
-
Number(pm.openTime)
|
|
11588
|
+
Number(pm.openTime),
|
|
11589
|
+
windowSeconds
|
|
11587
11590
|
);
|
|
11588
11591
|
pythUpdateData = [...openVAA, ...closeVAA];
|
|
11589
11592
|
} else {
|
|
@@ -11801,18 +11804,12 @@ var PriceMarketModule = class extends BaseModule {
|
|
|
11801
11804
|
if (pm.strikePrice !== BigInt(0)) return null;
|
|
11802
11805
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
11803
11806
|
if (now < pm.openTime) return null;
|
|
11804
|
-
const
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
}
|
|
11811
|
-
const data = await response.json();
|
|
11812
|
-
const parsed = data.parsed?.[0];
|
|
11813
|
-
if (!parsed?.price) {
|
|
11814
|
-
throw new Error("Pyth Hermes response missing parsed.price for open VAA");
|
|
11815
|
-
}
|
|
11807
|
+
const parsed = await this.fetchPythHistoricalParsed(
|
|
11808
|
+
pm.feedId,
|
|
11809
|
+
Number(pm.openTime),
|
|
11810
|
+
Number(pm.resolutionWindow)
|
|
11811
|
+
);
|
|
11812
|
+
if (!parsed) return null;
|
|
11816
11813
|
return {
|
|
11817
11814
|
price: BigInt(parsed.price.price),
|
|
11818
11815
|
publishTime: BigInt(parsed.price.publish_time),
|
|
@@ -11822,22 +11819,105 @@ var PriceMarketModule = class extends BaseModule {
|
|
|
11822
11819
|
};
|
|
11823
11820
|
}
|
|
11824
11821
|
/**
|
|
11825
|
-
* Fetch historical Pyth price update data
|
|
11826
|
-
*
|
|
11827
|
-
*
|
|
11822
|
+
* Fetch historical Pyth price update data covering the window
|
|
11823
|
+
* `[publishTime, publishTime + windowSeconds]`.
|
|
11824
|
+
*
|
|
11825
|
+
* Hermes serves a VAA AT the exact requested second when one exists, and
|
|
11826
|
+
* 404s when no publish landed in that second. For low-volume feeds or
|
|
11827
|
+
* markets resolving deep in the past this means a single request at
|
|
11828
|
+
* `publishTime` is fragile. This helper walks a few sample points across
|
|
11829
|
+
* the window until it finds a VAA, transparently retrying with exponential
|
|
11830
|
+
* backoff on 429.
|
|
11831
|
+
*
|
|
11832
|
+
* The on-chain `pickEarliestInWindow` accepts any VAA whose `publishTime`
|
|
11833
|
+
* falls in the same window, so returning an offset VAA is correct as long
|
|
11834
|
+
* as it's still in range.
|
|
11835
|
+
*/
|
|
11836
|
+
async fetchPythHistoricalData(feedId, publishTime, windowSeconds) {
|
|
11837
|
+
const result = await this.fetchPythHistoricalRaw(
|
|
11838
|
+
feedId,
|
|
11839
|
+
publishTime,
|
|
11840
|
+
windowSeconds
|
|
11841
|
+
);
|
|
11842
|
+
if (!result) {
|
|
11843
|
+
throw new Error(
|
|
11844
|
+
`No Pyth VAA available in window [${publishTime}, ${publishTime + windowSeconds}] for feed ${feedId}`
|
|
11845
|
+
);
|
|
11846
|
+
}
|
|
11847
|
+
return result.updateData;
|
|
11848
|
+
}
|
|
11849
|
+
/**
|
|
11850
|
+
* Hermes parsed+binary fetch shared by {@link fetchPythHistoricalData} and
|
|
11851
|
+
* {@link fetchProjectedOpenPrice}. Returns the first in-window VAA whose
|
|
11852
|
+
* Hermes response includes a `parsed[0].price` entry, walking a few sample
|
|
11853
|
+
* timestamps across the window before giving up. Returns `null` on
|
|
11854
|
+
* complete miss so the caller can decide how to surface the failure
|
|
11855
|
+
* (resolution throws; UI projection returns null gracefully).
|
|
11828
11856
|
*/
|
|
11829
|
-
async
|
|
11830
|
-
const
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
11857
|
+
async fetchPythHistoricalParsed(feedId, publishTime, windowSeconds) {
|
|
11858
|
+
const result = await this.fetchPythHistoricalRaw(
|
|
11859
|
+
feedId,
|
|
11860
|
+
publishTime,
|
|
11861
|
+
windowSeconds
|
|
11862
|
+
);
|
|
11863
|
+
return result?.parsed ?? null;
|
|
11864
|
+
}
|
|
11865
|
+
async fetchPythHistoricalRaw(feedId, publishTime, windowSeconds) {
|
|
11866
|
+
const window = Math.max(0, Math.floor(windowSeconds));
|
|
11867
|
+
const offsets = window === 0 ? [0] : Array.from(/* @__PURE__ */ new Set([
|
|
11868
|
+
0,
|
|
11869
|
+
Math.floor(window / 4),
|
|
11870
|
+
Math.floor(window / 2),
|
|
11871
|
+
Math.floor(3 * window / 4),
|
|
11872
|
+
window
|
|
11873
|
+
])).sort((a, b) => a - b);
|
|
11874
|
+
for (const offset of offsets) {
|
|
11875
|
+
const t = publishTime + offset;
|
|
11876
|
+
const url = `${PYTH_HERMES_BASE}/v2/updates/price/${t}?ids[]=${feedId}`;
|
|
11877
|
+
const response = await this.hermesFetchWithBackoff(url);
|
|
11878
|
+
if (response === null) continue;
|
|
11879
|
+
const data = await response.json();
|
|
11880
|
+
const updateDataRaw = data.binary?.data;
|
|
11881
|
+
const parsed = data.parsed?.[0];
|
|
11882
|
+
if (!updateDataRaw || updateDataRaw.length === 0) continue;
|
|
11883
|
+
return {
|
|
11884
|
+
updateData: updateDataRaw.map(
|
|
11885
|
+
(d) => `0x${d}`
|
|
11886
|
+
),
|
|
11887
|
+
parsed
|
|
11888
|
+
};
|
|
11834
11889
|
}
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11890
|
+
return null;
|
|
11891
|
+
}
|
|
11892
|
+
/**
|
|
11893
|
+
* Fetch a Hermes URL with exponential backoff on 429. Returns the response
|
|
11894
|
+
* for 2xx, `null` for 404 (treated as "no VAA at this timestamp, try
|
|
11895
|
+
* another"), and throws for other errors.
|
|
11896
|
+
*/
|
|
11897
|
+
async hermesFetchWithBackoff(url, options = {}) {
|
|
11898
|
+
const maxAttempts = options.maxAttempts ?? 4;
|
|
11899
|
+
const initialDelayMs = options.initialDelayMs ?? 500;
|
|
11900
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
11901
|
+
const response = await fetch(url);
|
|
11902
|
+
if (response.status === 429) {
|
|
11903
|
+
if (attempt === maxAttempts - 1) {
|
|
11904
|
+
throw new Error(
|
|
11905
|
+
`Pyth Hermes API error: 429 Too Many Requests (gave up after ${maxAttempts} attempts)`
|
|
11906
|
+
);
|
|
11907
|
+
}
|
|
11908
|
+
const delay = initialDelayMs * Math.pow(2, attempt);
|
|
11909
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
11910
|
+
continue;
|
|
11911
|
+
}
|
|
11912
|
+
if (response.status === 404) return null;
|
|
11913
|
+
if (!response.ok) {
|
|
11914
|
+
throw new Error(
|
|
11915
|
+
`Pyth Hermes API error: ${response.status} ${response.statusText}`
|
|
11916
|
+
);
|
|
11917
|
+
}
|
|
11918
|
+
return response;
|
|
11839
11919
|
}
|
|
11840
|
-
return
|
|
11920
|
+
return null;
|
|
11841
11921
|
}
|
|
11842
11922
|
};
|
|
11843
11923
|
|