@waterx/sdk 4.0.1 → 4.3.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 (130) hide show
  1. package/README.md +37 -17
  2. package/dist/cjs/src/account/account.js +2 -1
  3. package/dist/cjs/src/account/config.d.ts +3 -2
  4. package/dist/cjs/src/account/funding/balance.d.ts +25 -2
  5. package/dist/cjs/src/account/funding/balance.js +36 -24
  6. package/dist/cjs/src/account/funding/credit.js +6 -10
  7. package/dist/cjs/src/constants.d.ts +15 -1
  8. package/dist/cjs/src/constants.js +18 -4
  9. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  10. package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +13 -0
  11. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  12. package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.js +31 -0
  13. package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
  14. package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +946 -0
  15. package/dist/cjs/src/oracle/aggregate.d.ts +23 -21
  16. package/dist/cjs/src/oracle/aggregate.js +133 -59
  17. package/dist/cjs/src/oracle/config.d.ts +82 -41
  18. package/dist/cjs/src/oracle/config.js +0 -42
  19. package/dist/cjs/src/oracle/host.d.ts +26 -11
  20. package/dist/cjs/src/oracle/index.d.ts +6 -2
  21. package/dist/cjs/src/oracle/index.js +36 -8
  22. package/dist/cjs/src/oracle/price-update-rule.d.ts +16 -10
  23. package/dist/cjs/src/oracle/price-update-rule.js +3 -3
  24. package/dist/cjs/src/oracle/pyth.d.ts +44 -0
  25. package/dist/cjs/src/oracle/pyth.js +48 -6
  26. package/dist/cjs/src/oracle/read-plane.d.ts +70 -0
  27. package/dist/cjs/src/oracle/read-plane.js +78 -0
  28. package/dist/cjs/src/oracle/rule-registry.d.ts +14 -11
  29. package/dist/cjs/src/oracle/rule-registry.js +16 -11
  30. package/dist/cjs/src/oracle/rules/pyth-core-rule.js +4 -4
  31. package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
  32. package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +29 -4
  33. package/dist/cjs/src/oracle/rules/pyth-rule.js +5 -4
  34. package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +126 -0
  35. package/dist/cjs/src/oracle/rules/waterx-rule.js +312 -0
  36. package/dist/cjs/src/perp/client.d.ts +71 -20
  37. package/dist/cjs/src/perp/client.js +35 -13
  38. package/dist/cjs/src/perp/config.d.ts +6 -7
  39. package/dist/cjs/src/perp/config.js +12 -11
  40. package/dist/cjs/src/perp/constants.d.ts +0 -6
  41. package/dist/cjs/src/perp/constants.js +11 -9
  42. package/dist/cjs/src/perp/fetch/account.js +3 -0
  43. package/dist/cjs/src/perp/fetch/bridge.js +2 -1
  44. package/dist/cjs/src/perp/fetch/market.js +2 -1
  45. package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
  46. package/dist/cjs/src/perp/fetch/positions.js +23 -20
  47. package/dist/cjs/src/perp/index.d.ts +9 -5
  48. package/dist/cjs/src/perp/index.js +16 -7
  49. package/dist/cjs/src/perp/liq-view.d.ts +64 -0
  50. package/dist/cjs/src/perp/liq-view.js +74 -0
  51. package/dist/cjs/src/perp/user/order.d.ts +13 -0
  52. package/dist/cjs/src/perp/user/order.js +30 -16
  53. package/dist/cjs/src/perp/user/staking.js +3 -2
  54. package/dist/cjs/src/perp/user/trading.js +25 -24
  55. package/dist/cjs/src/perp/user/wlp.js +6 -5
  56. package/dist/cjs/src/prediction/utils.d.ts +11 -2
  57. package/dist/cjs/src/prediction/utils.js +22 -22
  58. package/dist/cjs/src/unified-client.d.ts +41 -15
  59. package/dist/cjs/src/unified-client.js +4 -2
  60. package/dist/cjs/src/utils/format.d.ts +14 -0
  61. package/dist/cjs/src/utils/format.js +24 -0
  62. package/dist/cjs/src/utils/math.d.ts +304 -12
  63. package/dist/cjs/src/utils/math.js +397 -17
  64. package/dist/cjs/src/utils/validate.d.ts +69 -0
  65. package/dist/cjs/src/utils/validate.js +183 -0
  66. package/dist/src/account/account.js +2 -1
  67. package/dist/src/account/config.d.ts +3 -2
  68. package/dist/src/account/funding/balance.d.ts +25 -2
  69. package/dist/src/account/funding/balance.js +36 -24
  70. package/dist/src/account/funding/credit.js +6 -10
  71. package/dist/src/constants.d.ts +15 -1
  72. package/dist/src/constants.js +17 -3
  73. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
  74. package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
  75. package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
  76. package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
  77. package/dist/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
  78. package/dist/src/generated/waterx_rule/waterx_rule.js +855 -0
  79. package/dist/src/oracle/aggregate.d.ts +23 -21
  80. package/dist/src/oracle/aggregate.js +133 -59
  81. package/dist/src/oracle/config.d.ts +82 -41
  82. package/dist/src/oracle/config.js +1 -41
  83. package/dist/src/oracle/host.d.ts +26 -11
  84. package/dist/src/oracle/index.d.ts +6 -2
  85. package/dist/src/oracle/index.js +27 -9
  86. package/dist/src/oracle/price-update-rule.d.ts +16 -10
  87. package/dist/src/oracle/price-update-rule.js +3 -3
  88. package/dist/src/oracle/pyth.d.ts +44 -0
  89. package/dist/src/oracle/pyth.js +45 -5
  90. package/dist/src/oracle/read-plane.d.ts +70 -0
  91. package/dist/src/oracle/read-plane.js +74 -0
  92. package/dist/src/oracle/rule-registry.d.ts +14 -11
  93. package/dist/src/oracle/rule-registry.js +16 -11
  94. package/dist/src/oracle/rules/pyth-core-rule.js +5 -5
  95. package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
  96. package/dist/src/oracle/rules/pyth-lazer-rule.js +28 -3
  97. package/dist/src/oracle/rules/pyth-rule.js +5 -4
  98. package/dist/src/oracle/rules/waterx-rule.d.ts +126 -0
  99. package/dist/src/oracle/rules/waterx-rule.js +305 -0
  100. package/dist/src/perp/client.d.ts +71 -20
  101. package/dist/src/perp/client.js +36 -14
  102. package/dist/src/perp/config.d.ts +6 -7
  103. package/dist/src/perp/config.js +11 -9
  104. package/dist/src/perp/constants.d.ts +0 -6
  105. package/dist/src/perp/constants.js +10 -8
  106. package/dist/src/perp/fetch/account.js +3 -0
  107. package/dist/src/perp/fetch/bridge.js +2 -1
  108. package/dist/src/perp/fetch/market.js +2 -1
  109. package/dist/src/perp/fetch/positions.d.ts +16 -10
  110. package/dist/src/perp/fetch/positions.js +28 -20
  111. package/dist/src/perp/index.d.ts +9 -5
  112. package/dist/src/perp/index.js +6 -4
  113. package/dist/src/perp/liq-view.d.ts +64 -0
  114. package/dist/src/perp/liq-view.js +71 -0
  115. package/dist/src/perp/user/order.d.ts +13 -0
  116. package/dist/src/perp/user/order.js +30 -16
  117. package/dist/src/perp/user/staking.js +3 -2
  118. package/dist/src/perp/user/trading.js +25 -24
  119. package/dist/src/perp/user/wlp.js +6 -5
  120. package/dist/src/prediction/utils.d.ts +11 -2
  121. package/dist/src/prediction/utils.js +22 -22
  122. package/dist/src/unified-client.d.ts +41 -15
  123. package/dist/src/unified-client.js +4 -2
  124. package/dist/src/utils/format.d.ts +14 -0
  125. package/dist/src/utils/format.js +21 -0
  126. package/dist/src/utils/math.d.ts +304 -12
  127. package/dist/src/utils/math.js +394 -17
  128. package/dist/src/utils/validate.d.ts +69 -0
  129. package/dist/src/utils/validate.js +167 -0
  130. package/package.json +4 -1
