@waterx/sdk 4.0.1 → 4.1.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 (110) hide show
  1. package/README.md +25 -10
  2. package/dist/cjs/src/account/account.js +2 -1
  3. package/dist/cjs/src/account/funding/balance.d.ts +25 -2
  4. package/dist/cjs/src/account/funding/balance.js +36 -24
  5. package/dist/cjs/src/account/funding/credit.js +6 -10
  6. package/dist/cjs/src/constants.d.ts +15 -1
  7. package/dist/cjs/src/constants.js +18 -4
  8. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  9. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +13 -0
  10. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  11. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.js +31 -0
  12. package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +940 -0
  13. package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +1092 -0
  14. package/dist/cjs/src/oracle/aggregate.d.ts +2 -0
  15. package/dist/cjs/src/oracle/aggregate.js +27 -2
  16. package/dist/cjs/src/oracle/config.d.ts +75 -0
  17. package/dist/cjs/src/oracle/config.js +15 -1
  18. package/dist/cjs/src/oracle/host.d.ts +12 -1
  19. package/dist/cjs/src/oracle/index.d.ts +2 -0
  20. package/dist/cjs/src/oracle/index.js +6 -1
  21. package/dist/cjs/src/oracle/price-update-rule.d.ts +3 -4
  22. package/dist/cjs/src/oracle/rule-registry.d.ts +8 -7
  23. package/dist/cjs/src/oracle/rule-registry.js +10 -7
  24. package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +89 -0
  25. package/dist/cjs/src/oracle/rules/waterx-rule.js +272 -0
  26. package/dist/cjs/src/perp/client.d.ts +44 -6
  27. package/dist/cjs/src/perp/client.js +14 -0
  28. package/dist/cjs/src/perp/config.d.ts +2 -3
  29. package/dist/cjs/src/perp/config.js +2 -1
  30. package/dist/cjs/src/perp/constants.d.ts +0 -6
  31. package/dist/cjs/src/perp/constants.js +11 -9
  32. package/dist/cjs/src/perp/fetch/account.js +3 -0
  33. package/dist/cjs/src/perp/fetch/bridge.js +2 -1
  34. package/dist/cjs/src/perp/fetch/market.js +2 -1
  35. package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
  36. package/dist/cjs/src/perp/fetch/positions.js +23 -20
  37. package/dist/cjs/src/perp/index.d.ts +6 -2
  38. package/dist/cjs/src/perp/index.js +12 -6
  39. package/dist/cjs/src/perp/liq-view.d.ts +64 -0
  40. package/dist/cjs/src/perp/liq-view.js +74 -0
  41. package/dist/cjs/src/perp/user/order.d.ts +13 -0
  42. package/dist/cjs/src/perp/user/order.js +30 -16
  43. package/dist/cjs/src/perp/user/staking.js +3 -2
  44. package/dist/cjs/src/perp/user/trading.js +25 -24
  45. package/dist/cjs/src/perp/user/wlp.js +6 -5
  46. package/dist/cjs/src/prediction/utils.d.ts +11 -2
  47. package/dist/cjs/src/prediction/utils.js +22 -22
  48. package/dist/cjs/src/unified-client.d.ts +31 -10
  49. package/dist/cjs/src/unified-client.js +2 -0
  50. package/dist/cjs/src/utils/format.d.ts +14 -0
  51. package/dist/cjs/src/utils/format.js +24 -0
  52. package/dist/cjs/src/utils/math.d.ts +304 -12
  53. package/dist/cjs/src/utils/math.js +397 -17
  54. package/dist/cjs/src/utils/validate.d.ts +69 -0
  55. package/dist/cjs/src/utils/validate.js +183 -0
  56. package/dist/src/account/account.js +2 -1
  57. package/dist/src/account/funding/balance.d.ts +25 -2
  58. package/dist/src/account/funding/balance.js +36 -24
  59. package/dist/src/account/funding/credit.js +6 -10
  60. package/dist/src/constants.d.ts +15 -1
  61. package/dist/src/constants.js +17 -3
  62. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  63. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
  64. package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  65. package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
  66. package/dist/src/generated/waterx_rule/waterx_rule.d.ts +940 -0
  67. package/dist/src/generated/waterx_rule/waterx_rule.js +991 -0
  68. package/dist/src/oracle/aggregate.d.ts +2 -0
  69. package/dist/src/oracle/aggregate.js +27 -2
  70. package/dist/src/oracle/config.d.ts +75 -0
  71. package/dist/src/oracle/config.js +14 -0
  72. package/dist/src/oracle/host.d.ts +12 -1
  73. package/dist/src/oracle/index.d.ts +2 -0
  74. package/dist/src/oracle/index.js +3 -0
  75. package/dist/src/oracle/price-update-rule.d.ts +3 -4
  76. package/dist/src/oracle/rule-registry.d.ts +8 -7
  77. package/dist/src/oracle/rule-registry.js +10 -7
  78. package/dist/src/oracle/rules/waterx-rule.d.ts +89 -0
  79. package/dist/src/oracle/rules/waterx-rule.js +266 -0
  80. package/dist/src/perp/client.d.ts +44 -6
  81. package/dist/src/perp/client.js +15 -1
  82. package/dist/src/perp/config.d.ts +2 -3
  83. package/dist/src/perp/config.js +1 -1
  84. package/dist/src/perp/constants.d.ts +0 -6
  85. package/dist/src/perp/constants.js +10 -8
  86. package/dist/src/perp/fetch/account.js +3 -0
  87. package/dist/src/perp/fetch/bridge.js +2 -1
  88. package/dist/src/perp/fetch/market.js +2 -1
  89. package/dist/src/perp/fetch/positions.d.ts +16 -10
  90. package/dist/src/perp/fetch/positions.js +28 -20
  91. package/dist/src/perp/index.d.ts +6 -2
  92. package/dist/src/perp/index.js +4 -2
  93. package/dist/src/perp/liq-view.d.ts +64 -0
  94. package/dist/src/perp/liq-view.js +71 -0
  95. package/dist/src/perp/user/order.d.ts +13 -0
  96. package/dist/src/perp/user/order.js +30 -16
  97. package/dist/src/perp/user/staking.js +3 -2
  98. package/dist/src/perp/user/trading.js +25 -24
  99. package/dist/src/perp/user/wlp.js +6 -5
  100. package/dist/src/prediction/utils.d.ts +11 -2
  101. package/dist/src/prediction/utils.js +22 -22
  102. package/dist/src/unified-client.d.ts +31 -10
  103. package/dist/src/unified-client.js +2 -0
  104. package/dist/src/utils/format.d.ts +14 -0
  105. package/dist/src/utils/format.js +21 -0
  106. package/dist/src/utils/math.d.ts +304 -12
  107. package/dist/src/utils/math.js +394 -17
  108. package/dist/src/utils/validate.d.ts +69 -0
  109. package/dist/src/utils/validate.js +167 -0
  110. package/package.json +4 -1
