@waterx/sdk 4.1.0 → 4.3.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/README.md +29 -19
- package/dist/cjs/src/account/config.d.ts +3 -2
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +7 -134
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +8 -154
- package/dist/cjs/src/oracle/aggregate.d.ts +21 -21
- package/dist/cjs/src/oracle/aggregate.js +121 -71
- package/dist/cjs/src/oracle/config.d.ts +38 -72
- package/dist/cjs/src/oracle/config.js +0 -56
- package/dist/cjs/src/oracle/host.d.ts +24 -20
- package/dist/cjs/src/oracle/index.d.ts +7 -3
- package/dist/cjs/src/oracle/index.js +41 -8
- package/dist/cjs/src/oracle/price-update-rule.d.ts +32 -11
- package/dist/cjs/src/oracle/price-update-rule.js +23 -3
- package/dist/cjs/src/oracle/pyth.d.ts +44 -0
- package/dist/cjs/src/oracle/pyth.js +48 -6
- package/dist/cjs/src/oracle/read-plane.d.ts +70 -0
- package/dist/cjs/src/oracle/read-plane.js +85 -0
- package/dist/cjs/src/oracle/rule-registry.d.ts +6 -4
- package/dist/cjs/src/oracle/rule-registry.js +6 -4
- package/dist/cjs/src/oracle/rules/pyth-core-rule.js +6 -5
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +34 -6
- package/dist/cjs/src/oracle/rules/pyth-rule.js +5 -4
- package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +42 -5
- package/dist/cjs/src/oracle/rules/waterx-rule.js +61 -18
- package/dist/cjs/src/oracle/source-list.d.ts +36 -0
- package/dist/cjs/src/oracle/source-list.js +57 -0
- package/dist/cjs/src/perp/client.d.ts +41 -28
- package/dist/cjs/src/perp/client.js +32 -20
- package/dist/cjs/src/perp/config-view.js +7 -6
- package/dist/cjs/src/perp/config.d.ts +6 -6
- package/dist/cjs/src/perp/config.js +12 -12
- package/dist/cjs/src/perp/index.d.ts +3 -3
- package/dist/cjs/src/perp/index.js +11 -4
- package/dist/cjs/src/perp/user/staking.js +2 -1
- package/dist/cjs/src/unified-client.d.ts +14 -9
- package/dist/cjs/src/unified-client.js +2 -2
- package/dist/cjs/src/utils/config.js +2 -1
- package/dist/cjs/src/utils/record.d.ts +12 -0
- package/dist/cjs/src/utils/record.js +22 -0
- package/dist/src/account/config.d.ts +3 -2
- package/dist/src/generated/waterx_rule/waterx_rule.d.ts +7 -134
- package/dist/src/generated/waterx_rule/waterx_rule.js +7 -143
- package/dist/src/oracle/aggregate.d.ts +21 -21
- package/dist/src/oracle/aggregate.js +121 -71
- package/dist/src/oracle/config.d.ts +38 -72
- package/dist/src/oracle/config.js +1 -55
- package/dist/src/oracle/host.d.ts +24 -20
- package/dist/src/oracle/index.d.ts +7 -3
- package/dist/src/oracle/index.js +32 -10
- package/dist/src/oracle/price-update-rule.d.ts +32 -11
- package/dist/src/oracle/price-update-rule.js +22 -3
- package/dist/src/oracle/pyth.d.ts +44 -0
- package/dist/src/oracle/pyth.js +45 -5
- package/dist/src/oracle/read-plane.d.ts +70 -0
- package/dist/src/oracle/read-plane.js +81 -0
- package/dist/src/oracle/rule-registry.d.ts +6 -4
- package/dist/src/oracle/rule-registry.js +6 -4
- package/dist/src/oracle/rules/pyth-core-rule.js +7 -6
- package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
- package/dist/src/oracle/rules/pyth-lazer-rule.js +33 -5
- package/dist/src/oracle/rules/pyth-rule.js +5 -4
- package/dist/src/oracle/rules/waterx-rule.d.ts +42 -5
- package/dist/src/oracle/rules/waterx-rule.js +57 -15
- package/dist/src/oracle/source-list.d.ts +36 -0
- package/dist/src/oracle/source-list.js +53 -0
- package/dist/src/perp/client.d.ts +41 -28
- package/dist/src/perp/client.js +33 -21
- package/dist/src/perp/config-view.js +7 -6
- package/dist/src/perp/config.d.ts +6 -6
- package/dist/src/perp/config.js +11 -9
- package/dist/src/perp/index.d.ts +3 -3
- package/dist/src/perp/index.js +2 -2
- package/dist/src/perp/user/staking.js +2 -1
- package/dist/src/unified-client.d.ts +14 -9
- package/dist/src/unified-client.js +2 -2
- package/dist/src/utils/config.js +2 -1
- package/dist/src/utils/record.d.ts +12 -0
- package/dist/src/utils/record.js +19 -0
- package/package.json +1 -1
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { BasePackageEntry } from "../account/config.ts";
|
|
13
13
|
import type { BaseLineConfig } from "../base-client.ts";
|
|
14
|
-
import type { Network } from "../constants.ts";
|
|
15
14
|
import type { FetchPolicy } from "./update-fetch.ts";
|
|
16
15
|
export interface PythRulePackage extends BasePackageEntry {
|
|
17
16
|
config: string;
|
|
@@ -31,7 +30,7 @@ export interface PythSponsorRulePackage extends BasePackageEntry {
|
|
|
31
30
|
*
|
|
32
31
|
* `enabled` mirrors the JSON field verbatim but MUST NOT be read for routing —
|
|
33
32
|
* which rule prices a ticker is decided solely by the client's `oracleSource`
|
|
34
|
-
* create option (see `OracleHost.
|
|
33
|
+
* create option (see `OracleHost.oracleSources`), never by this flag or any
|
|
35
34
|
* other config value.
|
|
36
35
|
*/
|
|
37
36
|
export interface PythLazerRulePackage extends BasePackageEntry {
|
|
@@ -99,11 +98,12 @@ export interface WaterxRuleFeedEntry {
|
|
|
99
98
|
* Read by `WaterxRule` (`rules/waterx-rule.ts`): `feeds` for ticker support,
|
|
100
99
|
* `config`/`enclave_config`/`enclave` for the `collect_batch_latest` call,
|
|
101
100
|
* `published_at` for the package address. The off-chain signed price is pulled
|
|
102
|
-
* from the quote-center (endpoint from
|
|
101
|
+
* from the quote-center (endpoint from the rule-owned `WATERX_INFRA` table in
|
|
102
|
+
* `rules/waterx-rule.ts`), not this JSON.
|
|
103
103
|
*
|
|
104
104
|
* `enabled` mirrors the JSON field verbatim but MUST NOT be read for routing —
|
|
105
105
|
* which rule prices a ticker is decided solely by the client's `oracleSource`
|
|
106
|
-
* create option (see `OracleHost.
|
|
106
|
+
* create option (see `OracleHost.oracleSources`), mirroring `pyth_lazer_rule`.
|
|
107
107
|
*/
|
|
108
108
|
export interface WaterxRulePackage extends BasePackageEntry {
|
|
109
109
|
/** Shared `waterx_rule::Config` (per-symbol on-chain feed_config). */
|
|
@@ -137,17 +137,6 @@ export interface OraclePackages {
|
|
|
137
137
|
waterx_rule?: WaterxRulePackage;
|
|
138
138
|
waterx_oracle: WaterxOraclePackage;
|
|
139
139
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Resolved Pyth Core infra as it lives on `client.pyth` — NOT a config-JSON
|
|
142
|
-
* shape. `state_id` / `wormhole_state_id` / `hermes_endpoint` come verbatim
|
|
143
|
-
* from the fixed per-network constant ({@link PYTH_DEFAULTS}); `api_key` /
|
|
144
|
-
* `fetch` are layered on from the caller's `pythApiKey` / `pythFetch` create
|
|
145
|
-
* options. None of it is sourced from the canonical `waterx-config` JSON — the
|
|
146
|
-
* SDK never reads a `pyth` block there (a Bearer secret has no place in a
|
|
147
|
-
* public CDN document). The infra is the same for every `oracleSource`; the
|
|
148
|
-
* `pyth_lazer_rule` source reads only the `api_key` / `fetch` from here and
|
|
149
|
-
* gets its on-chain infra from {@link LAZER_DEFAULTS} + config instead.
|
|
150
|
-
*/
|
|
151
140
|
/**
|
|
152
141
|
* The caller-tunable subset of `fetchWithPolicy`'s policy exposed on the
|
|
153
142
|
* `pythFetch` create option and `client.pyth.fetch` — the retry/timeout budget
|
|
@@ -160,18 +149,24 @@ export type PythFetchPolicy = {
|
|
|
160
149
|
timeoutMs?: number;
|
|
161
150
|
retries?: number;
|
|
162
151
|
};
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
152
|
+
/**
|
|
153
|
+
* `client.pyth` — ONLY the caller-supplied Pyth credential + fetch policy,
|
|
154
|
+
* shared by the Pyth-family rules (`pyth_rule`, `pyth_lazer_rule`). It carries
|
|
155
|
+
* NO endpoints and NO on-chain object ids: every oracle source owns its own
|
|
156
|
+
* infra, co-located with its rule (`PYTH_CORE_INFRA` in `oracle/pyth.ts`;
|
|
157
|
+
* the Lazer constants inside `rules/pyth-lazer-rule.ts`). A non-Pyth source
|
|
158
|
+
* never reads this slice.
|
|
159
|
+
* Nothing here is sourced from the canonical `waterx-config` JSON — a Bearer
|
|
160
|
+
* secret has no place in a public CDN document.
|
|
161
|
+
*/
|
|
162
|
+
export interface PythAccessConfig {
|
|
167
163
|
/**
|
|
168
|
-
* Pyth
|
|
164
|
+
* Pyth access token (`Authorization: Bearer …`). Required by
|
|
169
165
|
* `PythLazerRule`'s signed-update fetch — Lazer is auth-first, so there is
|
|
170
|
-
* no keyless default
|
|
171
|
-
*
|
|
172
|
-
* `
|
|
173
|
-
*
|
|
174
|
-
* migration (post-2026-08-18, per
|
|
166
|
+
* no keyless default; absent when a lazer-routed fetch runs →
|
|
167
|
+
* `LazerApiKeyMissing` is thrown at fetch time. Supplied via the
|
|
168
|
+
* `pythApiKey` create option (the SDK never reads `process.env` or the
|
|
169
|
+
* config JSON). As of the Pyth Pro migration (post-2026-08-18, per
|
|
175
170
|
* https://docs.pyth.network/price-feeds/core/upgrade) this is ALSO required
|
|
176
171
|
* for `pyth_rule`'s Hermes fetch (`fetchPriceFeedsUpdateData`) — see
|
|
177
172
|
* `fetch` below.
|
|
@@ -187,66 +182,37 @@ export interface PythInfraConfig {
|
|
|
187
182
|
*/
|
|
188
183
|
fetch?: PythFetchPolicy;
|
|
189
184
|
}
|
|
190
|
-
export declare const PYTH_DEFAULTS: Record<Network, PythInfraConfig>;
|
|
191
|
-
/**
|
|
192
|
-
* Pyth Lazer (Pyth Pro) external infra the `PythLazerRule` needs, by network.
|
|
193
|
-
* Mirrors {@link PYTH_DEFAULTS}: per-network constants for infrastructure Pyth
|
|
194
|
-
* operates (not part of the `waterx-config` JSON). A fuller `PYTH_INFRA`
|
|
195
|
-
* restructure is deferred — this stays a minimal map until then.
|
|
196
|
-
*
|
|
197
|
-
* - `endpoint` — Lazer HTTP API base; signed updates come from
|
|
198
|
-
* `POST /v1/latest_price` (Bearer-authenticated). The service is
|
|
199
|
-
* network-agnostic (one signed payload verifies on any chain that trusts the
|
|
200
|
-
* Lazer signers), so both networks share the production host.
|
|
201
|
-
* - `verifier_package` — the Sui package carrying
|
|
202
|
-
* `pyth_lazer::parse_and_verify_le_ecdsa_update`. Per-network: testnet is
|
|
203
|
-
* still the original v1 publish; mainnet is the v2-upgraded package (which
|
|
204
|
-
* still exposes the v1 entry `pyth_lazer_rule` binds). Values mirror the
|
|
205
|
-
* contract repo's `pyth_lazer_rule/Move.toml` published-at pins.
|
|
206
|
-
*/
|
|
207
|
-
export declare const LAZER_DEFAULTS: Record<Network, {
|
|
208
|
-
endpoint: string;
|
|
209
|
-
verifier_package: string;
|
|
210
|
-
}>;
|
|
211
185
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
186
|
+
* `client.waterx` — ONLY the caller-supplied quote-center overrides for
|
|
187
|
+
* `WaterxRule`, mirroring {@link PythAccessConfig}: no resolved infra lives on
|
|
188
|
+
* the client. When a field is unset the rule resolves it against its OWN
|
|
189
|
+
* per-network table (`WATERX_INFRA` in `rules/waterx-rule.ts`) — no other
|
|
190
|
+
* source's endpoint or policy is ever consulted.
|
|
215
191
|
*
|
|
216
|
-
* The override exists because this is the one oracle source a BROWSER
|
|
217
|
-
* itself: the rule pulls the signed envelope from the page, so it is
|
|
218
|
-
* the quote-center deployment's CORS allowlist. A front end whose
|
|
219
|
-
* on that list — or one that must route egress through its own
|
|
220
|
-
* `endpoint` at a same-origin proxy (or supplies
|
|
221
|
-
* being locked to the
|
|
192
|
+
* The endpoint override exists because this is the one oracle source a BROWSER
|
|
193
|
+
* fetches itself: the rule pulls the signed envelope from the page, so it is
|
|
194
|
+
* subject to the quote-center deployment's CORS allowlist. A front end whose
|
|
195
|
+
* origin is not on that list — or one that must route egress through its own
|
|
196
|
+
* backend — points `endpoint` at a same-origin proxy (or supplies
|
|
197
|
+
* `fetch.fetchImpl`) instead of being locked to the default host.
|
|
222
198
|
*/
|
|
223
|
-
export interface
|
|
199
|
+
export interface WaterxAccessConfig {
|
|
224
200
|
/**
|
|
225
|
-
* Quote-center base URL
|
|
226
|
-
* `joinEndpointPath`, so
|
|
201
|
+
* Quote-center base URL override (`waterxEndpoint` create option). A base
|
|
202
|
+
* PATH is preserved — the rule appends via `joinEndpointPath`, so
|
|
203
|
+
* `https://app.example/api/quote-center` resolves to
|
|
227
204
|
* `…/api/quote-center/v1/quotes/update` and a proxy route is not rewritten
|
|
228
205
|
* away. A trailing slash is trimmed.
|
|
229
206
|
*/
|
|
230
|
-
endpoint
|
|
207
|
+
endpoint?: string;
|
|
231
208
|
/**
|
|
232
209
|
* Retry/timeout policy (and `fetchImpl`) for the quote-center fetch — see
|
|
233
210
|
* `fetchWithPolicy` (`./update-fetch.ts`). Supplied via the `waterxFetch`
|
|
234
|
-
* create option.
|
|
235
|
-
*
|
|
211
|
+
* create option. Falls back to `fetchWithPolicy`'s built-in defaults (15s
|
|
212
|
+
* timeout, 2 retries) when unset — never to another source's policy.
|
|
236
213
|
*/
|
|
237
214
|
fetch?: FetchPolicy;
|
|
238
215
|
}
|
|
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>;
|
|
250
216
|
/**
|
|
251
217
|
* The narrow config shape the oracle/refresh code needs. `WaterXConfig`
|
|
252
218
|
* (the perp line's full config) is assignable to this, so `PerpClient` satisfies
|
|
@@ -9,58 +9,4 @@
|
|
|
9
9
|
* depends on this shared schema instead of the perp line's full config —
|
|
10
10
|
* mirrors the earlier account-config hoist.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
MAINNET: {
|
|
14
|
-
state_id: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
|
|
15
|
-
wormhole_state_id: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
|
|
16
|
-
hermes_endpoint: "https://hermes.pyth.network",
|
|
17
|
-
},
|
|
18
|
-
TESTNET: {
|
|
19
|
-
state_id: "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c",
|
|
20
|
-
wormhole_state_id: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
|
|
21
|
-
hermes_endpoint: "https://hermes-beta.pyth.network",
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Pyth Lazer — external infra, defaults by network
|
|
26
|
-
// ============================================================================
|
|
27
|
-
/**
|
|
28
|
-
* Pyth Lazer (Pyth Pro) external infra the `PythLazerRule` needs, by network.
|
|
29
|
-
* Mirrors {@link PYTH_DEFAULTS}: per-network constants for infrastructure Pyth
|
|
30
|
-
* operates (not part of the `waterx-config` JSON). A fuller `PYTH_INFRA`
|
|
31
|
-
* restructure is deferred — this stays a minimal map until then.
|
|
32
|
-
*
|
|
33
|
-
* - `endpoint` — Lazer HTTP API base; signed updates come from
|
|
34
|
-
* `POST /v1/latest_price` (Bearer-authenticated). The service is
|
|
35
|
-
* network-agnostic (one signed payload verifies on any chain that trusts the
|
|
36
|
-
* Lazer signers), so both networks share the production host.
|
|
37
|
-
* - `verifier_package` — the Sui package carrying
|
|
38
|
-
* `pyth_lazer::parse_and_verify_le_ecdsa_update`. Per-network: testnet is
|
|
39
|
-
* still the original v1 publish; mainnet is the v2-upgraded package (which
|
|
40
|
-
* still exposes the v1 entry `pyth_lazer_rule` binds). Values mirror the
|
|
41
|
-
* contract repo's `pyth_lazer_rule/Move.toml` published-at pins.
|
|
42
|
-
*/
|
|
43
|
-
export const LAZER_DEFAULTS = {
|
|
44
|
-
MAINNET: {
|
|
45
|
-
endpoint: "https://pyth-lazer.dourolabs.app",
|
|
46
|
-
verifier_package: "0xefbfd064480777699fd9c557a5804d72ace7bc82661fdc8d1f1a44ea6d92ee10",
|
|
47
|
-
},
|
|
48
|
-
TESTNET: {
|
|
49
|
-
endpoint: "https://pyth-lazer.dourolabs.app",
|
|
50
|
-
verifier_package: "0xf5bd2141967507050a91b58de3d95e77c432cd90d1799ee46effc27430a68c21",
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
/**
|
|
54
|
-
* WaterX quote-center base URL by network — the first-party TEE-signed price
|
|
55
|
-
* hub `WaterxRule` pulls from (`GET /v1/quotes/update?symbols=…`). Mirrors
|
|
56
|
-
* {@link LAZER_DEFAULTS}: infra WaterX operates, not part of the `waterx-config`
|
|
57
|
-
* JSON. Public read (no auth), so there is no api_key. `endpoint` has no
|
|
58
|
-
* trailing slash — the rule appends the path.
|
|
59
|
-
*
|
|
60
|
-
* These are DEFAULTS, not a hard pin: a consumer overrides them per client via
|
|
61
|
-
* `waterxEndpoint` / `waterxFetch` (resolved onto `client.waterx`).
|
|
62
|
-
*/
|
|
63
|
-
export const WATERX_DEFAULTS = {
|
|
64
|
-
MAINNET: { endpoint: "https://quote-center.waterx.app" },
|
|
65
|
-
TESTNET: { endpoint: "https://quote-center-staging.waterx.app" },
|
|
66
|
-
};
|
|
12
|
+
export {};
|
|
@@ -9,37 +9,41 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { SuiGrpcClient } from "@mysten/sui/grpc";
|
|
11
11
|
import type { Network } from "../constants.ts";
|
|
12
|
-
import type { OracleConfig,
|
|
12
|
+
import type { OracleConfig, PythAccessConfig, WaterxAccessConfig } from "./config.ts";
|
|
13
13
|
import type { OracleSource } from "./price-update-rule.ts";
|
|
14
14
|
export interface OracleHost {
|
|
15
|
-
/** Sui network this client targets —
|
|
15
|
+
/** Sui network this client targets — each rule keys its OWN infra table by it (`PYTH_CORE_INFRA`, `LAZER_INFRA`). */
|
|
16
16
|
readonly network: Network;
|
|
17
17
|
/** Oracle slice of the canonical `waterx-config` JSON (rule packages + per-ticker feeds). */
|
|
18
18
|
readonly config: OracleConfig;
|
|
19
|
-
/**
|
|
20
|
-
readonly pyth:
|
|
19
|
+
/** Caller-supplied Pyth credential + fetch policy (create options) — NO endpoints, NO object ids. */
|
|
20
|
+
readonly pyth: PythAccessConfig;
|
|
21
21
|
/**
|
|
22
|
-
* WaterX quote-center
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* (`
|
|
29
|
-
*
|
|
22
|
+
* Caller-supplied WaterX quote-center overrides for `WaterxRule`
|
|
23
|
+
* (`waterxEndpoint` / `waterxFetch` create options) — access-only, mirroring
|
|
24
|
+
* `pyth` above. OPTIONAL so an existing host stays a valid `OracleHost`;
|
|
25
|
+
* unset fields resolve against the rule's own `WATERX_INFRA[network]` table.
|
|
26
|
+
* This is the hook a browser consumer uses to route the quote-center fetch
|
|
27
|
+
* through a same-origin proxy (`endpoint`) or its own transport
|
|
28
|
+
* (`fetch.fetchImpl`) — that request is made from the page, so it is bound
|
|
29
|
+
* by the quote-center's CORS allowlist.
|
|
30
30
|
*/
|
|
31
|
-
readonly waterx?:
|
|
31
|
+
readonly waterx?: WaterxAccessConfig;
|
|
32
32
|
/** gRPC client for the on-chain reads the Pyth update path needs. */
|
|
33
33
|
readonly grpcClient: SuiGrpcClient;
|
|
34
34
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
35
|
+
* The FED SET for `refreshOraclePrices`'s update legs — the REQUIRED
|
|
36
|
+
* `oracleSource` create option normalized to a non-empty, deduped list.
|
|
37
|
+
* Every listed source's data is fetched and fed in one build; the chain's
|
|
38
|
+
* per-ticker weight tables decide which contributions count (feeding an
|
|
39
|
+
* unweighted rule is dropped on-chain; starving a weighted one aborts), so
|
|
40
|
+
* during weight migrations the list stays a SUPERSET of every ticker's
|
|
41
|
+
* weighted set. Routing is driven by this value ALONE: never by a config
|
|
42
|
+
* JSON `enabled` flag and never by `process.env` — the SDK never reads it;
|
|
43
|
+
* consumers (BE/FE) wire this option from their own env var
|
|
44
|
+
* (`ORACLE_SOURCE`, comma-separated).
|
|
41
45
|
*/
|
|
42
|
-
readonly
|
|
46
|
+
readonly oracleSources: readonly OracleSource[];
|
|
43
47
|
/** True when `ticker` is priced by `constant_rule`. */
|
|
44
48
|
isConstantTicker(ticker: string): boolean;
|
|
45
49
|
/** The `supra_rule` config when deployed, enabled, and fully wired; else `undefined`. */
|
|
@@ -18,15 +18,19 @@
|
|
|
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 { ORACLE_SOURCES } from "./price-update-rule.ts";
|
|
25
|
+
export { isOracleSource, parseOracleSourceList } from "./source-list.ts";
|
|
26
|
+
export { resolveOracleReadPlan, resolveHermesReadEndpoint } from "./read-plane.ts";
|
|
27
|
+
export type { OracleReadPlan } from "./read-plane.ts";
|
|
24
28
|
export { PythCoreRule } from "./rules/pyth-core-rule.ts";
|
|
25
29
|
export type { PythCoreUpdatePayload } from "./rules/pyth-core-rule.ts";
|
|
26
30
|
export { PythLazerRule, LazerApiKeyMissingError } from "./rules/pyth-lazer-rule.ts";
|
|
27
31
|
export type { PythLazerUpdatePayload } from "./rules/pyth-lazer-rule.ts";
|
|
28
|
-
export { WaterxRule, parseSignedEnvelope } from "./rules/waterx-rule.ts";
|
|
32
|
+
export { WaterxRule, parseSignedEnvelope, BATCH_PRICE_INTENT, WATERX_INFRA, waterxQuoteCenterEndpoint, waterxEnvelopeOf, } from "./rules/waterx-rule.ts";
|
|
29
33
|
export type { WaterxUpdatePayload, WaterxSignedEnvelope, WaterxBatchItem, } from "./rules/waterx-rule.ts";
|
|
30
|
-
export { OracleSourceNotImplementedError } from "./rule-registry.ts";
|
|
34
|
+
export { OracleSourceNotImplementedError, resolveOracleRule } from "./rule-registry.ts";
|
|
31
35
|
export { aggregateTicker, aggregateTickerWithPyth, aggregateTickerWithConstant, refreshOraclePrices, } from "./aggregate.ts";
|
|
32
36
|
export { openPythSponsorFund, reimbursePythSponsor } from "./rules/sponsor.ts";
|
package/dist/src/oracle/index.js
CHANGED
|
@@ -33,24 +33,46 @@ 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,
|
|
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
|
+
// Canonical OracleSource value list + THE env-string parser consumers fold
|
|
44
|
+
// onto — semantics and rationale in `source-list.ts`'s header.
|
|
45
|
+
export { ORACLE_SOURCES } from "./price-update-rule.js";
|
|
46
|
+
export { isOracleSource, parseOracleSourceList } from "./source-list.js";
|
|
47
|
+
// Per-source READ-plane resolution — which tickers a source can price
|
|
48
|
+
// off-chain and with which ids (`resolveOracleReadPlan`), and which
|
|
49
|
+
// Hermes-compatible base the hermes plans execute against
|
|
50
|
+
// (`resolveHermesReadEndpoint`: pyth_rule listed → Core, else override ??
|
|
51
|
+
// the documented Pyth Pro base). The one place the "lazer reads through
|
|
52
|
+
// `pyth_rule.feeds` hex ids" invariant lives; consumers resolve through
|
|
53
|
+
// this instead of hardcoding namespace sharing or endpoint branching.
|
|
54
|
+
export { resolveOracleReadPlan, resolveHermesReadEndpoint } from "./read-plane.js";
|
|
37
55
|
// Pyth Core rule (PriceUpdateRule wrapper over the Pyth source above)
|
|
38
56
|
export { PythCoreRule } from "./rules/pyth-core-rule.js";
|
|
39
57
|
// Pyth Lazer rule (signed-update generation; `feedLazerRule` stays internal to `aggregate.ts`)
|
|
40
58
|
// `LazerApiKeyMissingError` is re-exported (not just the type) for the same
|
|
41
59
|
// `instanceof` reason as `OracleFeeSourceUnavailableError` above.
|
|
42
60
|
export { PythLazerRule, LazerApiKeyMissingError } from "./rules/pyth-lazer-rule.js";
|
|
61
|
+
// `WATERX_INFRA` / `waterxQuoteCenterEndpoint` are the source's own infra table +
|
|
62
|
+
// read-plane accessor (mirrors `pythCoreHermesEndpoint`).
|
|
43
63
|
// WaterX quote-center rule (first-party ed25519 signed batches; `feedWaterxRule`
|
|
44
64
|
// stays internal to `aggregate.ts`).
|
|
45
|
-
export { WaterxRule, parseSignedEnvelope
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
// `
|
|
53
|
-
|
|
65
|
+
export { WaterxRule, parseSignedEnvelope, BATCH_PRICE_INTENT, WATERX_INFRA, waterxQuoteCenterEndpoint,
|
|
66
|
+
// Rule-owned payload accessor (kind-check + unwrap in one place) — never
|
|
67
|
+
// hand-cast the payload shape.
|
|
68
|
+
waterxEnvelopeOf, } from "./rules/waterx-rule.js";
|
|
69
|
+
// `resolveOracleRule` is the ONE source→rule registry — exported so external
|
|
70
|
+
// consumers (e.g. a BE prefetch cache that keys per source and needs each
|
|
71
|
+
// source's `supportedTickers`/`fetchUpdateData`) resolve through it instead of
|
|
72
|
+
// hand-mirroring the map and drifting. `OracleSourceNotImplementedError` is
|
|
73
|
+
// its `instanceof`-able failure (same reason as `OracleFeeSourceUnavailableError`
|
|
74
|
+
// above).
|
|
75
|
+
export { OracleSourceNotImplementedError, resolveOracleRule } from "./rule-registry.js";
|
|
54
76
|
// Aggregation orchestrator
|
|
55
77
|
export { aggregateTicker, aggregateTickerWithPyth, aggregateTickerWithConstant, refreshOraclePrices, } from "./aggregate.js";
|
|
56
78
|
// Sponsor rule (fund open / reimburse + witness attach)
|
|
@@ -11,23 +11,37 @@
|
|
|
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`
|
|
15
|
-
* `rule-registry.ts`, then drives fetch + `buildUpdateCalls`
|
|
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
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
23
|
+
* The canonical list of selectable oracle sources — the SINGLE authority the
|
|
24
|
+
* {@link OracleSource} union derives from (the value-list→union derive
|
|
25
|
+
* idiom of `unified-client.ts`'s `NON_CLIENT_FIRST`, plus `Object.freeze`
|
|
26
|
+
* so the immutability is RUNTIME truth: `as const` alone would let a JS
|
|
27
|
+
* consumer push into the array and desync the membership Set built from it
|
|
28
|
+
* in `source-list.ts`). Runtime membership checks and the `ORACLE_SOURCE`
|
|
29
|
+
* env parser live there, on `isOracleSource` / `parseOracleSourceList`.
|
|
30
|
+
* Only sources belong here: `supra_rule` and `constant_rule` are auxiliary
|
|
31
|
+
* rules fed alongside whichever sources are selected (see
|
|
32
|
+
* `aggregateTicker`), not sources themselves — the `satisfies` keeps
|
|
33
|
+
* entries inside `PriceUpdateRuleKind` but adding an auxiliary rule to this
|
|
34
|
+
* list is an (incorrect) editorial decision this comment exists to prevent.
|
|
29
35
|
*/
|
|
30
|
-
export
|
|
36
|
+
export declare const ORACLE_SOURCES: readonly ["pyth_rule", "pyth_lazer_rule", "waterx_rule"];
|
|
37
|
+
/**
|
|
38
|
+
* The kinds listable in a client's `oracleSource` create option (see
|
|
39
|
+
* `OracleHost.oracleSources`) — i.e. rules that can serve as the on-chain
|
|
40
|
+
* price *update* leg `refreshOraclePrices` runs before aggregating. Derived
|
|
41
|
+
* from {@link ORACLE_SOURCES}. The SDK never reads `process.env` — consumers
|
|
42
|
+
* resolve their own env var to this type.
|
|
43
|
+
*/
|
|
44
|
+
export type OracleSource = (typeof ORACLE_SOURCES)[number];
|
|
31
45
|
/**
|
|
32
46
|
* Off-chain payload fetched by a rule, tagged by `kind` so a caller holding
|
|
33
47
|
* several rules' results can tell them apart. `payload` is `unknown` here —
|
|
@@ -116,7 +130,14 @@ export interface UpdateDataProvider {
|
|
|
116
130
|
get(source: OracleSource, tickers: string[]): Promise<RuleUpdateData | null>;
|
|
117
131
|
}
|
|
118
132
|
export interface PriceUpdateRule {
|
|
119
|
-
|
|
133
|
+
/**
|
|
134
|
+
* `OracleSource`, not the wider `PriceUpdateRuleKind`: only selectable
|
|
135
|
+
* sources implement this port (`supra_rule`/`constant_rule` are plain
|
|
136
|
+
* collector-feed helpers), and the narrower type is what lets
|
|
137
|
+
* `refreshOraclePrices`'s per-source carry step switch exhaustively —
|
|
138
|
+
* adding a source without deciding its carry becomes a compile error.
|
|
139
|
+
*/
|
|
140
|
+
readonly kind: OracleSource;
|
|
120
141
|
/**
|
|
121
142
|
* `true` when this rule's on-chain update leg charges a per-update fee
|
|
122
143
|
* that must be paid from either a sponsor fund or `tx.gas` (Pyth Core:
|
|
@@ -11,10 +11,29 @@
|
|
|
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`
|
|
15
|
-
* `rule-registry.ts`, then drives fetch + `buildUpdateCalls`
|
|
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
|
+
/**
|
|
19
|
+
* The canonical list of selectable oracle sources — the SINGLE authority the
|
|
20
|
+
* {@link OracleSource} union derives from (the value-list→union derive
|
|
21
|
+
* idiom of `unified-client.ts`'s `NON_CLIENT_FIRST`, plus `Object.freeze`
|
|
22
|
+
* so the immutability is RUNTIME truth: `as const` alone would let a JS
|
|
23
|
+
* consumer push into the array and desync the membership Set built from it
|
|
24
|
+
* in `source-list.ts`). Runtime membership checks and the `ORACLE_SOURCE`
|
|
25
|
+
* env parser live there, on `isOracleSource` / `parseOracleSourceList`.
|
|
26
|
+
* Only sources belong here: `supra_rule` and `constant_rule` are auxiliary
|
|
27
|
+
* rules fed alongside whichever sources are selected (see
|
|
28
|
+
* `aggregateTicker`), not sources themselves — the `satisfies` keeps
|
|
29
|
+
* entries inside `PriceUpdateRuleKind` but adding an auxiliary rule to this
|
|
30
|
+
* list is an (incorrect) editorial decision this comment exists to prevent.
|
|
31
|
+
*/
|
|
32
|
+
export const ORACLE_SOURCES = Object.freeze([
|
|
33
|
+
"pyth_rule",
|
|
34
|
+
"pyth_lazer_rule",
|
|
35
|
+
"waterx_rule",
|
|
36
|
+
]);
|
|
18
37
|
/**
|
|
19
38
|
* Shared null → kind → shape guard ladder for a `PriceUpdateRule.buildUpdateCalls`
|
|
20
39
|
* payload — every rule's `buildUpdateCalls` needs the exact same three checks,
|
|
@@ -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;
|
package/dist/src/oracle/pyth.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
//
|
|
585
|
-
//
|
|
586
|
-
const endpoint = host.
|
|
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,
|