@@ -18,13 +18,17 @@
18
18
  export type { OracleHost } from "./host.ts";
19
19
  export { FetchPolicyError, fetchWithPolicy, joinEndpointPath } from "./update-fetch.ts";
20
20
  export type { FetchPolicy } from "./update-fetch.ts";
21
- export { PythCache, fetchPriceFeedsUpdateData, endpointSupportedFeedIds, probeMissingFeeds, buildPythPriceUpdateCalls, updatePythPrices, HermesEndpointRejectedAllFeedsError, MISSING_FEED_MEMO_TTL_MS, OracleFeeSourceUnavailableError, } from "./pyth.ts";
21
+ export { PythCache, fetchPriceFeedsUpdateData, endpointSupportedFeedIds, probeMissingFeeds, buildPythPriceUpdateCalls, pythCoreHermesEndpoint, pythProHermesEndpoint, PYTH_PRO_HERMES_ENDPOINT, updatePythPrices, HermesEndpointRejectedAllFeedsError, MISSING_FEED_MEMO_TTL_MS, OracleFeeSourceUnavailableError, } from "./pyth.ts";
22
22
  export type { OracleFeeSource } from "./pyth.ts";
23
23
  export type { PriceUpdateRule, PriceUpdateRuleKind, RuleUpdateData, RuleUpdateHandle, BuildUpdateOpts, OracleSource, UpdateDataProvider, } from "./price-update-rule.ts";
24
+ export { resolveOracleReadPlan, resolveHermesReadEndpoint } from "./read-plane.ts";
25
+ export type { OracleReadPlan } from "./read-plane.ts";
24
26
  export { PythCoreRule } from "./rules/pyth-core-rule.ts";
25
27
  export type { PythCoreUpdatePayload } from "./rules/pyth-core-rule.ts";
26
28
  export { PythLazerRule, LazerApiKeyMissingError } from "./rules/pyth-lazer-rule.ts";
27
29
  export type { PythLazerUpdatePayload } from "./rules/pyth-lazer-rule.ts";
28
- export { OracleSourceNotImplementedError } from "./rule-registry.ts";
30
+ export { WaterxRule, parseSignedEnvelope, BATCH_PRICE_INTENT, WATERX_INFRA, waterxQuoteCenterEndpoint, } from "./rules/waterx-rule.ts";
31
+ export type { WaterxUpdatePayload, WaterxSignedEnvelope, WaterxBatchItem, } from "./rules/waterx-rule.ts";
32
+ export { OracleSourceNotImplementedError, resolveOracleRule } from "./rule-registry.ts";
29
33
  export { aggregateTicker, aggregateTickerWithPyth, aggregateTickerWithConstant, refreshOraclePrices, } from "./aggregate.ts";
30
34
  export { openPythSponsorFund, reimbursePythSponsor } from "./rules/sponsor.ts";
@@ -33,21 +33,39 @@ export { FetchPolicyError, fetchWithPolicy, joinEndpointPath } from "./update-fe
33
33
  // branch on the fee-source failure directly, and a consumer of
34
34
  // `fetchPriceFeedsUpdateData` / `probeMissingFeeds` can tell a misconfigured
35
35
  // or unentitled endpoint apart from feeds that endpoint genuinely lacks.