@@ -25,6 +25,7 @@ import type { Transaction, TransactionArgument } from "@mysten/sui/transactions"
25
25
  import type { OracleHost } from "./host.ts";
26
26
  import type { OracleSource, PriceUpdateRule, UpdateDataProvider } from "./price-update-rule.ts";
27
27
  import { type OracleFeeSource, type PythCache } from "./pyth.ts";
28
+ import { type WaterxSignedEnvelope } from "./rules/waterx-rule.ts";
28
29
  /**
29
30
  * Aggregate one ticker's price into the shared `Oracle`: build a collector, feed
30
31
  * every rule the ticker is configured for, then `aggregate`.
@@ -54,6 +55,7 @@ export declare function aggregateTicker(tx: Transaction, host: OracleHost, args:
54
55
  ticker: string;
55
56
  priceInfoObjectId?: string;
56
57
  lazerUpdate?: TransactionArgument;
58
+ waterxEnvelope?: WaterxSignedEnvelope;
57
59
  }): void;
58
60
  /**
59
61
  * Thin wrapper over {@link aggregateTicker} for a Pyth-fed ticker. Kept for
@@ -34,6 +34,7 @@ const constant_rule_ts_1 = require("./rules/constant-rule.js");
34
34
  const pyth_lazer_rule_ts_1 = require("./rules/pyth-lazer-rule.js");
35
35
  const pyth_rule_ts_1 = require("./rules/pyth-rule.js");
36
36
  const supra_rule_ts_1 = require("./rules/supra-rule.js");
37
+ const waterx_rule_ts_1 = require("./rules/waterx-rule.js");
37
38
  /**
38
39
  * Resolve one group's off-chain update payload for {@link refreshOraclePrices}:
39
40
  * try `provider.get(source, tickers)` first (when a provider is configured),
@@ -116,6 +117,14 @@ function aggregateTicker(tx, host, args) {
116
117
  (0, pyth_lazer_rule_ts_1.feedLazerRule)(tx, host, collector, args.lazerUpdate);
117
118
  fed = true;
118
119
  }
120
+ if (args.waterxEnvelope !== undefined) {
121
+ // waterx_rule::collect_batch_latest verifies the batch signature and feeds
122
+ // this collector's symbol from the batch. If the ticker's aggregator does
123
+ // not (yet) weight `WaterxRule`, the contribution is silently dropped
124
+ // on-chain — feeding ahead of the weight migration is harmless.
125
+ (0, waterx_rule_ts_1.feedWaterxRule)(tx, host, collector, args.waterxEnvelope);
126
+ fed = true;
127
+ }
119
128
  if (fed) {
120
129
  // Supra rides on the same collector when enabled (abstains on-chain otherwise).
121
130
  (0, supra_rule_ts_1.maybeFeedSupra)(tx, host, collector);
@@ -250,6 +259,11 @@ async function refreshOraclePrices(tx, host, tickers, opts = {}) {
250
259
  // moveCalls in a caller-owned tx. Map each lazer-served ticker to the one
251
260
  // verified `Update` PTB value for the collector-feed leg below.
252
261
  const lazerUpdateByTicker = new Map();
262
+ // Signed batch envelope per waterx-served ticker. Unlike Lazer's shared PTB
263
+ // handle, waterx's verify+feed is bundled into `collect_batch_latest` in the
264
+ // per-ticker feed leg, so its `buildUpdateCalls` emits nothing and the
265
+ // envelope is carried straight from the group's fetched data.
266
+ const waterxEnvelopeByTicker = new Map();
253
267
  if (selectedGroup.length > 0) {
254
268
  const group = { source: host.oracleSource, rule: selectedRule, tickers: selectedGroup };
255
269
  const data = await resolveGroupUpdateData(host, group, opts.updateDataProvider);
@@ -258,12 +272,22 @@ async function refreshOraclePrices(tx, host, tickers, opts = {}) {
258
272
  feeSource: opts.feeSource,
259
273
  })) ?? undefined;
260
274
  // Route by the handle's kind discriminant — the one site the tag exists to
261
- // protect: a future non-lazer handle (e.g. a WaterxRule value) must never
262
- // be silently fed into pyth_lazer_rule::feed.
275
+ // protect: a future non-lazer handle must never be silently fed into
276
+ // pyth_lazer_rule::feed.
263
277
  if (handle?.kind === "pyth_lazer_rule") {
264
278
  for (const ticker of selectedGroup)
265
279
  lazerUpdateByTicker.set(ticker, handle.update);
266
280
  }
281
+ // waterx_rule emits no shared handle (verify+feed is bundled into the
282
+ // per-ticker `collect_batch_latest`), so the envelope is carried straight
283
+ // from this group's fetched data to the feed leg below.
284
+ if (selectedRule.kind === "waterx_rule") {
285
+ const envelope = (0, waterx_rule_ts_1.waterxEnvelopeOf)(data);
286
+ if (envelope) {
287
+ for (const ticker of selectedGroup)
288
+ waterxEnvelopeByTicker.set(ticker, envelope);
289
+ }
290
+ }
267
291
  }
268
292
  // Aggregate each ticker, feeding whichever rules it is configured for.
269
293
  for (const ticker of tickers) {
@@ -271,6 +295,7 @@ async function refreshOraclePrices(tx, host, tickers, opts = {}) {
271
295
  ticker,
272
296
  priceInfoObjectId: priceInfoByTicker.get(ticker),
273
297
  lazerUpdate: lazerUpdateByTicker.get(ticker),
298
+ waterxEnvelope: waterxEnvelopeByTicker.get(ticker),
274
299
  });
275
300
  }
276
301
  }
@@ -12,6 +12,7 @@
12
12
  import type { BasePackageEntry } from "../account/config.ts";
13
13
  import type { BaseLineConfig } from "../base-client.ts";
14
14
  import type { Network } from "../constants.ts";
15
+ import type { FetchPolicy } from "./update-fetch.ts";
15
16
  export interface PythRulePackage extends BasePackageEntry {
16
17
  config: string;
17
18
  feeds: Record<string, {
@@ -82,6 +83,39 @@ export interface SupraRulePackage extends BasePackageEntry {
82
83
  */
