@oddmaki-protocol/sdk 0.3.1 → 0.4.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.
package/dist/index.mjs CHANGED
@@ -5045,6 +5045,11 @@ var PriceMarketFacet_default = [
5045
5045
  name: "strikePrice",
5046
5046
  type: "int64",
5047
5047
  internalType: "int64"
5048
+ },
5049
+ {
5050
+ name: "openPriceTime",
5051
+ type: "uint256",
5052
+ internalType: "uint256"
5048
5053
  }
5049
5054
  ],
5050
5055
  stateMutability: "view"
@@ -5190,6 +5195,32 @@ var PythResolutionFacet_default = [
5190
5195
  outputs: [],
5191
5196
  stateMutability: "nonpayable"
5192
5197
  },
5198
+ {
5199
+ type: "function",
5200
+ name: "setOpenMaxStaleness",
5201
+ inputs: [
5202
+ {
5203
+ name: "openMaxStaleness",
5204
+ type: "uint256",
5205
+ internalType: "uint256"
5206
+ }
5207
+ ],
5208
+ outputs: [],
5209
+ stateMutability: "nonpayable"
5210
+ },
5211
+ {
5212
+ type: "function",
5213
+ name: "getOpenMaxStaleness",
5214
+ inputs: [],
5215
+ outputs: [
5216
+ {
5217
+ name: "",
5218
+ type: "uint256",
5219
+ internalType: "uint256"
5220
+ }
5221
+ ],
5222
+ stateMutability: "view"
5223
+ },
5193
5224
  {
5194
5225
  type: "event",
5195
5226
  name: "MarketCreated",
@@ -5412,6 +5443,19 @@ var PythResolutionFacet_default = [
5412
5443
  ],
5413
5444
  anonymous: false
5414
5445
  },
5446
+ {
5447
+ type: "event",
5448
+ name: "OpenMaxStalenessUpdated",
5449
+ inputs: [
5450
+ {
5451
+ name: "openMaxStaleness",
5452
+ type: "uint256",
5453
+ indexed: false,
5454
+ internalType: "uint256"
5455
+ }
5456
+ ],
5457
+ anonymous: false
5458
+ },
5415
5459
  {
5416
5460
  type: "event",
5417
5461
  name: "WrappedCollateralRegistered",
@@ -7842,6 +7886,25 @@ var TradeModule = class extends BaseModule {
7842
7886
  });
7843
7887
  return wallet.writeContract(request);
7844
7888
  }
7889
+ /**
7890
+ * Cancel all remaining orders on a resolved market in a single transaction.
7891
+ * Regular cancelOrder / batchCancelOrders revert once the market is no longer
7892
+ * active, so this is the only way to clear stale orders post-resolution.
7893
+ * @param marketId - The resolved market
7894
+ * @param orderIds - Order IDs to cancel (must belong to caller)
7895
+ */
7896
+ async cancelOrdersOnResolvedMarket(marketId, orderIds) {
7897
+ const wallet = this.walletClient;
7898
+ const [account] = await wallet.getAddresses();
7899
+ const { request } = await this.publicClient.simulateContract({
7900
+ address: this.config.diamondAddress,
7901
+ abi: LimitOrdersFacet_default,
7902
+ functionName: "cancelOrdersOnResolvedMarket",
7903
+ args: [marketId, orderIds],
7904
+ account
7905
+ });
7906
+ return wallet.writeContract(request);
7907
+ }
7845
7908
  /**
7846
7909
  * Execute a market order (FOK or FAK)
7847
7910
  *
@@ -10463,6 +10526,8 @@ var FeedProvider = /* @__PURE__ */ ((FeedProvider2) => {
10463
10526
  FeedProvider2[FeedProvider2["CHAINLINK"] = 1] = "CHAINLINK";
10464
10527
  return FeedProvider2;
10465
10528
  })(FeedProvider || {});