36
- export { PythCache, fetchPriceFeedsUpdateData, endpointSupportedFeedIds, probeMissingFeeds, buildPythPriceUpdateCalls, updatePythPrices, HermesEndpointRejectedAllFeedsError, MISSING_FEED_MEMO_TTL_MS, OracleFeeSourceUnavailableError, } from "./pyth.js";
36
+ export { PythCache, fetchPriceFeedsUpdateData, endpointSupportedFeedIds, probeMissingFeeds, buildPythPriceUpdateCalls,
37
+ // The pyth read-plane endpoint accessors — Core (keyless, per network) and
38
+ // Pro (the documented fixed base; auth via the caller's Bearer key). There
39
+ // is no client-level endpoint field: consumers pick via
40
+ // `resolveHermesReadEndpoint` (pyth_rule listed → Core, else override ??
41
+ // Pro) — never a hand-rolled branch, never a cross-source fallback.
42
+ pythCoreHermesEndpoint, pythProHermesEndpoint, PYTH_PRO_HERMES_ENDPOINT, updatePythPrices, HermesEndpointRejectedAllFeedsError, MISSING_FEED_MEMO_TTL_MS, OracleFeeSourceUnavailableError, } from "./pyth.js";
43
+ // Per-source READ-plane resolution — which tickers a source can price
44
+ // off-chain and with which ids (`resolveOracleReadPlan`), and which
45
+ // Hermes-compatible base the hermes plans execute against
46
+ // (`resolveHermesReadEndpoint`: pyth_rule listed → Core, else override ??
47
+ // the documented Pyth Pro base). The one place the "lazer reads through
48
+ // `pyth_rule.feeds` hex ids" invariant lives; consumers resolve through
49
+ // this instead of hardcoding namespace sharing or endpoint branching.
50
+ export { resolveOracleReadPlan, resolveHermesReadEndpoint } from "./read-plane.js";
37
51
  // Pyth Core rule (PriceUpdateRule wrapper over the Pyth source above)
38
52
  export { PythCoreRule } from "./rules/pyth-core-rule.js";
39
53
  // Pyth Lazer rule (signed-update generation; `feedLazerRule` stays internal to `aggregate.ts`)
40
54
  // `LazerApiKeyMissingError` is re-exported (not just the type) for the same
41
55
  // `instanceof` reason as `OracleFeeSourceUnavailableError` above.
42
56
  export { PythLazerRule, LazerApiKeyMissingError } from "./rules/pyth-lazer-rule.js";
43
- // `resolveOracleRule` (rule-registry.ts) is NOT re-exported here it has one
44
- // production consumer (`refreshOraclePrices` below) and no external caller;
45
- // per repo convention ("no unused exports") it stays module-internal. Tests
46
- // import it directly from `./rule-registry.ts`. `OracleSourceNotImplementedError`
47
- // IS re-exported (the same `instanceof` reason as `OracleFeeSourceUnavailableError`
48
- // above) a consumer of `refreshOraclePrices` can catch it without importing
49
- // `resolveOracleRule` itself.
50
- export { OracleSourceNotImplementedError } from "./rule-registry.js";
57
+ // `WATERX_INFRA` / `waterxQuoteCenterEndpoint` are the source's own infra table +
58
+ // read-plane accessor (mirrors `pythCoreHermesEndpoint`).
59
+ // WaterX quote-center rule (first-party ed25519 signed batches; `feedWaterxRule`
60
+ // stays internal to `aggregate.ts`).
61
+ export { WaterxRule, parseSignedEnvelope, BATCH_PRICE_INTENT, WATERX_INFRA, waterxQuoteCenterEndpoint, } from "./rules/waterx-rule.js";
62
+ // `resolveOracleRule` is the ONE source→rule registry exported so external
63
+ // consumers (e.g. a BE prefetch cache that keys per source and needs each
64
+ // source's `supportedTickers`/`fetchUpdateData`) resolve through it instead of
65
+ // hand-mirroring the map and drifting. `OracleSourceNotImplementedError` is
66
+ // its `instanceof`-able failure (same reason as `OracleFeeSourceUnavailableError`
67
+ // above).
68
+ export { OracleSourceNotImplementedError, resolveOracleRule } from "./rule-registry.js";
51
69
  // Aggregation orchestrator
52
70
  export { aggregateTicker, aggregateTickerWithPyth, aggregateTickerWithConstant, refreshOraclePrices, } from "./aggregate.js";
53
71
  // Sponsor rule (fund open / reimburse + witness attach)
@@ -11,24 +11,23 @@
11
11
  * remain plain collector-feed helpers wired directly into `aggregate.ts`.
12
12
  *
13
13
  * This file defines the port only — routing IS wired: `aggregate.ts`'s
14
- * `refreshOraclePrices` selects the concrete rule per `host.oracleSource` via
15
- * `rule-registry.ts`, then drives fetch + `buildUpdateCalls` through this
16
- * port; `aggregate.ts` stays the sole orchestrator.
14
+ * `refreshOraclePrices` resolves a concrete rule per `host.oracleSources`
15
+ * entry via `rule-registry.ts`, then drives fetch + `buildUpdateCalls`
16
+ * through this port; `aggregate.ts` stays the sole orchestrator.
17
17
  */
18
18
  import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
19
19
  import type { OracleHost } from "./host.ts";
20
20
  import type { OracleFeeSource, PythCache } from "./pyth.ts";
21
21
  export type PriceUpdateRuleKind = "pyth_rule" | "pyth_lazer_rule" | "supra_rule" | "constant_rule" | "waterx_rule";
22
22
  /**
23
- * The subset of `PriceUpdateRuleKind`s selectable via a client's `oracleSource`
24
- * create option (see `OracleHost.oracleSource`) — i.e. rules that can serve as
23
+ * The subset of `PriceUpdateRuleKind`s listable in a client's `oracleSource`
24
+ * create option (see `OracleHost.oracleSources`) — 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 —
@@ -117,7 +116,14 @@ export interface UpdateDataProvider {
117
116
  get(source: OracleSource, tickers: string[]): Promise<RuleUpdateData | null>;
118
117
  }
119
118
  export interface PriceUpdateRule {
120
- readonly kind: PriceUpdateRuleKind;
119
+ /**
120
+ * `OracleSource`, not the wider `PriceUpdateRuleKind`: only selectable
121
+ * sources implement this port (`supra_rule`/`constant_rule` are plain
122
+ * collector-feed helpers), and the narrower type is what lets
123
+ * `refreshOraclePrices`'s per-source carry step switch exhaustively —
124
+ * adding a source without deciding its carry becomes a compile error.
125
+ */
126
+ readonly kind: OracleSource;
121
127
  /**
122
128
  * `true` when this rule's on-chain update leg charges a per-update fee
123
129
  * that must be paid from either a sponsor fund or `tx.gas` (Pyth Core:
@@ -11,9 +11,9 @@
11
11
  * remain plain collector-feed helpers wired directly into `aggregate.ts`.
12
12
  *
13
13
  * This file defines the port only — routing IS wired: `aggregate.ts`'s
14
- * `refreshOraclePrices` selects the concrete rule per `host.oracleSource` via
15
- * `rule-registry.ts`, then drives fetch + `buildUpdateCalls` through this
16
- * port; `aggregate.ts` stays the sole orchestrator.
14
+ * `refreshOraclePrices` resolves a concrete rule per `host.oracleSources`
15
+ * entry via `rule-registry.ts`, then drives fetch + `buildUpdateCalls`
16
+ * through this port; `aggregate.ts` stays the sole orchestrator.
17
17
  */