83
84
  enabled?: boolean;
84
85
  }
86
+ /**
87
+ * Per-ticker `waterx_rule` feed entry. Keyed in `feeds` by the oracle **ticker**
88
+ * (e.g. `"SUIUSD"`, the same key `pyth_rule.feeds` uses), so
89
+ * `Object.keys(feeds)` is the SDK's supported-ticker set. The fields are
90
+ * informational off-chain — the SDK keys routing/support off the entry's
91
+ * presence and pushes the enclave-signed price verbatim, never re-deriving it.
92
+ */
93
+ export interface WaterxRuleFeedEntry {
94
+ /** Exchange ticker the quote-center aggregates from (e.g. `"SUIUSDT"`). */
95
+ ticker?: string;
96
+ }
97
+ /**
98
+ * `waterx_rule` deployment entry — the first-party Nautilus-TEE oracle rule.
99
+ * Read by `WaterxRule` (`rules/waterx-rule.ts`): `feeds` for ticker support,
100
+ * `config`/`enclave_config`/`enclave` for the `collect_batch_latest` call,
101
+ * `published_at` for the package address. The off-chain signed price is pulled
102
+ * from the quote-center (endpoint from {@link WATERX_DEFAULTS}), not this JSON.
103
+ *
104
+ * `enabled` mirrors the JSON field verbatim but MUST NOT be read for routing —
105
+ * which rule prices a ticker is decided solely by the client's `oracleSource`
106
+ * create option (see `OracleHost.oracleSource`), mirroring `pyth_lazer_rule`.
107
+ */
108
+ export interface WaterxRulePackage extends BasePackageEntry {
109
+ /** Shared `waterx_rule::Config` (per-symbol on-chain feed_config). */
110
+ config: string;
111
+ /** Shared `EnclaveConfig<WATERX_RULE>` the on-chain signature verify runs against. */
112
+ enclave_config: string;
113
+ /** Shared `Enclave<WATERX_RULE>` holding the registered TEE signing pubkey. */
114
+ enclave: string;
115
+ enabled?: boolean;
116
+ /** Oracle ticker → feed entry; presence marks the ticker as waterx-served. */
117
+ feeds: Record<string, WaterxRuleFeedEntry>;
118
+ }
85
119
  export interface WaterxOraclePackage extends BasePackageEntry {
86
120
  listing_cap: string;
87
121
  oracle: string;
@@ -99,6 +133,8 @@ export interface OraclePackages {
99
133
  pyth_lazer_rule?: PythLazerRulePackage;
100
134
  constant_rule?: WaterxConstantRulePackage;
101
135
  supra_rule?: SupraRulePackage;
136
+ /** See {@link WaterxRulePackage} — read by `WaterxRule` when `oracleSource` selects it. */
137
+ waterx_rule?: WaterxRulePackage;
102
138
  waterx_oracle: WaterxOraclePackage;
103
139
  }
104
140
  /**
@@ -172,6 +208,45 @@ export declare const LAZER_DEFAULTS: Record<Network, {
172
208
  endpoint: string;
173
209
  verifier_package: string;
174
210
  }>;
211
+ /**
212
+ * Resolved WaterX quote-center infra for `WaterxRule` — the network default
213
+ * from {@link WATERX_DEFAULTS}, with both fields overridable at client init
214
+ * (`waterxEndpoint` / `waterxFetch`).
215
+ *
216
+ * The override exists because this is the one oracle source a BROWSER fetches
217
+ * itself: the rule pulls the signed envelope from the page, so it is subject to
218
+ * the quote-center deployment's CORS allowlist. A front end whose origin is not
219
+ * on that list — or one that must route egress through its own backend — points
220
+ * `endpoint` at a same-origin proxy (or supplies `fetch.fetchImpl`) instead of
221
+ * being locked to the hardcoded host.
222
+ */
223
+ export interface WaterxInfraConfig {
224
+ /**
225
+ * Quote-center base URL. A base PATH is preserved — the rule appends via
226
+ * `joinEndpointPath`, so `https://app.example/api/quote-center` resolves to
227
+ * `…/api/quote-center/v1/quotes/update` and a proxy route is not rewritten
228
+ * away. A trailing slash is trimmed.
229
+ */
230
+ endpoint: string;
231
+ /**
232
+ * Retry/timeout policy (and `fetchImpl`) for the quote-center fetch — see
233
+ * `fetchWithPolicy` (`./update-fetch.ts`). Supplied via the `waterxFetch`
234
+ * create option. When unset the rule falls back to the shared `pyth.fetch`
235
+ * policy, then to `fetchWithPolicy`'s defaults (15s timeout, 2 retries).
236
+ */
237
+ fetch?: FetchPolicy;
238
+ }
239
+ /**
240
+ * WaterX quote-center base URL by network — the first-party TEE-signed price
241
+ * hub `WaterxRule` pulls from (`GET /v1/quotes/update?symbols=…`). Mirrors
242
+ * {@link LAZER_DEFAULTS}: infra WaterX operates, not part of the `waterx-config`
243
+ * JSON. Public read (no auth), so there is no api_key. `endpoint` has no
244
+ * trailing slash — the rule appends the path.
245
+ *
246
+ * These are DEFAULTS, not a hard pin: a consumer overrides them per client via
247
+ * `waterxEndpoint` / `waterxFetch` (resolved onto `client.waterx`).
248
+ */
249
+ export declare const WATERX_DEFAULTS: Record<Network, WaterxInfraConfig>;
175
250
  /**
176
251
  * The narrow config shape the oracle/refresh code needs. `WaterXConfig`
177
252
  * (the perp line's full config) is assignable to this, so `PerpClient` satisfies
@@ -11,7 +11,7 @@
11
11
  * mirrors the earlier account-config hoist.
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.LAZER_DEFAULTS = exports.PYTH_DEFAULTS = void 0;
14
+ exports.WATERX_DEFAULTS = exports.LAZER_DEFAULTS = exports.PYTH_DEFAULTS = void 0;
15
15
  exports.PYTH_DEFAULTS = {
16
16
  MAINNET: {
17
17
  state_id: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
@@ -53,3 +53,17 @@ exports.LAZER_DEFAULTS = {
53
53
  verifier_package: "0xf5bd2141967507050a91b58de3d95e77c432cd90d1799ee46effc27430a68c21",
54
54
  },
55
55
  };
56
+ /**
57
+ * WaterX quote-center base URL by network — the first-party TEE-signed price
58
+ * hub `WaterxRule` pulls from (`GET /v1/quotes/update?symbols=…`). Mirrors
59
+ * {@link LAZER_DEFAULTS}: infra WaterX operates, not part of the `waterx-config`
60
+ * JSON. Public read (no auth), so there is no api_key. `endpoint` has no
61
+ * trailing slash — the rule appends the path.
62
+ *
63
+ * These are DEFAULTS, not a hard pin: a consumer overrides them per client via
64
+ * `waterxEndpoint` / `waterxFetch` (resolved onto `client.waterx`).
65
+ */
66
+ exports.WATERX_DEFAULTS = {
67
+ MAINNET: { endpoint: "https://quote-center.waterx.app" },
68
+ TESTNET: { endpoint: "https://quote-center-staging.waterx.app" },
69
+ };
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import type { SuiGrpcClient } from "@mysten/sui/grpc";
11
11
  import type { Network } from "../constants.ts";
12
- import type { OracleConfig, PythInfraConfig } from "./config.ts";
12
+ import type { OracleConfig, PythInfraConfig, WaterxInfraConfig } from "./config.ts";
13
13
  import type { OracleSource } from "./price-update-rule.ts";
14
14
  export interface OracleHost {
15
15
  /** Sui network this client targets — selects per-network external-infra defaults (e.g. `LAZER_DEFAULTS`). */
@@ -18,6 +18,17 @@ export interface OracleHost {
18
18
  readonly config: OracleConfig;
19
19
  /** External Pyth/Wormhole/Hermes infra — fixed per `(network, generation)`; api_key/fetch layered from create options. */
20
20
  readonly pyth: PythInfraConfig;
21
+ /**
22
+ * WaterX quote-center infra for `WaterxRule` — endpoint + fetch policy,
23
+ * resolved from the `waterxEndpoint` / `waterxFetch` create options.
24
+ *
25
+ * OPTIONAL so an existing host stays a valid `OracleHost`: when absent the
26
+ * rule falls back to `WATERX_DEFAULTS[network]`. This is the hook a browser
27
+ * consumer uses to route the quote-center fetch through a same-origin proxy
28
+ * (`endpoint`) or its own transport (`fetch.fetchImpl`) — that request is
29
+ * made from the page, so it is bound by the quote-center's CORS allowlist.
30
+ */
31
+ readonly waterx?: WaterxInfraConfig;
21
32
  /** gRPC client for the on-chain reads the Pyth update path needs. */
22
33
  readonly grpcClient: SuiGrpcClient;
23
34
  /**
@@ -25,6 +25,8 @@ export { PythCoreRule } from "./rules/pyth-core-rule.ts";
25
25
  export type { PythCoreUpdatePayload } from "./rules/pyth-core-rule.ts";
26
26
  export { PythLazerRule, LazerApiKeyMissingError } from "./rules/pyth-lazer-rule.ts";
27
27
  export type { PythLazerUpdatePayload } from "./rules/pyth-lazer-rule.ts";
28
+ export { WaterxRule, parseSignedEnvelope } from "./rules/waterx-rule.ts";
29
+ export type { WaterxUpdatePayload, WaterxSignedEnvelope, WaterxBatchItem, } from "./rules/waterx-rule.ts";
28
30
  export { OracleSourceNotImplementedError } from "./rule-registry.ts";
29
31
  export { aggregateTicker, aggregateTickerWithPyth, aggregateTickerWithConstant, refreshOraclePrices, } from "./aggregate.ts";
30
32
  export { openPythSponsorFund, reimbursePythSponsor } from "./rules/sponsor.ts";
@@ -17,7 +17,7 @@
17
17
  * rules that consume it are separate concerns.
18
18
  */
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.reimbursePythSponsor = exports.openPythSponsorFund = exports.refreshOraclePrices = exports.aggregateTickerWithConstant = exports.aggregateTickerWithPyth = exports.aggregateTicker = exports.OracleSourceNotImplementedError = exports.LazerApiKeyMissingError = exports.PythLazerRule = exports.PythCoreRule = exports.OracleFeeSourceUnavailableError = exports.MISSING_FEED_MEMO_TTL_MS = exports.HermesEndpointRejectedAllFeedsError = exports.updatePythPrices = exports.buildPythPriceUpdateCalls = exports.probeMissingFeeds = exports.endpointSupportedFeedIds = exports.fetchPriceFeedsUpdateData = exports.PythCache = exports.joinEndpointPath = exports.fetchWithPolicy = exports.FetchPolicyError = void 0;
20
+ exports.reimbursePythSponsor = exports.openPythSponsorFund = exports.refreshOraclePrices = exports.aggregateTickerWithConstant = exports.aggregateTickerWithPyth = exports.aggregateTicker = exports.OracleSourceNotImplementedError = exports.parseSignedEnvelope = exports.WaterxRule = exports.LazerApiKeyMissingError = exports.PythLazerRule = exports.PythCoreRule = exports.OracleFeeSourceUnavailableError = exports.MISSING_FEED_MEMO_TTL_MS = exports.HermesEndpointRejectedAllFeedsError = exports.updatePythPrices = exports.buildPythPriceUpdateCalls = exports.probeMissingFeeds = exports.endpointSupportedFeedIds = exports.fetchPriceFeedsUpdateData = exports.PythCache = exports.joinEndpointPath = exports.fetchWithPolicy = exports.FetchPolicyError = void 0;
21
21
  // Shared fetch resilience wrapper — `FetchPolicyError` is re-exported (not
22
22
  // just the type) so a consumer (e.g. a BE prefetch cache) can `instanceof`
23
23
  // it off the failure `fetchPriceFeedsUpdateData` / `PythLazerRule` /
@@ -58,6 +58,11 @@ Object.defineProperty(exports, "PythCoreRule", { enumerable: true, get: function
58
58
  var pyth_lazer_rule_ts_1 = require("./rules/pyth-lazer-rule.js");
59
59
  Object.defineProperty(exports, "PythLazerRule", { enumerable: true, get: function () { return pyth_lazer_rule_ts_1.PythLazerRule; } });
60
60
  Object.defineProperty(exports, "LazerApiKeyMissingError", { enumerable: true, get: function () { return pyth_lazer_rule_ts_1.LazerApiKeyMissingError; } });
61
+ // WaterX quote-center rule (first-party ed25519 signed batches; `feedWaterxRule`
62
+ // stays internal to `aggregate.ts`).
63
+ var waterx_rule_ts_1 = require("./rules/waterx-rule.js");
64
+ Object.defineProperty(exports, "WaterxRule", { enumerable: true, get: function () { return waterx_rule_ts_1.WaterxRule; } });
65
+ Object.defineProperty(exports, "parseSignedEnvelope", { enumerable: true, get: function () { return waterx_rule_ts_1.parseSignedEnvelope; } });
61
66
  // `resolveOracleRule` (rule-registry.ts) is NOT re-exported here — it has one
62
67
  // production consumer (`refreshOraclePrices` below) and no external caller;
63
68
  // per repo convention ("no unused exports") it stays module-internal. Tests
@@ -24,11 +24,10 @@ export type PriceUpdateRuleKind = "pyth_rule" | "pyth_lazer_rule" | "supra_rule"
24
24
  * create option (see `OracleHost.oracleSource`) — i.e. rules that can serve as
25
25
  * the on-chain price *update* leg `refreshOraclePrices` runs before aggregating.
26
26
  * `supra_rule` and `constant_rule` are auxiliary rules fed alongside whichever
27
- * source is selected (see `aggregateTicker`), not sources themselves;
28
- * `waterx_rule` has no `PriceUpdateRule` implementation yet. The SDK never
29
- * reads `process.env` — consumers resolve their own env var to this type.
27
+ * source is selected (see `aggregateTicker`), not sources themselves. The SDK
28
+ * never reads `process.env` consumers resolve their own env var to this type.
30
29
  */
31
- export type OracleSource = "pyth_rule" | "pyth_lazer_rule";
30
+ export type OracleSource = "pyth_rule" | "pyth_lazer_rule" | "waterx_rule";
32
31
  /**
33
32
  * Off-chain payload fetched by a rule, tagged by `kind` so a caller holding
34
33
  * several rules' results can tell them apart. `payload` is `unknown` here —
@@ -7,13 +7,14 @@
7
7
  * option) — never by a config JSON `enabled` flag and never by `process.env`.
8
8
  *
9
9
  * Each source is self-contained: it owns its own infra + config and does NOT
10
- * back-stop any other source. Both are registered: `pyth_rule` (`PythCoreRule`,
11
- * Hermes VAA) and `pyth_lazer_rule` (`PythLazerRule`, Lazer signed updates).
12
- * Resolving a source with no registered rule throws a clear
13
- * `OracleSourceNotImplemented` error. There is deliberately no cross-source
14
- * fallback and no client-creation config guard: selecting a source whose feeds
15
- * are absent is not an error at init it surfaces at tx-build time for the
16
- * specific tickers that source can't serve (see `refreshOraclePrices`).
10
+ * back-stop any other source. Three are registered: `pyth_rule`
11
+ * (`PythCoreRule`, Hermes VAA), `pyth_lazer_rule` (`PythLazerRule`, Lazer
12
+ * signed updates), and `waterx_rule` (`WaterxRule`, first-party quote-center
13
+ * ed25519 signed batches). Resolving a source with no registered rule throws a
14
+ * clear `OracleSourceNotImplemented` error. There is deliberately no
15
+ * cross-source fallback and no client-creation config guard: selecting a source
16
+ * whose feeds are absent is not an error at init — it surfaces at tx-build time
17
+ * for the specific tickers that source can't serve (see `refreshOraclePrices`).
17
18
  */
18
19
  import type { OracleSource, PriceUpdateRule } from "./price-update-rule.ts";
19
20
  /**
@@ -8,19 +8,21 @@
8
8
  * option) — never by a config JSON `enabled` flag and never by `process.env`.
9
9
  *
10
10
  * Each source is self-contained: it owns its own infra + config and does NOT
11
- * back-stop any other source. Both are registered: `pyth_rule` (`PythCoreRule`,
12
- * Hermes VAA) and `pyth_lazer_rule` (`PythLazerRule`, Lazer signed updates).
13
- * Resolving a source with no registered rule throws a clear
14
- * `OracleSourceNotImplemented` error. There is deliberately no cross-source
15
- * fallback and no client-creation config guard: selecting a source whose feeds
16
- * are absent is not an error at init it surfaces at tx-build time for the
17
- * specific tickers that source can't serve (see `refreshOraclePrices`).
11
+ * back-stop any other source. Three are registered: `pyth_rule`
12
+ * (`PythCoreRule`, Hermes VAA), `pyth_lazer_rule` (`PythLazerRule`, Lazer
13
+ * signed updates), and `waterx_rule` (`WaterxRule`, first-party quote-center
14
+ * ed25519 signed batches). Resolving a source with no registered rule throws a
15
+ * clear `OracleSourceNotImplemented` error. There is deliberately no
16
+ * cross-source fallback and no client-creation config guard: selecting a source
17
+ * whose feeds are absent is not an error at init — it surfaces at tx-build time
18
+ * for the specific tickers that source can't serve (see `refreshOraclePrices`).
18
19
  */
19
20
  Object.defineProperty(exports, "__esModule", { value: true });
20
21
  exports.OracleSourceNotImplementedError = void 0;
21
22
  exports.resolveOracleRule = resolveOracleRule;
22
23
  const pyth_core_rule_ts_1 = require("./rules/pyth-core-rule.js");
23
24
  const pyth_lazer_rule_ts_1 = require("./rules/pyth-lazer-rule.js");
25
+ const waterx_rule_ts_1 = require("./rules/waterx-rule.js");
24
26
  /**
25
27
  * Production registry. Frozen — tests inject a fake rule via
26
28
  * `resolveOracleRule`'s `overrides` param instead of mutating this.
@@ -28,6 +30,7 @@ const pyth_lazer_rule_ts_1 = require("./rules/pyth-lazer-rule.js");
28
30
  const DEFAULT_RULES = Object.freeze({
29
31
  pyth_rule: pyth_core_rule_ts_1.PythCoreRule,
30
32
  pyth_lazer_rule: pyth_lazer_rule_ts_1.PythLazerRule,
33
+ waterx_rule: waterx_rule_ts_1.WaterxRule,
31
34
  });
32
35
  /**
33
36
  * Thrown by {@link resolveOracleRule} when `source` has no `PriceUpdateRule`
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `WaterxRule` — `PriceUpdateRule` for the first-party WaterX quote-center
3
+ * (Nautilus-TEE, ed25519), plus `feedWaterxRule`, the collector-feed leg
4
+ * `aggregateTicker` appends per waterx-routed ticker. Pulls one enclave-signed
5
+ * batch envelope covering every requested ticker from the quote-center
6
+ * (`GET /v1/quotes/update?symbols=…`, endpoint from `host.waterx` — the
7
+ * `waterxEndpoint`/`waterxFetch` create options — else `WATERX_DEFAULTS`), then —
8
+ * unlike Pyth Lazer, whose verify is a single shared PTB step — verifies AND
9
+ * feeds in ONE `waterx_rule::collect_batch_latest` call per collector (the Move
10
+ * API bundles the two). So `buildUpdateCalls` emits nothing and the signed
11
+ * envelope is handed straight to the per-ticker feed leg.
12
+ *
13
+ * `collect_batch_latest` is the dual-rule path: it feeds the item matching
14
+ * `collector.symbol()` WITHOUT aggregating, so a waterx-routed ticker composes
15
+ * onto the same collector as Pyth/Supra (compose-then-aggregate). On-chain a
16
+ * freshness miss / replayed timestamp ABSTAINS (the other weighted rules
17
+ * cover); a config/integrity mismatch or bad signature aborts.
18
+ */
19
+ import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
20
+ import type { OracleHost } from "../host.ts";
21
+ import { type PriceUpdateRule, type RuleUpdateData } from "../price-update-rule.ts";
22
+ /**
23
+ * One item inside a signed batch payload, mirroring the quote-center
24
+ * `/v1/quotes/update` JSON 1:1 (snake_case). The u64 integer fields are the
25
+ * EXACT values the enclave signed over BCS — `collect_batch_latest` rebuilds
26
+ * the payload on-chain and re-verifies, so they must round-trip byte-for-byte.
27
+ * They are `bigint` (not `number`): {@link parseSignedEnvelope} decodes them
28
+ * from the raw JSON integer literals so a value above `Number.MAX_SAFE_INTEGER`
29
+ * (2^53) can never lose precision and silently abort the on-chain signature
30
+ * check. `num_sources` is a `u8` (≤ 255) and stays a `number`.
31
+ */
32
+ export interface WaterxBatchItem {
33
+ symbol: string;
34
+ ticker: string;
35
+ sources: bigint[];
36
+ method: string;
37
+ price_timestamp_ms: bigint;
38
+ price_n: bigint;
39
+ price_scale: bigint;
40
+ confidence_n: bigint;
41
+ confidence_scale: bigint;
42
+ max_source_deviation_bps: bigint;
43
+ num_sources: number;
44
+ }
45
+ /** The enclave-signed batch envelope from `GET /v1/quotes/update`. */
46
+ export interface WaterxSignedEnvelope {
47
+ intent: number;
48
+ /** Enclave signing timestamp (ms) — the on-chain `timestamp_ms` argument. */
49
+ timestamp_ms: bigint;
50
+ payload: {
51
+ items: WaterxBatchItem[];
52
+ };
53
+ /** ed25519 signature over `BCS(IntentMessage<BatchPricePayload>)`, hex (± `0x`). */
54
+ signature: string;
55
+ }
56
+ /** `waterx_rule`'s narrowed `RuleUpdateData.payload` shape. */
57
+ export interface WaterxUpdatePayload {
58
+ readonly envelope: WaterxSignedEnvelope;
59
+ }
60
+ /**
61
+ * Parse a quote-center `/v1/quotes/update` response body into a
62
+ * {@link WaterxSignedEnvelope} with the u64 fields decoded as `bigint`, exact.
63
+ *
64
+ * The signature is over `BCS(IntentMessage<BatchPricePayload>)`, so every u64
65
+ * the SDK rebuilds in-PTB must equal the enclave's byte-for-byte or
66
+ * `collect_batch_latest` aborts the whole trade PTB (bad signature — not an
67
+ * abstain). A plain `JSON.parse` yields IEEE-754 doubles that lose precision
68
+ * above 2^53, so instead we recover each integer's exact source literal via the
69
+ * ES2023 reviver `context.source` (Node 21+ / modern browsers) and `BigInt()`
70
+ * it. On an older runtime that passes no `context`, a value within 2^53 is
71
+ * still exact (`BigInt(number)`); a value ABOVE it throws loudly here rather
72
+ * than silently corrupting the payload into an on-chain abort. `num_sources`
73
+ * (u8) and `intent` are coerced back to `number` — both are tiny.
74
+ */
75
+ export declare function parseSignedEnvelope(text: string): WaterxSignedEnvelope;
76
+ /** Narrow a `RuleUpdateData` to its `WaterxSignedEnvelope`, or `null`. */
77
+ export declare function waterxEnvelopeOf(data: RuleUpdateData): WaterxSignedEnvelope | null;
78
+ /**
79
+ * `waterx_rule::collect_batch_latest(collector, config, clock, enclave_config,
80
+ * enclave, timestamp_ms, payload, sig)` — rebuild the enclave-signed batch
81
+ * payload in-PTB (`new_batch_payload` + one `new_batch_item`/`push_batch_item`
82
+ * per item, the exact shape the enclave signed) and contribute the price for
83
+ * `collector.symbol()` to the collector. One collect call re-verifies the batch
84
+ * signature and picks this collector's symbol out of the batch; on-chain it
85
+ * abstains (records `none`) instead of aborting when the symbol is stale,
86
+ * absent from the batch, or its timestamp was already accepted (replay).
87
+ */
88
+ export declare function feedWaterxRule(tx: Transaction, host: OracleHost, collector: TransactionArgument, envelope: WaterxSignedEnvelope): void;
89
+ export declare const WaterxRule: PriceUpdateRule;