10529
+ var DEFAULT_FRESH_MAX_AGE_SECONDS = 120;
10530
+ var DEFAULT_FRESH_MAX_ATTEMPTS = 3;
10466
10531
  var PriceMarketModule = class extends BaseModule {
10467
10532
  /**
10468
10533
  * Create a Pyth-powered price market
@@ -10606,7 +10671,8 @@ var PriceMarketModule = class extends BaseModule {
10606
10671
  finalPrice: BigInt(result[5]),
10607
10672
  resolutionWindow: BigInt(result[6]),
10608
10673
  resolved: result[7],
10609
- strikePrice: BigInt(result[8])
10674
+ strikePrice: BigInt(result[8]),
10675
+ openPriceTime: BigInt(result[9])
10610
10676
  };
10611
10677
  }
10612
10678
  /**
@@ -10619,6 +10685,51 @@ var PriceMarketModule = class extends BaseModule {
10619
10685
  functionName: "getPythContract"
10620
10686
  });
10621
10687
  }
10688
+ /**
10689
+ * Set the Pyth oracle contract address. Diamond owner only.
10690
+ */
10691
+ async setPythContract(pythContract) {
10692
+ const wallet = this.walletClient;
10693
+ const [account] = await wallet.getAddresses();
10694
+ const { request } = await this.publicClient.simulateContract({
10695
+ address: this.config.diamondAddress,
10696
+ abi: PythResolutionFacet_default,
10697
+ functionName: "setPythContract",
10698
+ args: [pythContract],
10699
+ account
10700
+ });
10701
+ return wallet.writeContract(request);
10702
+ }
10703
+ /**
10704
+ * Get the effective opening-price staleness window in seconds.
10705
+ *
10706
+ * A submitted VAA's `publishTime` must fall within
10707
+ * `[block.timestamp - openMaxStaleness, block.timestamp + OPEN_FUTURE_SKEW]`
10708
+ * at `createPriceMarketPyth` time. Defaults to 300s when unset on-chain.
10709
+ */
10710
+ async getOpenMaxStaleness() {
10711
+ return await this.publicClient.readContract({
10712
+ address: this.config.diamondAddress,
10713
+ abi: PythResolutionFacet_default,
10714
+ functionName: "getOpenMaxStaleness"
10715
+ });
10716
+ }
10717
+ /**
10718
+ * Set the opening-price staleness window (seconds). Diamond owner only.
10719
+ * Pass 0 to fall back to the built-in default.
10720
+ */
10721
+ async setOpenMaxStaleness(openMaxStaleness) {
10722
+ const wallet = this.walletClient;
10723
+ const [account] = await wallet.getAddresses();
10724
+ const { request } = await this.publicClient.simulateContract({
10725
+ address: this.config.diamondAddress,
10726
+ abi: PythResolutionFacet_default,
10727
+ functionName: "setOpenMaxStaleness",
10728
+ args: [openMaxStaleness],
10729
+ account
10730
+ });
10731
+ return wallet.writeContract(request);
10732
+ }
10622
10733
  // ---- Private helpers ----
10623
10734
  /**
10624
10735
  * Shared pre-flight checks: creation fee allowance, ancillary data, tags
@@ -10671,20 +10782,73 @@ var PriceMarketModule = class extends BaseModule {
10671
10782
  return stringToHex(data);
10672
10783
  }
10673
10784
  /**
10674
- * Fetch latest Pyth price update data from Hermes API
10785
+ * Fetch latest Pyth price update from Hermes — bytes plus the VAA's publishTime.
10786
+ *
10787
+ * Use this (or {@link fetchFreshPythUpdate}) instead of re-rolling Hermes
10788
+ * calls when building `createPriceMarketPyth` transactions. The on-chain
10789
+ * staleness window defaults to 300s — if the user takes longer than that
10790
+ * to sign, the VAA will be rejected.
10675
10791
  */
10676
- async fetchPythUpdateData(feedId) {
10792
+ async fetchPythLatestUpdate(feedId) {
10677
10793
  const url = `${PYTH_HERMES_BASE}/v2/updates/price/latest?ids[]=${feedId}`;
10678
10794
  const response = await fetch(url);
10679
10795
  if (!response.ok) {
10680
- throw new Error(`Pyth Hermes API error: ${response.status} ${response.statusText}`);
10796
+ throw new Error(
10797
+ `Pyth Hermes API error: ${response.status} ${response.statusText}`
10798
+ );
10681
10799
  }
10682
10800
  const data = await response.json();
10683
10801
  const updateData = data.binary?.data;
10684
10802
  if (!updateData || updateData.length === 0) {
10685
10803
  throw new Error("No price update data returned from Pyth Hermes");
10686
10804
  }
10687
- return updateData.map((d) => `0x${d}`);
10805
+ const parsed = data.parsed?.[0];
10806
+ const publishTimeRaw = parsed?.price?.publish_time;
10807
+ if (typeof publishTimeRaw !== "number") {
10808
+ throw new Error("Pyth Hermes response missing parsed.price.publish_time");
10809
+ }
10810
+ return {
10811
+ updateData: updateData.map((d) => `0x${d}`),
10812
+ publishTime: BigInt(publishTimeRaw),
10813
+ fetchedAt: BigInt(Math.floor(Date.now() / 1e3))
10814
+ };
10815
+ }
10816
+ /**
10817
+ * Return a Pyth update that is fresh enough to pass the on-chain staleness check.
10818
+ *
10819
+ * If `cached` is provided and still within `maxAgeSeconds`, it is returned as-is.
10820
+ * Otherwise Hermes is re-queried; if the newly fetched VAA is also older than
10821
+ * `maxAgeSeconds` (e.g. feed is quiet), it retries up to `maxAttempts`.
10822
+ *
10823
+ * Defaults: `maxAgeSeconds = 120` (leaves ~180s headroom under the 300s default
10824
+ * on-chain window), `maxAttempts = 3`.
10825
+ */
10826
+ async fetchFreshPythUpdate(feedId, options = {}) {
10827
+ const maxAgeSeconds = options.maxAgeSeconds ?? DEFAULT_FRESH_MAX_AGE_SECONDS;
10828
+ const maxAttempts = options.maxAttempts ?? DEFAULT_FRESH_MAX_ATTEMPTS;
10829
+ const isFresh = (u) => {
10830
+ const now = BigInt(Math.floor(Date.now() / 1e3));
10831
+ return now - u.publishTime <= BigInt(maxAgeSeconds);
10832
+ };
10833
+ if (options.cached && isFresh(options.cached)) {
10834
+ return options.cached;
10835
+ }
10836
+ let latest;
10837
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
10838
+ latest = await this.fetchPythLatestUpdate(feedId);
10839
+ if (isFresh(latest)) return latest;
10840
+ }
10841
+ if (!latest) {
10842
+ throw new Error("Failed to fetch any Pyth update from Hermes");
10843
+ }
10844
+ return latest;
10845
+ }
10846
+ /**
10847
+ * Fetch latest Pyth price update data from Hermes API (raw bytes only).
10848
+ */
10849
+ async fetchPythUpdateData(feedId) {
10850
+ const { updateData } = await this.fetchPythLatestUpdate(feedId);
10851
+ return updateData;
10688
10852
  }
10689
10853
  /**
10690
10854
  * Fetch historical Pyth price update data at a specific timestamp