18
18
  /**
19
19
  * Shared null → kind → shape guard ladder for a `PriceUpdateRule.buildUpdateCalls`
@@ -14,8 +14,52 @@
14
14
  * 4. hot_potato_vector::destroy
15
15
  */
16
16
  import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
17
+ import type { Network } from "../constants.ts";
17
18
  import type { PythFetchPolicy } from "./config.ts";
18
19
  import type { OracleHost } from "./host.ts";
20
+ /**
21
+ * Everything the Core source needs that is not in the canonical
22
+ * `waterx-config` JSON lives HERE, in the source that consumes it —
23
+ * `client.pyth` carries only the caller's credential/fetch policy
24
+ * (see `PythAccessConfig`). No other oracle source reads this table:
25
+ * selecting `pyth_lazer_rule` (or any future source) must never touch a Core
26
+ * endpoint or Core state object, so nothing Core-shaped stays on the shared
27
+ * client to leak across sources.
28
+ *
29
+ * - `state_id` / `wormhole_state_id` — the Core Pyth + Wormhole state objects
30
+ * the on-chain update PTB reads (below).
31
+ * - `hermes_endpoint` — the Core Hermes REST base for
32
+ * `fetchPriceFeedsUpdateData`. Keyless today; auth-first after the Pyth Pro
33
+ * migration (post-2026-08-18) via `client.pyth.api_key`.
34
+ */
35
+ export interface PythCoreInfra {
36
+ state_id: string;
37
+ wormhole_state_id: string;
38
+ hermes_endpoint: string;
39
+ }
40
+ export declare const PYTH_CORE_INFRA: Record<Network, PythCoreInfra>;
41
+ /**
42
+ * The Core source's Hermes REST base for `network` — for consumers (BE/FE
43
+ * read planes) whose `ORACLE_SOURCE` fed set includes `'pyth_rule'`. A fed
44
+ * set WITHOUT `pyth_rule` reads the keyed Pyth Pro base instead — resolve
45
+ * through `resolveHermesReadEndpoint` (`oracle/read-plane.ts`) rather than
46
+ * branching by hand.
47
+ */
48
+ export declare function pythCoreHermesEndpoint(network: Network): string;
49
+ /**
50
+ * The Pyth Pro Hermes-compatible REST base — the documented drop-in
51
+ * replacement for the Core endpoint (`https://pyth.dourolabs.app/hermes/…`),
52
+ * IDENTICAL for every subscriber: only the `Authorization: Bearer` key
53
+ * (`client.pyth.api_key` / the `pythApiKey` create option) is
54
+ * account-specific, so the URL is SDK infra, not deployment config. One base
55
+ * for both networks — Pro has no testnet variant (Pyth feed ids are
56
+ * chain-agnostic; `hermes-beta` is a Core-testnet concern). Consumers with a
57
+ * proxy/self-hosted mirror override it per deployment via
58
+ * `resolveHermesReadEndpoint`'s `override` param.
59
+ */
60
+ export declare const PYTH_PRO_HERMES_ENDPOINT = "https://pyth.dourolabs.app/hermes";
61
+ /** Accessor mirror of {@link pythCoreHermesEndpoint} for the Pro base. */
62
+ export declare function pythProHermesEndpoint(): string;
19
63
  type PriceTableInfo = {
20
64
  id: string;
21
65
  fieldType: string;
@@ -16,6 +16,44 @@
16
16
  import { fromHex, toHex } from "@mysten/bcs";
17
17
  import { bcs } from "@mysten/sui/bcs";
18
18
  import { fetchWithPolicy, joinEndpointPath, rethrowExhaustedFetch, trimTrailingSlashes, } from "./update-fetch.js";
19
+ export const PYTH_CORE_INFRA = {
20
+ MAINNET: {
21
+ state_id: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
22
+ wormhole_state_id: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
23
+ hermes_endpoint: "https://hermes.pyth.network",
24
+ },
25
+ TESTNET: {
26
+ state_id: "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c",
27
+ wormhole_state_id: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
28
+ hermes_endpoint: "https://hermes-beta.pyth.network",
29
+ },
30
+ };
31
+ /**
32
+ * The Core source's Hermes REST base for `network` — for consumers (BE/FE
33
+ * read planes) whose `ORACLE_SOURCE` fed set includes `'pyth_rule'`. A fed
34
+ * set WITHOUT `pyth_rule` reads the keyed Pyth Pro base instead — resolve
35
+ * through `resolveHermesReadEndpoint` (`oracle/read-plane.ts`) rather than
36
+ * branching by hand.
37
+ */
38
+ export function pythCoreHermesEndpoint(network) {
39
+ return PYTH_CORE_INFRA[network].hermes_endpoint;
40
+ }
41
+ /**
42
+ * The Pyth Pro Hermes-compatible REST base — the documented drop-in
43
+ * replacement for the Core endpoint (`https://pyth.dourolabs.app/hermes/…`),
44
+ * IDENTICAL for every subscriber: only the `Authorization: Bearer` key
45
+ * (`client.pyth.api_key` / the `pythApiKey` create option) is
46
+ * account-specific, so the URL is SDK infra, not deployment config. One base
47
+ * for both networks — Pro has no testnet variant (Pyth feed ids are
48
+ * chain-agnostic; `hermes-beta` is a Core-testnet concern). Consumers with a
49
+ * proxy/self-hosted mirror override it per deployment via
50
+ * `resolveHermesReadEndpoint`'s `override` param.
51
+ */
52
+ export const PYTH_PRO_HERMES_ENDPOINT = "https://pyth.dourolabs.app/hermes";
53
+ /** Accessor mirror of {@link pythCoreHermesEndpoint} for the Pro base. */
54
+ export function pythProHermesEndpoint() {
55
+ return PYTH_PRO_HERMES_ENDPOINT;
56
+ }
19
57
  export class PythCache {
20
58
  pythStateInfo;
21
59
  wormholePackageId;
@@ -428,7 +466,7 @@ async function getPriceTableInfo(client, pythStateId, cache) {
428
466
  }
429
467
  async function getPriceFeedObjectId(client, table, feedId, cache, pythStateId) {
430
468
  const normalized = feedId.replace(/^0x/, "");
431
- const cacheKey = pythStateId ? `${pythStateId}:${normalized}` : normalized;
469
+ const cacheKey = `${pythStateId}:${normalized}`;
432
470
  if (cache?.priceFeedObjectIdCache.has(cacheKey)) {
433
471
  return cache.priceFeedObjectIdCache.get(cacheKey);
434
472
  }
@@ -523,7 +561,9 @@ export async function buildPythPriceUpdateCalls(tx, host, updates, feedIds, opts
523
561
  throw new OracleFeeSourceUnavailableError();
524
562
  }
525
563
  const cache = opts?.cache;
526
- const pyth = host.pyth;
564
+ // Core on-chain infra is the `pyth_rule` source's own table, keyed by the
565
+ // host's network — `client.pyth` carries only the caller's credential/policy.
566
+ const pyth = PYTH_CORE_INFRA[host.network];
527
567
  const [stateInfo, wormholePackageId, table] = await Promise.all([
528
568
  getPythStateInfo(host.grpcClient, pyth.state_id, cache),
529
569
  getWormholePackageId(host.grpcClient, pyth.wormhole_state_id, cache),
@@ -581,9 +621,9 @@ export async function buildPythPriceUpdateCalls(tx, host, updates, feedIds, opts
581
621
  }
582
622
  /** All-in-one: fetch from Hermes, append update calls. Returns PriceInfoObject IDs. */
583
623
  export async function updatePythPrices(tx, host, feedIds, opts) {
584
- // `host.pyth` is the Pyth Core infra (fixed per network) plus the caller's
585
- // api_key/fetch endpoint, credential and policy all come from it.
586
- const endpoint = host.pyth.hermes_endpoint;
624
+ // The Core source's own Hermes endpoint (per-network, rule-owned table);
625
+ // credential + fetch policy are the caller-supplied `client.pyth` slice.
626
+ const endpoint = PYTH_CORE_INFRA[host.network].hermes_endpoint;
587
627
  const updates = await fetchPriceFeedsUpdateData(endpoint, feedIds, {
588
628
  apiKey: host.pyth.api_key,
589
629
  fetch: host.pyth.fetch,
@@ -0,0 +1,70 @@
1
+ /**
2
+ * `read-plane.ts` — per-source READ-plane resolution: which of a caller's
3
+ * tickers a source can PRICE off-chain, and with which ids. The write plane
4
+ * (`PriceUpdateRule` + each source's `feeds` block) and the read plane are
5
+ * DIFFERENT namespaces for the pyth sources: Lazer WRITES with the integer
6
+ * ids in `pyth_lazer_rule.feeds`, but every Hermes-compatible price READ is
7
+ * keyed by the hex ids only `pyth_rule.feeds` carries. That cross-block
8
+ * dependency is a config invariant ("a lazer-fed ticker must also carry a
9
+ * Core hex entry to be read-visible"), and it lives HERE, once — consumers
10
+ * (FE/BE price facades) resolve through this instead of hardcoding which
11
+ * sources share which feeds namespace.
12
+ */
13
+ import type { Network } from "../constants.ts";
14
+ import type { OracleHost } from "./host.ts";
15
+ import type { OracleSource } from "./price-update-rule.ts";
16
+ /**
17
+ * One source's read plan for a requested ticker set.
18
+ *
19
+ * - `plane: "hermes"` (pyth sources) — price via a Hermes-compatible REST
20
+ * endpoint, one entry per servable ticker mapped to its HEX feed id. The
21
+ * endpoint to execute against is {@link resolveHermesReadEndpoint} — the
22
+ * plan (ids) plus that resolver (host) is the complete read contract.
23
+ * - `plane: "quote_center"` (waterx) — price via the quote-center symbols
24
+ * api, keyed by ticker; served set = the `waterx_rule.feeds` block. An
25
+ * ABSENT block (source listed, package missing from the loaded config)
26
+ * serves NOTHING: claiming tickers would silently reroute reads to the
27
+ * quote-center — it happily serves symbols regardless of on-chain config —
28
+ * and swallow tickers a later-listed source could price. The
29
+ * misconfiguration is caught loudly by the consumer's feeds assert at
30
+ * client creation instead.
31
+ * - `unreadable` — requested tickers this source WRITES on-chain (its update
32
+ * leg serves them) but its read plane cannot price: the silent-invisibility
33
+ * trap (e.g. a lazer-fed ticker with no `pyth_rule.feeds` hex entry).
34
+ * Callers should surface these loudly; empty for sources whose write and
35
+ * read namespaces coincide.
36
+ */
37
+ export type OracleReadPlan = {
38
+ unreadable: string[];
39
+ } & ({
40
+ plane: "hermes";
41
+ feedIdByTicker: Map<string, string>;
42
+ } | {
43
+ plane: "quote_center";
44
+ tickers: string[];
45
+ });
46
+ /**
47
+ * Resolve `source`'s read plan for `tickers`. Pure config lookup — no
48
+ * network, no endpoint resolution (endpoints come from
49
+ * `pythCoreHermesEndpoint` / `waterxQuoteCenterEndpoint` / the deployment's
50
+ * own env). A ticker absent from the returned plan is simply not servable by
51
+ * THIS source's read plane — callers decide how to degrade (typically: ask
52
+ * the next source in their `ORACLE_SOURCE` list, then omit).
53
+ */
54
+ /**
55
+ * The Hermes-compatible REST base a deployment's hermes-plane read plans
56
+ * execute against — the endpoint half of the read contract
57
+ * ({@link resolveOracleReadPlan} is the ids half):
58
+ *
59
+ * - `pyth_rule` in the fed set → the Core source's own keyless endpoint
60
+ * (`pythCoreHermesEndpoint(network)`).
61
+ * - otherwise → `override` when the deployment set one (a proxy or
62
+ * self-hosted mirror), else the documented Pyth Pro base
63
+ * (`pythProHermesEndpoint()` — identical for every subscriber; auth is the
64
+ * caller's `pythApiKey` Bearer, not a per-deployment URL).
65
+ *
66
+ * Total — never throws, never falls back Core-ward: a fed set without
67
+ * `pyth_rule` reads Pro (or the override), full stop.
68
+ */
69
+ export declare function resolveHermesReadEndpoint(network: Network, sources: readonly OracleSource[], override?: string): string;
70
+ export declare function resolveOracleReadPlan(host: OracleHost, source: OracleSource, tickers: string[]): OracleReadPlan;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `read-plane.ts` — per-source READ-plane resolution: which of a caller's
3
+ * tickers a source can PRICE off-chain, and with which ids. The write plane
4
+ * (`PriceUpdateRule` + each source's `feeds` block) and the read plane are
5
+ * DIFFERENT namespaces for the pyth sources: Lazer WRITES with the integer
6
+ * ids in `pyth_lazer_rule.feeds`, but every Hermes-compatible price READ is
7
+ * keyed by the hex ids only `pyth_rule.feeds` carries. That cross-block
8
+ * dependency is a config invariant ("a lazer-fed ticker must also carry a
9
+ * Core hex entry to be read-visible"), and it lives HERE, once — consumers
10
+ * (FE/BE price facades) resolve through this instead of hardcoding which
11
+ * sources share which feeds namespace.
12
+ */
13
+ import { pythCoreHermesEndpoint, pythProHermesEndpoint } from "./pyth.js";
14
+ /**
15
+ * Resolve `source`'s read plan for `tickers`. Pure config lookup — no
16
+ * network, no endpoint resolution (endpoints come from
17
+ * `pythCoreHermesEndpoint` / `waterxQuoteCenterEndpoint` / the deployment's
18
+ * own env). A ticker absent from the returned plan is simply not servable by
19
+ * THIS source's read plane — callers decide how to degrade (typically: ask
20
+ * the next source in their `ORACLE_SOURCE` list, then omit).
21
+ */
22
+ /**
23
+ * The Hermes-compatible REST base a deployment's hermes-plane read plans
24
+ * execute against — the endpoint half of the read contract
25
+ * ({@link resolveOracleReadPlan} is the ids half):
26
+ *
27
+ * - `pyth_rule` in the fed set → the Core source's own keyless endpoint
28
+ * (`pythCoreHermesEndpoint(network)`).
29
+ * - otherwise → `override` when the deployment set one (a proxy or
30
+ * self-hosted mirror), else the documented Pyth Pro base
31
+ * (`pythProHermesEndpoint()` — identical for every subscriber; auth is the
32
+ * caller's `pythApiKey` Bearer, not a per-deployment URL).
33
+ *
34
+ * Total — never throws, never falls back Core-ward: a fed set without
35
+ * `pyth_rule` reads Pro (or the override), full stop.
36
+ */
37
+ export function resolveHermesReadEndpoint(network, sources, override) {
38
+ if (sources.includes("pyth_rule"))
39
+ return pythCoreHermesEndpoint(network);
40
+ return override ?? pythProHermesEndpoint();
41
+ }
42
+ export function resolveOracleReadPlan(host, source, tickers) {
43
+ switch (source) {
44
+ case "pyth_rule":
45
+ case "pyth_lazer_rule": {
46
+ const hexFeeds = host.config.packages.pyth_rule?.feeds;
47
+ const feedIdByTicker = new Map();
48
+ for (const ticker of tickers) {
49
+ const feedId = hexFeeds?.[ticker]?.feed_id;
50
+ if (feedId !== undefined)
51
+ feedIdByTicker.set(ticker, feedId);
52
+ }
53
+ // For pyth_rule the write and read namespaces coincide, so `unreadable`
54
+ // is always empty; for lazer it is exactly the hex-entry gap.
55
+ const writeFeeds = source === "pyth_lazer_rule" ? host.config.packages.pyth_lazer_rule?.feeds : hexFeeds;
56
+ const unreadable = tickers.filter((ticker) => writeFeeds?.[ticker] !== undefined && !feedIdByTicker.has(ticker));
57
+ return { plane: "hermes", feedIdByTicker, unreadable };
58
+ }
59
+ case "waterx_rule": {
60
+ // Absent feeds block ⇒ serves nothing (see the OracleReadPlan doc) —
61
+ // never claim tickers the config doesn't name.
62
+ const feeds = host.config.packages.waterx_rule?.feeds;
63
+ return {
64
+ plane: "quote_center",
65
+ tickers: feeds ? tickers.filter((ticker) => ticker in feeds) : [],
66
+ unreadable: [],
67
+ };
68
+ }
69
+ default: {
70
+ const exhausted = source;
71
+ throw new Error(`resolveOracleReadPlan: unhandled OracleSource '${String(exhausted)}'`);
72
+ }
73
+ }
74
+ }
@@ -1,19 +1,22 @@
1
1
  /**
2
2
  * `rule-registry.ts` — maps a client-selected `OracleSource` to its concrete
3
- * `PriceUpdateRule` implementation. `refreshOraclePrices` (`aggregate.ts`) is
4
- * the only production caller; this is the one place `OracleSource` values are
5
- * wired to a rule instance. Selection is driven purely by the value passed in
6
- * (ultimately `OracleHost.oracleSource`, the `oracleSource` client create
3
+ * `PriceUpdateRule` implementation; the ONE place `OracleSource` values are
4
+ * wired to a rule instance. `refreshOraclePrices` (`aggregate.ts`) resolves
5
+ * every `host.oracleSources` entry through it, and consumers (e.g. a BE
6
+ * prefetch cache keying per source) import `resolveOracleRule` rather than
7
+ * hand-mirroring this map. Selection is driven purely by the value passed in
8
+ * (ultimately `OracleHost.oracleSources`, the `oracleSource` client create
7
9
  * option) — never by a config JSON `enabled` flag and never by `process.env`.
8
10
  *
9
11
  * 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`).
12
+ * back-stop any other source. Three are registered: `pyth_rule`
13
+ * (`PythCoreRule`, Hermes VAA), `pyth_lazer_rule` (`PythLazerRule`, Lazer
14
+ * signed updates), and `waterx_rule` (`WaterxRule`, first-party quote-center
15
+ * ed25519 signed batches). Resolving a source with no registered rule throws a
16
+ * clear `OracleSourceNotImplemented` error. There is deliberately no
17
+ * cross-source fallback and no client-creation config guard: selecting a source
18
+ * whose feeds are absent is not an error at init — it surfaces at tx-build time
19
+ * for the specific tickers that source can't serve (see `refreshOraclePrices`).
17
20
  */
18
21
  import type { OracleSource, PriceUpdateRule } from "./price-update-rule.ts";
19
22
  /**
@@ -1,22 +1,26 @@
1
1
  /**
2
2
  * `rule-registry.ts` — maps a client-selected `OracleSource` to its concrete
3
- * `PriceUpdateRule` implementation. `refreshOraclePrices` (`aggregate.ts`) is
4
- * the only production caller; this is the one place `OracleSource` values are
5
- * wired to a rule instance. Selection is driven purely by the value passed in
6
- * (ultimately `OracleHost.oracleSource`, the `oracleSource` client create
3
+ * `PriceUpdateRule` implementation; the ONE place `OracleSource` values are
4
+ * wired to a rule instance. `refreshOraclePrices` (`aggregate.ts`) resolves
5
+ * every `host.oracleSources` entry through it, and consumers (e.g. a BE
6
+ * prefetch cache keying per source) import `resolveOracleRule` rather than
7
+ * hand-mirroring this map. Selection is driven purely by the value passed in
8
+ * (ultimately `OracleHost.oracleSources`, the `oracleSource` client create
7
9
  * option) — never by a config JSON `enabled` flag and never by `process.env`.
8
10
  *
9
11
  * 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`).
12
+ * back-stop any other source. Three are registered: `pyth_rule`
13
+ * (`PythCoreRule`, Hermes VAA), `pyth_lazer_rule` (`PythLazerRule`, Lazer
14
+ * signed updates), and `waterx_rule` (`WaterxRule`, first-party quote-center
15
+ * ed25519 signed batches). Resolving a source with no registered rule throws a
16
+ * clear `OracleSourceNotImplemented` error. There is deliberately no
17
+ * cross-source fallback and no client-creation config guard: selecting a source
18
+ * whose feeds are absent is not an error at init — it surfaces at tx-build time
19
+ * for the specific tickers that source can't serve (see `refreshOraclePrices`).
17
20
  */
18
21
  import { PythCoreRule } from "./rules/pyth-core-rule.js";
19
22
  import { PythLazerRule } from "./rules/pyth-lazer-rule.js";
23
+ import { WaterxRule } from "./rules/waterx-rule.js";
20
24
  /**
21
25
  * Production registry. Frozen — tests inject a fake rule via
22
26
  * `resolveOracleRule`'s `overrides` param instead of mutating this.
@@ -24,6 +28,7 @@ import { PythLazerRule } from "./rules/pyth-lazer-rule.js";
24
28
  const DEFAULT_RULES = Object.freeze({
25
29
  pyth_rule: PythCoreRule,
26
30
  pyth_lazer_rule: PythLazerRule,
31
+ waterx_rule: WaterxRule,
27
32
  });
28
33
  /**
29
34
  * Thrown by {@link resolveOracleRule} when `source` has no `PriceUpdateRule`
@@ -7,7 +7,7 @@
7
7
  * changes vs `../pyth.ts` / `./pyth-rule.ts`.
8
8
  */
9
9
  import { assertRuleUpdateData, } from "../price-update-rule.js";
10
- import { buildPythPriceUpdateCalls, endpointSupportedFeedIds, fetchPriceFeedsUpdateData, } from "../pyth.js";
10
+ import { buildPythPriceUpdateCalls, endpointSupportedFeedIds, fetchPriceFeedsUpdateData, pythCoreHermesEndpoint, } from "../pyth.js";
11
11
  /**
12
12
  * Shape check ONLY — the `kind` discriminant is checked separately by the
13
13
  * caller before this runs, since a same-shaped payload from a different rule
@@ -33,10 +33,10 @@ export const PythCoreRule = {
33
33
  async fetchUpdateData(host, tickers) {
34
34
  if (tickers.length === 0)
35
35
  return null;
36
- // `host.pyth` is this source's own infra — the fixed per-network Core
37
- // Pyth block plus the caller's api_key/fetch. Endpoint, credential and
38
- // retry/timeout policy all come from it.
39
- const endpoint = host.pyth.hermes_endpoint;
36
+ // Endpoint is this source's own per-network infra (`PYTH_CORE_INFRA`);
37
+ // credential + retry/timeout policy are the caller-supplied `client.pyth`
38
+ // access slice.
39
+ const endpoint = pythCoreHermesEndpoint(host.network);
40
40
  const feedIds = tickers.map((ticker) => host.getPythFeed(ticker).feed_id);
41
41
  const updates = await fetchPriceFeedsUpdateData(endpoint, feedIds, {
42
42
  apiKey: host.pyth.api_key,
@@ -8,8 +8,29 @@
8
8
  * `Update` PTB value back through a `RuleUpdateHandle` for the feed calls.
9
9
  */
10
10
  import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
11
+ import type { Network } from "../../constants.ts";
11
12
  import type { OracleHost } from "../host.ts";
12
13
  import { type PriceUpdateRule } from "../price-update-rule.ts";
14
+ /**
15
+ * Pyth Lazer (Pyth Pro) external infra — owned by THIS source, by network.
16
+ * Per-network constants for infrastructure Pyth operates (not part of the
17
+ * `waterx-config` JSON), co-located with the only rule that reads them —
18
+ * no other oracle source ever touches a Lazer endpoint or verifier.
19
+ *
20
+ * - `endpoint` — Lazer HTTP API base; signed updates come from
21
+ * `POST /v1/latest_price` (Bearer-authenticated). The service is
22
+ * network-agnostic (one signed payload verifies on any chain that trusts the
23
+ * Lazer signers), so both networks share the production host.
24
+ * - `verifier_package` — the Sui package carrying
25
+ * `pyth_lazer::parse_and_verify_le_ecdsa_update`. Per-network: testnet is
26
+ * still the original v1 publish; mainnet is the v2-upgraded package (which
27
+ * still exposes the v1 entry `pyth_lazer_rule` binds). Values mirror the
28
+ * contract repo's `pyth_lazer_rule/Move.toml` published-at pins.
29
+ */
30
+ export declare const LAZER_INFRA: Record<Network, {
31
+ endpoint: string;
32
+ verifier_package: string;
33
+ }>;
13
34
  /** `pyth_lazer_rule`'s narrowed `RuleUpdateData.payload` shape. */
14
35
  export interface PythLazerUpdatePayload {
15
36
  /** One signed `leEcdsa` message carrying every requested feed. */
@@ -8,9 +8,34 @@
8
8
  * `Update` PTB value back through a `RuleUpdateHandle` for the feed calls.
9
9
  */
10
10
  import { fromHex } from "@mysten/bcs";
11
- import { LAZER_DEFAULTS } from "../config.js";
12
11
  import { assertRuleUpdateData, } from "../price-update-rule.js";
13
12
  import { fetchWithPolicy, joinEndpointPath, rethrowExhaustedFetch } from "../update-fetch.js";
13
+ /**
14
+ * Pyth Lazer (Pyth Pro) external infra — owned by THIS source, by network.
15
+ * Per-network constants for infrastructure Pyth operates (not part of the
16
+ * `waterx-config` JSON), co-located with the only rule that reads them —
17
+ * no other oracle source ever touches a Lazer endpoint or verifier.
18
+ *
19
+ * - `endpoint` — Lazer HTTP API base; signed updates come from
20
+ * `POST /v1/latest_price` (Bearer-authenticated). The service is
21
+ * network-agnostic (one signed payload verifies on any chain that trusts the
22
+ * Lazer signers), so both networks share the production host.
23
+ * - `verifier_package` — the Sui package carrying
24
+ * `pyth_lazer::parse_and_verify_le_ecdsa_update`. Per-network: testnet is
25
+ * still the original v1 publish; mainnet is the v2-upgraded package (which
26
+ * still exposes the v1 entry `pyth_lazer_rule` binds). Values mirror the
27
+ * contract repo's `pyth_lazer_rule/Move.toml` published-at pins.
28
+ */
29
+ export const LAZER_INFRA = {
30
+ MAINNET: {
31
+ endpoint: "https://pyth-lazer.dourolabs.app",
32
+ verifier_package: "0xefbfd064480777699fd9c557a5804d72ace7bc82661fdc8d1f1a44ea6d92ee10",
33
+ },
34
+ TESTNET: {
35
+ endpoint: "https://pyth-lazer.dourolabs.app",
36
+ verifier_package: "0xf5bd2141967507050a91b58de3d95e77c432cd90d1799ee46effc27430a68c21",
37
+ },
38
+ };
14
39
  /**
15
40
  * Signed-update request pins, mirroring what the on-chain rule consumes:
16
41
  * - `properties` — `price` + `exponent` are REQUIRED by
@@ -147,7 +172,7 @@ export const PythLazerRule = {
147
172
  if (!apiKey) {
148
173
  throw new LazerApiKeyMissingError();
149
174
  }
150
- const update = await fetchLazerSignedUpdate(LAZER_DEFAULTS[host.network].endpoint, apiKey, feedIds, host.pyth.fetch);
175
+ const update = await fetchLazerSignedUpdate(LAZER_INFRA[host.network].endpoint, apiKey, feedIds, host.pyth.fetch);
151
176
  return { kind: "pyth_lazer_rule", payload: { update, feedIds } };
152
177
  },
153
178
  /**
@@ -184,7 +209,7 @@ export const PythLazerRule = {
184
209
  return undefined;
185
210
  const lazer = requireLazerPackage(host);
186
211
  const [update] = tx.moveCall({
187
- target: `${LAZER_DEFAULTS[host.network].verifier_package}::pyth_lazer::parse_and_verify_le_ecdsa_update`,
212
+ target: `${LAZER_INFRA[host.network].verifier_package}::pyth_lazer::parse_and_verify_le_ecdsa_update`,
188
213
  arguments: [tx.object(lazer.state), tx.object.clock(), tx.pure.vector("u8", payload.update)],
189
214
  });
190
215
  return { kind: "pyth_lazer_rule", update };
@@ -7,6 +7,7 @@
7
7
  * `PriceInfoObject` is fresh.
8
8
  */
9
9
  import { feed as pythRuleFeed } from "../../generated/waterx_pyth_rule/pyth_rule.js";
10
+ import { PYTH_CORE_INFRA } from "../pyth.js";
10
11
  export function feedPythRule(tx, host, collector, priceInfoObjectId) {
11
12
  pythRuleFeed({
12
13
  package: host.config.packages.pyth_rule.published_at,
@@ -15,10 +16,10 @@ export function feedPythRule(tx, host, collector, priceInfoObjectId) {
15
16
  config: tx.object(host.config.packages.pyth_rule.config),
16
17
  // The deployed pyth_rule package is compiled against the Core pyth
17
18
  // dependency, so its `&PythState` parameter is the Core-package-qualified
18
- // type and `host.pyth` (the fixed per-network Core infra) is always the
19
- // right state to pass. The config's price_info_object entries are Core
20
- // objects to match.
21
- pythState: tx.object(host.pyth.state_id),
19
+ // type and the Core source's own per-network state (`PYTH_CORE_INFRA`)
20
+ // is always the right state to pass. The config's price_info_object
21
+ // entries are Core objects to match.
22
+ pythState: tx.object(PYTH_CORE_INFRA[host.network].state_id),
22
23
  pythPriceInfo: tx.object(priceInfoObjectId),
23
24
  },
24
25
  })(tx);