@waterx/sdk 4.3.3 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/waterx-sdk-integration/SKILL.md +41 -35
- package/README.md +81 -77
- package/dist/cjs/src/account/config.d.ts +3 -5
- package/dist/cjs/src/account/funding/wormhole.d.ts +1 -2
- package/dist/cjs/src/account/funding/wormhole.js +1 -2
- package/dist/cjs/src/oracle/aggregate.d.ts +45 -61
- package/dist/cjs/src/oracle/aggregate.js +138 -138
- package/dist/cjs/src/oracle/config.d.ts +35 -49
- package/dist/cjs/src/oracle/config.js +1 -1
- package/dist/cjs/src/oracle/host.d.ts +14 -19
- package/dist/cjs/src/oracle/host.js +3 -3
- package/dist/cjs/src/oracle/index.d.ts +25 -16
- package/dist/cjs/src/oracle/index.js +79 -66
- package/dist/cjs/src/oracle/price-update-rule.d.ts +104 -66
- package/dist/cjs/src/oracle/price-update-rule.js +24 -16
- package/dist/cjs/src/oracle/pyth-pro-history.d.ts +36 -0
- package/dist/cjs/src/oracle/pyth-pro-history.js +41 -0
- package/dist/cjs/src/oracle/read-plane.d.ts +35 -53
- package/dist/cjs/src/oracle/read-plane.js +26 -48
- package/dist/cjs/src/oracle/read-prices.d.ts +105 -0
- package/dist/cjs/src/oracle/read-prices.js +162 -0
- package/dist/cjs/src/oracle/rule-registry.d.ts +12 -12
- package/dist/cjs/src/oracle/rule-registry.js +12 -14
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +24 -3
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +40 -20
- package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +137 -12
- package/dist/cjs/src/oracle/rules/waterx-rule.js +318 -55
- package/dist/cjs/src/oracle/schedule.d.ts +109 -0
- package/dist/cjs/src/oracle/schedule.js +991 -0
- package/dist/cjs/src/oracle/source-list.d.ts +31 -27
- package/dist/cjs/src/oracle/source-list.js +43 -45
- package/dist/cjs/src/oracle/symbol-catalog.d.ts +54 -0
- package/dist/cjs/src/oracle/symbol-catalog.js +69 -0
- package/dist/cjs/src/oracle/update-fetch.d.ts +11 -15
- package/dist/cjs/src/oracle/update-fetch.js +12 -19
- package/dist/cjs/src/oracle/validate.d.ts +105 -0
- package/dist/cjs/src/oracle/validate.js +185 -0
- package/dist/cjs/src/oracle/weight-coverage.d.ts +79 -0
- package/dist/cjs/src/oracle/weight-coverage.js +173 -0
- package/dist/cjs/src/perp/client.d.ts +35 -52
- package/dist/cjs/src/perp/client.js +44 -17
- package/dist/cjs/src/perp/config-view.d.ts +5 -14
- package/dist/cjs/src/perp/config-view.js +5 -16
- package/dist/cjs/src/perp/config.d.ts +3 -3
- package/dist/cjs/src/perp/config.js +11 -13
- package/dist/cjs/src/perp/index.d.ts +4 -6
- package/dist/cjs/src/perp/index.js +35 -18
- package/dist/cjs/src/perp/tx-builders/common.d.ts +86 -48
- package/dist/cjs/src/perp/tx-builders/common.js +115 -47
- package/dist/cjs/src/perp/tx-builders/wlp.d.ts +3 -14
- package/dist/cjs/src/perp/tx-builders/wlp.js +6 -35
- package/dist/cjs/src/perp/tx-builders.d.ts +6 -5
- package/dist/cjs/src/perp/tx-builders.js +16 -10
- package/dist/cjs/src/unified-client.d.ts +8 -34
- package/dist/cjs/src/unified-client.js +3 -4
- package/dist/cjs/src/utils/config.d.ts +0 -8
- package/dist/cjs/src/utils/config.js +5 -13
- package/dist/src/account/config.d.ts +3 -5
- package/dist/src/account/funding/wormhole.d.ts +1 -2
- package/dist/src/account/funding/wormhole.js +1 -2
- package/dist/src/oracle/aggregate.d.ts +45 -61
- package/dist/src/oracle/aggregate.js +138 -137
- package/dist/src/oracle/config.d.ts +35 -49
- package/dist/src/oracle/config.js +1 -1
- package/dist/src/oracle/host.d.ts +14 -19
- package/dist/src/oracle/host.js +3 -3
- package/dist/src/oracle/index.d.ts +25 -16
- package/dist/src/oracle/index.js +55 -50
- package/dist/src/oracle/price-update-rule.d.ts +104 -66
- package/dist/src/oracle/price-update-rule.js +23 -16
- package/dist/src/oracle/pyth-pro-history.d.ts +36 -0
- package/dist/src/oracle/pyth-pro-history.js +38 -0
- package/dist/src/oracle/read-plane.d.ts +35 -53
- package/dist/src/oracle/read-plane.js +25 -47
- package/dist/src/oracle/read-prices.d.ts +105 -0
- package/dist/src/oracle/read-prices.js +156 -0
- package/dist/src/oracle/rule-registry.d.ts +12 -12
- package/dist/src/oracle/rule-registry.js +12 -14
- package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +24 -3
- package/dist/src/oracle/rules/pyth-lazer-rule.js +39 -20
- package/dist/src/oracle/rules/waterx-rule.d.ts +137 -12
- package/dist/src/oracle/rules/waterx-rule.js +314 -56
- package/dist/src/oracle/schedule.d.ts +109 -0
- package/dist/src/oracle/schedule.js +985 -0
- package/dist/src/oracle/source-list.d.ts +31 -27
- package/dist/src/oracle/source-list.js +42 -43
- package/dist/src/oracle/symbol-catalog.d.ts +54 -0
- package/dist/src/oracle/symbol-catalog.js +65 -0
- package/dist/src/oracle/update-fetch.d.ts +11 -15
- package/dist/src/oracle/update-fetch.js +12 -18
- package/dist/src/oracle/validate.d.ts +105 -0
- package/dist/src/oracle/validate.js +177 -0
- package/dist/src/oracle/weight-coverage.d.ts +79 -0
- package/dist/src/oracle/weight-coverage.js +166 -0
- package/dist/src/perp/client.d.ts +35 -52
- package/dist/src/perp/client.js +45 -18
- package/dist/src/perp/config-view.d.ts +5 -14
- package/dist/src/perp/config-view.js +5 -16
- package/dist/src/perp/config.d.ts +3 -3
- package/dist/src/perp/config.js +11 -13
- package/dist/src/perp/index.d.ts +4 -6
- package/dist/src/perp/index.js +11 -5
- package/dist/src/perp/tx-builders/common.d.ts +86 -48
- package/dist/src/perp/tx-builders/common.js +114 -48
- package/dist/src/perp/tx-builders/wlp.d.ts +3 -14
- package/dist/src/perp/tx-builders/wlp.js +6 -35
- package/dist/src/perp/tx-builders.d.ts +6 -5
- package/dist/src/perp/tx-builders.js +15 -6
- package/dist/src/unified-client.d.ts +8 -34
- package/dist/src/unified-client.js +3 -4
- package/dist/src/utils/config.d.ts +0 -8
- package/dist/src/utils/config.js +5 -12
- package/package.json +1 -1
- package/dist/cjs/src/generated/pyth_sponsor_rule/deps/sui/balance.d.ts +0 -12
- package/dist/cjs/src/generated/pyth_sponsor_rule/deps/sui/balance.js +0 -17
- package/dist/cjs/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.d.ts +0 -68
- package/dist/cjs/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.js +0 -113
- package/dist/cjs/src/generated/waterx_pyth_rule/deps/sui/vec_map.d.ts +0 -36
- package/dist/cjs/src/generated/waterx_pyth_rule/deps/sui/vec_map.js +0 -31
- package/dist/cjs/src/generated/waterx_pyth_rule/pyth_rule.d.ts +0 -192
- package/dist/cjs/src/generated/waterx_pyth_rule/pyth_rule.js +0 -214
- package/dist/cjs/src/oracle/pyth.d.ts +0 -227
- package/dist/cjs/src/oracle/pyth.js +0 -652
- package/dist/cjs/src/oracle/rules/pyth-core-rule.d.ts +0 -15
- package/dist/cjs/src/oracle/rules/pyth-core-rule.js +0 -100
- package/dist/cjs/src/oracle/rules/pyth-rule.d.ts +0 -11
- package/dist/cjs/src/oracle/rules/pyth-rule.js +0 -29
- package/dist/cjs/src/oracle/rules/sponsor.d.ts +0 -32
- package/dist/cjs/src/oracle/rules/sponsor.js +0 -56
- package/dist/src/generated/pyth_sponsor_rule/deps/sui/balance.d.ts +0 -12
- package/dist/src/generated/pyth_sponsor_rule/deps/sui/balance.js +0 -14
- package/dist/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.d.ts +0 -68
- package/dist/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.js +0 -73
- package/dist/src/generated/waterx_pyth_rule/deps/sui/vec_map.d.ts +0 -36
- package/dist/src/generated/waterx_pyth_rule/deps/sui/vec_map.js +0 -27
- package/dist/src/generated/waterx_pyth_rule/pyth_rule.d.ts +0 -192
- package/dist/src/generated/waterx_pyth_rule/pyth_rule.js +0 -170
- package/dist/src/oracle/pyth.d.ts +0 -227
- package/dist/src/oracle/pyth.js +0 -638
- package/dist/src/oracle/rules/pyth-core-rule.d.ts +0 -15
- package/dist/src/oracle/rules/pyth-core-rule.js +0 -97
- package/dist/src/oracle/rules/pyth-rule.d.ts +0 -11
- package/dist/src/oracle/rules/pyth-rule.js +0 -26
- package/dist/src/oracle/rules/sponsor.d.ts +0 -32
- package/dist/src/oracle/rules/sponsor.js +0 -52
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `PriceUpdateRule` — the strategy port for one oracle rule generation: fetch
|
|
3
3
|
* its off-chain update payload and emit the PTB calls that verify/push that
|
|
4
|
-
* update on-chain (e.g.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* {@link RuleUpdateHandle}). Implementations: `
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
4
|
+
* update on-chain (e.g. Lazer's single signature-verify step). Feeding the
|
|
5
|
+
* refreshed price into an oracle `PriceCollector` is a separate step that
|
|
6
|
+
* stays in `aggregate.ts` — this port covers fetch + verify/push only
|
|
7
|
+
* (`buildUpdateCalls` may hand the feed step a PTB value via
|
|
8
|
+
* {@link RuleUpdateHandle}). Implementations: `PythLazerRule` (Lazer signed
|
|
9
|
+
* updates) and `WaterxRule` (quote-center ed25519). `ConstantRule` and
|
|
10
|
+
* `SupraRule` do NOT implement this port — they remain plain collector-feed
|
|
11
|
+
* helpers wired directly into `aggregate.ts`.
|
|
12
12
|
*
|
|
13
13
|
* This file defines the port only — routing IS wired: `aggregate.ts`'s
|
|
14
14
|
* `refreshOraclePrices` resolves a concrete rule per `host.oracleSources`
|
|
@@ -17,25 +17,29 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
|
|
19
19
|
import type { OracleHost } from "./host.ts";
|
|
20
|
-
|
|
21
|
-
export type PriceUpdateRuleKind = "pyth_rule" | "pyth_lazer_rule" | "supra_rule" | "constant_rule" | "waterx_rule";
|
|
20
|
+
export type PriceUpdateRuleKind = "pyth_lazer_rule" | "supra_rule" | "constant_rule" | "waterx_rule";
|
|
22
21
|
/**
|
|
23
22
|
* The canonical list of selectable oracle sources — the SINGLE authority the
|
|
24
23
|
* {@link OracleSource} union derives from (the value-list→union derive
|
|
25
24
|
* idiom of `unified-client.ts`'s `NON_CLIENT_FIRST`, plus `Object.freeze`
|
|
26
25
|
* so the immutability is RUNTIME truth: `as const` alone would let a JS
|
|
27
|
-
* consumer push into the array and
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* consumer push into the array, and `deriveOracleSources` (`source-list.ts`)
|
|
27
|
+
* walks exactly this list to decide the fed set — a pushed entry would name a
|
|
28
|
+
* source with no rule module behind it.
|
|
30
29
|
* Only sources belong here: `supra_rule` and `constant_rule` are auxiliary
|
|
31
30
|
* rules fed alongside whichever sources are selected (see
|
|
32
31
|
* `aggregateTicker`), not sources themselves — the `satisfies` keeps
|
|
33
32
|
* entries inside `PriceUpdateRuleKind` but adding an auxiliary rule to this
|
|
34
33
|
* list is an (incorrect) editorial decision this comment exists to prevent.
|
|
34
|
+
*
|
|
35
|
+
* `pyth_rule` (Pyth Core, Hermes VAA) was RETIRED in 5.0.0 — it is no longer
|
|
36
|
+
* a `PriceUpdateRuleKind` at all. Its config block is still published in the
|
|
37
|
+
* live deployments and is inert precisely because it is absent from this
|
|
38
|
+
* list: `deriveOracleSources` can never select it.
|
|
35
39
|
*/
|
|
36
|
-
export declare const ORACLE_SOURCES: readonly ["
|
|
40
|
+
export declare const ORACLE_SOURCES: readonly ["pyth_lazer_rule", "waterx_rule"];
|
|
37
41
|
/**
|
|
38
|
-
* The
|
|
42
|
+
* The implementable price-update sources — the candidates `deriveOracleSources` picks from (see
|
|
39
43
|
* `OracleHost.oracleSources`) — i.e. rules that can serve as the on-chain
|
|
40
44
|
* price *update* leg `refreshOraclePrices` runs before aggregating. Derived
|
|
41
45
|
* from {@link ORACLE_SOURCES}. The SDK never reads `process.env` — consumers
|
|
@@ -45,8 +49,8 @@ export type OracleSource = (typeof ORACLE_SOURCES)[number];
|
|
|
45
49
|
/**
|
|
46
50
|
* Off-chain payload fetched by a rule, tagged by `kind` so a caller holding
|
|
47
51
|
* several rules' results can tell them apart. `payload` is `unknown` here —
|
|
48
|
-
* each rule implementation narrows it to its own shape (e.g. `
|
|
49
|
-
* `{
|
|
52
|
+
* each rule implementation narrows it to its own shape (e.g. `PythLazerRule`'s
|
|
53
|
+
* `{ update: Uint8Array; feedIds: number[] }`). `null` for rules with no
|
|
50
54
|
* off-chain fetch (e.g. `ConstantRule`) or when there is nothing to fetch.
|
|
51
55
|
*/
|
|
52
56
|
export type RuleUpdateData = {
|
|
@@ -62,9 +66,8 @@ export type RuleUpdateData = {
|
|
|
62
66
|
* empty ticker list upstream produced nothing to build).
|
|
63
67
|
* 2. `data.kind !== kind` throws BEFORE the shape check runs. This order is
|
|
64
68
|
* load-bearing, not stylistic: two rules' payloads can share an identical
|
|
65
|
-
* shape
|
|
66
|
-
*
|
|
67
|
-
* wrong-kind payload silently pass as this rule's own.
|
|
69
|
+
* shape, so checking shape first would let a wrong-kind payload silently
|
|
70
|
+
* pass as this rule's own.
|
|
68
71
|
* 3. `!isShape(data.payload)` throws for a same-`kind` payload whose shape
|
|
69
72
|
* doesn't match this rule's own (e.g. a hand-built test double).
|
|
70
73
|
*
|
|
@@ -75,18 +78,18 @@ export type RuleUpdateData = {
|
|
|
75
78
|
* `data` may carry past step 2.
|
|
76
79
|
* @param isShape - Type predicate narrowing `data.payload` to `T`.
|
|
77
80
|
* @param shapeDescription - Human-readable shape, quoted verbatim into the
|
|
78
|
-
* shape-mismatch error (e.g. `"{
|
|
81
|
+
* shape-mismatch error (e.g. `"{ update: Uint8Array; feedIds: number[] }"`).
|
|
79
82
|
*/
|
|
80
83
|
export declare function assertRuleUpdateData<T>(data: RuleUpdateData, kind: PriceUpdateRuleKind, isShape: (payload: unknown) => payload is T, shapeDescription: string): T | null;
|
|
81
84
|
/**
|
|
82
85
|
* PTB value handle a rule's {@link PriceUpdateRule.buildUpdateCalls} may
|
|
83
86
|
* return when its collector-feed leg needs a value produced by the update leg
|
|
84
|
-
* *within the same PTB*.
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
87
|
+
* *within the same PTB*. The Lazer rule returns the verified-update result of
|
|
88
|
+
* its network's verify entry — one signature verification covers every feed
|
|
89
|
+
* in the payload, and `pyth_lazer_rule::feed` takes it by reference per
|
|
90
|
+
* ticker (see `aggregateTicker`'s `lazerUpdate` arg). `WaterxRule` needs none
|
|
91
|
+
* (its verify+feed is bundled into the per-ticker collect call), so it
|
|
92
|
+
* returns `void`.
|
|
90
93
|
*/
|
|
91
94
|
export type RuleUpdateHandle = {
|
|
92
95
|
readonly kind: "pyth_lazer_rule";
|
|
@@ -101,26 +104,12 @@ export type RuleUpdateHandle = {
|
|
|
101
104
|
*/
|
|
102
105
|
readonly update: TransactionArgument;
|
|
103
106
|
};
|
|
104
|
-
/**
|
|
105
|
-
* Options for {@link PriceUpdateRule.buildUpdateCalls}. Mirrors
|
|
106
|
-
* `buildPythPriceUpdateCalls` / `updatePythPrices`'s own opts shape in
|
|
107
|
-
* `./pyth.ts` — `cache` shares on-chain Pyth state reads across builders;
|
|
108
|
-
* `feeSource` is the single {@link OracleFeeSource} already resolved by the
|
|
109
|
-
* caller (see its own doc for where/how). Both fields are Pyth-Core-specific
|
|
110
|
-
* mechanics; `refreshOraclePrices` passes the same `BuildUpdateOpts` to every
|
|
111
|
-
* rule uniformly, so a non-Pyth-Core rule (e.g. `PythLazerRule`, which
|
|
112
|
-
* charges no update fee) simply ignores whichever fields it has no use for.
|
|
113
|
-
*/
|
|
114
|
-
export interface BuildUpdateOpts {
|
|
115
|
-
readonly cache?: PythCache;
|
|
116
|
-
readonly feeSource?: OracleFeeSource;
|
|
117
|
-
}
|
|
118
107
|
/**
|
|
119
108
|
* Injectable update-data cache seam for `refreshOraclePrices` (`aggregate.ts`).
|
|
120
|
-
* A BE consumer (e.g. a prefetch cache that polls
|
|
121
|
-
* keeps a hot in-memory/Redis entry per source) implements
|
|
122
|
-
* as `refreshOraclePrices`'s `updateDataProvider` opt; the
|
|
123
|
-
* implements one. `get` is checked before the rule's own live
|
|
109
|
+
* A BE consumer (e.g. a prefetch cache that polls Lazer/quote-center
|
|
110
|
+
* out-of-band and keeps a hot in-memory/Redis entry per source) implements
|
|
111
|
+
* this and passes it as `refreshOraclePrices`'s `updateDataProvider` opt; the
|
|
112
|
+
* SDK itself never implements one. `get` is checked before the rule's own live
|
|
124
113
|
* `fetchUpdateData` for that group of tickers — a `null` return means "no
|
|
125
114
|
* cached data, fetch live" (mirrors {@link RuleUpdateData}'s own `null`
|
|
126
115
|
* variant: there is no separate signal for "the cache legitimately has
|
|
@@ -137,6 +126,40 @@ export interface BuildUpdateOpts {
|
|
|
137
126
|
export interface UpdateDataProvider {
|
|
138
127
|
get(source: OracleSource, tickers: string[]): Promise<RuleUpdateData | null>;
|
|
139
128
|
}
|
|
129
|
+
/** The credential kinds a rule can declare via {@link PriceUpdateRule.credential}. */
|
|
130
|
+
export type OracleCredentialKind = "pyth_api_key";
|
|
131
|
+
/**
|
|
132
|
+
* Caller-supplied credential values keyed BY {@link OracleCredentialKind} —
|
|
133
|
+
* the one shape both enforcement points check against, so neither has to
|
|
134
|
+
* branch on the kind. `refreshOraclePrices` builds it from a live
|
|
135
|
+
* `OracleHost` ({@link oracleCredentialsFromHost}); `missingOracleCredentials`
|
|
136
|
+
* builds it from a consumer's raw env values. Adding a kind means extending
|
|
137
|
+
* the union above plus those two adapters — never an `if` chain at a check
|
|
138
|
+
* site.
|
|
139
|
+
*/
|
|
140
|
+
export type OracleCredentials = Partial<Record<OracleCredentialKind, string>>;
|
|
141
|
+
/** The credentials a live client carries, in {@link OracleCredentials} shape. */
|
|
142
|
+
export declare function oracleCredentialsFromHost(host: OracleHost): OracleCredentials;
|
|
143
|
+
/**
|
|
144
|
+
* A rule's off-chain credential requirement — the KIND it needs plus the error
|
|
145
|
+
* it wants raised when that credential is absent, as ONE object so the two can
|
|
146
|
+
* never drift apart.
|
|
147
|
+
*
|
|
148
|
+
* Both enforcement points are fully generic over this: neither names a kind,
|
|
149
|
+
* and neither constructs another rule's error. `refreshOraclePrices`'s hoisted
|
|
150
|
+
* pre-check (`aggregate.ts`) throws `missing()` before any fetch or PTB
|
|
151
|
+
* mutation; `missingOracleCredentials` (`validate.ts`) reports `kind` for a
|
|
152
|
+
* consumer's boot-time env audit.
|
|
153
|
+
*/
|
|
154
|
+
export interface OracleCredentialRequirement {
|
|
155
|
+
readonly kind: OracleCredentialKind;
|
|
156
|
+
/**
|
|
157
|
+
* The rule's OWN error for "declared credential absent". Owning it here is
|
|
158
|
+
* what keeps the orchestrator from importing (and mis-attributing) one
|
|
159
|
+
* rule's error type on behalf of every rule that shares a kind.
|
|
160
|
+
*/
|
|
161
|
+
missing(): Error;
|
|
162
|
+
}
|
|
140
163
|
export interface PriceUpdateRule {
|
|
141
164
|
/**
|
|
142
165
|
* `OracleSource`, not the wider `PriceUpdateRuleKind`: only selectable
|
|
@@ -147,22 +170,18 @@ export interface PriceUpdateRule {
|
|
|
147
170
|
*/
|
|
148
171
|
readonly kind: OracleSource;
|
|
149
172
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* `
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* `tx` while the fee-charging group is left unpayable). A referential
|
|
161
|
-
* check against a specific rule instance (e.g. `=== PythCoreRule`) would
|
|
162
|
-
* silently stop protecting a future fee-charging rule, or a test double
|
|
163
|
-
* standing in for one — this field is the honest, extensible signal.
|
|
173
|
+
* The credential this rule's `fetchUpdateData` cannot run without, or absent
|
|
174
|
+
* for a credential-free rule. `PythLazerRule` declares `"pyth_api_key"`
|
|
175
|
+
* (Lazer is auth-first: `host.pyth.api_key` Bearer) with its own
|
|
176
|
+
* `LazerApiKeyMissingError`; `WaterxRule` declares nothing (the quote-center
|
|
177
|
+
* read surface is public).
|
|
178
|
+
*
|
|
179
|
+
* Two consumers key off this instead of hardcoding per-rule knowledge —
|
|
180
|
+
* `refreshOraclePrices`'s hoisted pre-check and `missingOracleCredentials` —
|
|
181
|
+
* and neither branches on the kind or names an error type. See
|
|
182
|
+
* {@link OracleCredentialRequirement}.
|
|
164
183
|
*/
|
|
165
|
-
readonly
|
|
184
|
+
readonly credential?: OracleCredentialRequirement;
|
|
166
185
|
/** Tickers this rule can serve in this environment (from config feeds + enabled). */
|
|
167
186
|
supportedTickers(host: OracleHost): string[];
|
|
168
187
|
/**
|
|
@@ -182,9 +201,10 @@ export interface PriceUpdateRule {
|
|
|
182
201
|
* altitude violation this method removes):
|
|
183
202
|
*
|
|
184
203
|
* - A non-null result MUST be valid {@link buildUpdateCalls} input covering
|
|
185
|
-
* exactly `tickers` — a divisible payload (
|
|
186
|
-
* returns a subset; an indivisible payload (Lazer's single signed message
|
|
187
|
-
* returns the whole payload iff every requested
|
|
204
|
+
* exactly `tickers` — a divisible payload (waterx's per-symbol leaves)
|
|
205
|
+
* returns a subset; an indivisible payload (Lazer's single signed message,
|
|
206
|
+
* waterx's batch envelope) returns the whole payload iff every requested
|
|
207
|
+
* ticker is covered.
|
|
188
208
|
* - A ticker this payload cannot serve → `null` (miss), NEVER a silent
|
|
189
209
|
* partial. `null` mirrors {@link UpdateDataProvider.get}'s convention: the
|
|
190
210
|
* caller falls back to a live {@link fetchUpdateData} for those tickers.
|
|
@@ -195,14 +215,32 @@ export interface PriceUpdateRule {
|
|
|
195
215
|
* bug), it does not miss.
|
|
196
216
|
*/
|
|
197
217
|
narrowUpdateData(host: OracleHost, data: RuleUpdateData, tickers: string[]): RuleUpdateData;
|
|
218
|
+
/**
|
|
219
|
+
* The per-symbol single-use identity of a payload's signed data, or `null`
|
|
220
|
+
* when this rule's updates carry no replay-guarded identity (then the
|
|
221
|
+
* method may also be absent entirely). This is the rule-owned key of the
|
|
222
|
+
* on-chain F-014 replay guard: submitting the SAME identity twice for a
|
|
223
|
+
* symbol is at best a paid-for abstain (the dual-rule collect entries) and
|
|
224
|
+
* at worst an `EReplayedSignature` abort (the single-rule feed entries) —
|
|
225
|
+
* so a consumer serving cached update data (e.g. a BE serve-at-most-once
|
|
226
|
+
* cache) keys its guard off this map instead of re-implementing each
|
|
227
|
+
* rule's payload anatomy.
|
|
228
|
+
*
|
|
229
|
+
* `WaterxRule`: leaves → `symbol → signed_timestamp_ms`; envelope →
|
|
230
|
+
* `symbol → timestamp_ms` (per item; the envelope's one signing timestamp
|
|
231
|
+
* is every covered symbol's identity). `PythLazerRule` does not implement
|
|
232
|
+
* it — a Lazer verify is not identity-replay-guarded on-chain.
|
|
233
|
+
*/
|
|
234
|
+
updateIdentityBySymbol?(data: RuleUpdateData): Map<string, bigint> | null;
|
|
198
235
|
/**
|
|
199
236
|
* Emit verify/update moveCalls + any per-rule setup into the PTB. Returns a
|
|
200
237
|
* {@link RuleUpdateHandle} when the rule's collector-feed leg needs a PTB
|
|
201
238
|
* value from this step (Lazer's verified `Update`); rules whose feed leg
|
|
202
|
-
*
|
|
239
|
+
* needs nothing from it return `void`. Takes no `tickers` param —
|
|
203
240
|
* every implementation derives everything it needs from `data.payload`
|
|
204
241
|
* (the tickers a group covers were already fixed when `fetchUpdateData`
|
|
205
|
-
* built that payload)
|
|
242
|
+
* built that payload) — and no options: nothing a rule needs at build time
|
|
243
|
+
* is caller-tunable, so there is no bag to thread.
|
|
206
244
|
*/
|
|
207
|
-
buildUpdateCalls(tx: Transaction, host: OracleHost, data: RuleUpdateData
|
|
245
|
+
buildUpdateCalls(tx: Transaction, host: OracleHost, data: RuleUpdateData): Promise<RuleUpdateHandle | void> | RuleUpdateHandle | void;
|
|
208
246
|
}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* `PriceUpdateRule` — the strategy port for one oracle rule generation: fetch
|
|
4
4
|
* its off-chain update payload and emit the PTB calls that verify/push that
|
|
5
|
-
* update on-chain (e.g.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* {@link RuleUpdateHandle}). Implementations: `
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* update on-chain (e.g. Lazer's single signature-verify step). Feeding the
|
|
6
|
+
* refreshed price into an oracle `PriceCollector` is a separate step that
|
|
7
|
+
* stays in `aggregate.ts` — this port covers fetch + verify/push only
|
|
8
|
+
* (`buildUpdateCalls` may hand the feed step a PTB value via
|
|
9
|
+
* {@link RuleUpdateHandle}). Implementations: `PythLazerRule` (Lazer signed
|
|
10
|
+
* updates) and `WaterxRule` (quote-center ed25519). `ConstantRule` and
|
|
11
|
+
* `SupraRule` do NOT implement this port — they remain plain collector-feed
|
|
12
|
+
* helpers wired directly into `aggregate.ts`.
|
|
13
13
|
*
|
|
14
14
|
* This file defines the port only — routing IS wired: `aggregate.ts`'s
|
|
15
15
|
* `refreshOraclePrices` resolves a concrete rule per `host.oracleSources`
|
|
@@ -19,22 +19,27 @@
|
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
20
|
exports.ORACLE_SOURCES = void 0;
|
|
21
21
|
exports.assertRuleUpdateData = assertRuleUpdateData;
|
|
22
|
+
exports.oracleCredentialsFromHost = oracleCredentialsFromHost;
|
|
22
23
|
/**
|
|
23
24
|
* The canonical list of selectable oracle sources — the SINGLE authority the
|
|
24
25
|
* {@link OracleSource} union derives from (the value-list→union derive
|
|
25
26
|
* idiom of `unified-client.ts`'s `NON_CLIENT_FIRST`, plus `Object.freeze`
|
|
26
27
|
* so the immutability is RUNTIME truth: `as const` alone would let a JS
|
|
27
|
-
* consumer push into the array and
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* consumer push into the array, and `deriveOracleSources` (`source-list.ts`)
|
|
29
|
+
* walks exactly this list to decide the fed set — a pushed entry would name a
|
|
30
|
+
* source with no rule module behind it.
|
|
30
31
|
* Only sources belong here: `supra_rule` and `constant_rule` are auxiliary
|
|
31
32
|
* rules fed alongside whichever sources are selected (see
|
|
32
33
|
* `aggregateTicker`), not sources themselves — the `satisfies` keeps
|
|
33
34
|
* entries inside `PriceUpdateRuleKind` but adding an auxiliary rule to this
|
|
34
35
|
* list is an (incorrect) editorial decision this comment exists to prevent.
|
|
36
|
+
*
|
|
37
|
+
* `pyth_rule` (Pyth Core, Hermes VAA) was RETIRED in 5.0.0 — it is no longer
|
|
38
|
+
* a `PriceUpdateRuleKind` at all. Its config block is still published in the
|
|
39
|
+
* live deployments and is inert precisely because it is absent from this
|
|
40
|
+
* list: `deriveOracleSources` can never select it.
|
|
35
41
|
*/
|
|
36
42
|
exports.ORACLE_SOURCES = Object.freeze([
|
|
37
|
-
"pyth_rule",
|
|
38
43
|
"pyth_lazer_rule",
|
|
39
44
|
"waterx_rule",
|
|
40
45
|
]);
|
|
@@ -47,9 +52,8 @@ exports.ORACLE_SOURCES = Object.freeze([
|
|
|
47
52
|
* empty ticker list upstream produced nothing to build).
|
|
48
53
|
* 2. `data.kind !== kind` throws BEFORE the shape check runs. This order is
|
|
49
54
|
* load-bearing, not stylistic: two rules' payloads can share an identical
|
|
50
|
-
* shape
|
|
51
|
-
*
|
|
52
|
-
* wrong-kind payload silently pass as this rule's own.
|
|
55
|
+
* shape, so checking shape first would let a wrong-kind payload silently
|
|
56
|
+
* pass as this rule's own.
|
|
53
57
|
* 3. `!isShape(data.payload)` throws for a same-`kind` payload whose shape
|
|
54
58
|
* doesn't match this rule's own (e.g. a hand-built test double).
|
|
55
59
|
*
|
|
@@ -60,7 +64,7 @@ exports.ORACLE_SOURCES = Object.freeze([
|
|
|
60
64
|
* `data` may carry past step 2.
|
|
61
65
|
* @param isShape - Type predicate narrowing `data.payload` to `T`.
|
|
62
66
|
* @param shapeDescription - Human-readable shape, quoted verbatim into the
|
|
63
|
-
* shape-mismatch error (e.g. `"{
|
|
67
|
+
* shape-mismatch error (e.g. `"{ update: Uint8Array; feedIds: number[] }"`).
|
|
64
68
|
*/
|
|
65
69
|
function assertRuleUpdateData(data, kind, isShape, shapeDescription) {
|
|
66
70
|
if (!data)
|
|
@@ -74,3 +78,7 @@ function assertRuleUpdateData(data, kind, isShape, shapeDescription) {
|
|
|
74
78
|
}
|
|
75
79
|
return data.payload;
|
|
76
80
|
}
|
|
81
|
+
/** The credentials a live client carries, in {@link OracleCredentials} shape. */
|
|
82
|
+
function oracleCredentialsFromHost(host) {
|
|
83
|
+
return { pyth_api_key: host.pyth.api_key };
|
|
84
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pyth-pro-history.ts` — Pyth Pro chart history
|
|
3
|
+
* (`GET /v1/{channel}/history`), the TradingView-UDF-shaped bar source that
|
|
4
|
+
* replaces Benchmarks for chart backfill. Bearer-REQUIRED (unlike the symbol
|
|
5
|
+
* catalog): consumers call this server-side with their `PYTH_API_KEY` and
|
|
6
|
+
* keep their own fallback policy (e.g. Benchmarks on 403/5xx while its
|
|
7
|
+
* keyless window lasts).
|
|
8
|
+
*
|
|
9
|
+
* The `symbol` must be FULLY QUALIFIED (`Crypto.BTC/USD`,
|
|
10
|
+
* `Equity.US.AAPL/USD` — the catalog's `symbol` field); a bare pair 404s.
|
|
11
|
+
* `channel` picks the aggregation cadence the key's grant allows (e.g.
|
|
12
|
+
* `fixed_rate@1000ms`).
|
|
13
|
+
*/
|
|
14
|
+
import { type FetchPolicy } from "./update-fetch.ts";
|
|
15
|
+
/**
|
|
16
|
+
* Fetch one history window. Returns the endpoint's TradingView-UDF-style JSON
|
|
17
|
+
* body VERBATIM (`unknown` — e.g. `{ s: "ok", t: [...], o: [...], h: [...],
|
|
18
|
+
* l: [...], c: [...] }`): bar-shape interpretation stays with the charting
|
|
19
|
+
* consumer, the SDK only owns transport + auth. Throws on non-2xx with the
|
|
20
|
+
* body attached (a 403 here is the caller's fallback trigger).
|
|
21
|
+
*/
|
|
22
|
+
export declare function fetchPythProHistory(opts: {
|
|
23
|
+
/** Aggregation channel path segment, e.g. `"fixed_rate@1000ms"`. */
|
|
24
|
+
channel: string;
|
|
25
|
+
/** Fully-qualified reference symbol, e.g. `"Crypto.BTC/USD"`. */
|
|
26
|
+
symbol: string;
|
|
27
|
+
/** UDF resolution, e.g. `"1"`, `"60"`, `"1D"`. */
|
|
28
|
+
resolution: string;
|
|
29
|
+
/** Window start (unix seconds, inclusive). */
|
|
30
|
+
fromSec: number;
|
|
31
|
+
/** Window end (unix seconds, inclusive). */
|
|
32
|
+
toSec: number;
|
|
33
|
+
/** Pyth Pro Bearer key — REQUIRED by the endpoint. */
|
|
34
|
+
apiKey: string;
|
|
35
|
+
fetch?: FetchPolicy;
|
|
36
|
+
}): Promise<unknown>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `pyth-pro-history.ts` — Pyth Pro chart history
|
|
4
|
+
* (`GET /v1/{channel}/history`), the TradingView-UDF-shaped bar source that
|
|
5
|
+
* replaces Benchmarks for chart backfill. Bearer-REQUIRED (unlike the symbol
|
|
6
|
+
* catalog): consumers call this server-side with their `PYTH_API_KEY` and
|
|
7
|
+
* keep their own fallback policy (e.g. Benchmarks on 403/5xx while its
|
|
8
|
+
* keyless window lasts).
|
|
9
|
+
*
|
|
10
|
+
* The `symbol` must be FULLY QUALIFIED (`Crypto.BTC/USD`,
|
|
11
|
+
* `Equity.US.AAPL/USD` — the catalog's `symbol` field); a bare pair 404s.
|
|
12
|
+
* `channel` picks the aggregation cadence the key's grant allows (e.g.
|
|
13
|
+
* `fixed_rate@1000ms`).
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.fetchPythProHistory = fetchPythProHistory;
|
|
17
|
+
const symbol_catalog_ts_1 = require("./symbol-catalog.js");
|
|
18
|
+
const update_fetch_ts_1 = require("./update-fetch.js");
|
|
19
|
+
/**
|
|
20
|
+
* Fetch one history window. Returns the endpoint's TradingView-UDF-style JSON
|
|
21
|
+
* body VERBATIM (`unknown` — e.g. `{ s: "ok", t: [...], o: [...], h: [...],
|
|
22
|
+
* l: [...], c: [...] }`): bar-shape interpretation stays with the charting
|
|
23
|
+
* consumer, the SDK only owns transport + auth. Throws on non-2xx with the
|
|
24
|
+
* body attached (a 403 here is the caller's fallback trigger).
|
|
25
|
+
*/
|
|
26
|
+
async function fetchPythProHistory(opts) {
|
|
27
|
+
const url = (0, update_fetch_ts_1.joinEndpointPath)(symbol_catalog_ts_1.PYTH_PRO_API_ENDPOINT, `v1/${opts.channel}/history`);
|
|
28
|
+
url.searchParams.set("symbol", opts.symbol);
|
|
29
|
+
url.searchParams.set("resolution", opts.resolution);
|
|
30
|
+
url.searchParams.set("from", String(opts.fromSec));
|
|
31
|
+
url.searchParams.set("to", String(opts.toSec));
|
|
32
|
+
// `opts.fetch` is the full `FetchPolicy`, which itself has an `apiKey`, so
|
|
33
|
+
// spreading it AFTER the explicit one let `{ fetch: { apiKey: undefined } }`
|
|
34
|
+
// silently strip the Bearer this endpoint requires — a 403 with no clue why.
|
|
35
|
+
// The dedicated argument wins; the policy supplies it only as a fallback.
|
|
36
|
+
const res = await (0, update_fetch_ts_1.fetchWithPolicy)(url.toString(), {}, { ...opts.fetch, apiKey: opts.apiKey ?? opts.fetch?.apiKey });
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
throw new Error(`Pyth Pro history fetch failed: ${res.status} ${await res.text()}`);
|
|
39
|
+
}
|
|
40
|
+
return res.json();
|
|
41
|
+
}
|
|
@@ -1,70 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
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.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* (FE/BE price facades) resolve through this instead
|
|
11
|
-
*
|
|
3
|
+
* tickers a source can PRICE off-chain, and with which ids. Every source
|
|
4
|
+
* reads through ITS OWN feeds namespace — `pyth_lazer_rule` via its integer
|
|
5
|
+
* ids on the Lazer HTTP API, `waterx_rule` via its tickers on the
|
|
6
|
+
* quote-center — so a source's write set and read set coincide by
|
|
7
|
+
* construction. (Until 5.0.0 Lazer reads borrowed `pyth_rule.feeds` hex ids
|
|
8
|
+
* on a Hermes-compatible endpoint; that cross-block dependency, the whole
|
|
9
|
+
* hermes plane, and the `unreadable` diagnostic are gone with the `pyth_rule`
|
|
10
|
+
* retirement.) Consumers (FE/BE price facades) resolve through this instead
|
|
11
|
+
* of hardcoding feed namespaces, and execute plans via the sibling
|
|
12
|
+
* `read-prices.ts` executors.
|
|
12
13
|
*/
|
|
13
|
-
import type { Network } from "../constants.ts";
|
|
14
14
|
import type { OracleHost } from "./host.ts";
|
|
15
15
|
import type { OracleSource } from "./price-update-rule.ts";
|
|
16
16
|
/**
|
|
17
17
|
* One source's read plan for a requested ticker set.
|
|
18
18
|
*
|
|
19
|
-
* - `plane: "
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* - `plane: "quote_center"` (
|
|
24
|
-
*
|
|
25
|
-
* ABSENT block (source listed,
|
|
26
|
-
*
|
|
27
|
-
* quote-center — it happily serves
|
|
28
|
-
*
|
|
29
|
-
* misconfiguration is caught loudly by
|
|
30
|
-
* client creation instead.
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
19
|
+
* - `plane: "lazer"` (`pyth_lazer_rule`) — price via the Lazer HTTP API
|
|
20
|
+
* (`readLazerPrices` in `read-prices.ts`), one entry per servable ticker
|
|
21
|
+
* mapped to its INTEGER Lazer feed id from `pyth_lazer_rule.feeds`. Auth is
|
|
22
|
+
* the caller's `pythApiKey` Bearer; the endpoint is `LAZER_INFRA`'s own.
|
|
23
|
+
* - `plane: "quote_center"` (`waterx_rule`) — price via the quote-center
|
|
24
|
+
* (`readQuoteCenterPrices` in `read-prices.ts`), keyed by ticker; served
|
|
25
|
+
* set = the `waterx_rule.feeds` block. An ABSENT block (source listed,
|
|
26
|
+
* package missing from the loaded config) serves NOTHING: claiming tickers
|
|
27
|
+
* would silently reroute reads to the quote-center — it happily serves
|
|
28
|
+
* symbols regardless of on-chain config — and swallow tickers a
|
|
29
|
+
* later-listed source could price. The misconfiguration is caught loudly by
|
|
30
|
+
* `assertOracleWriteCoverage` (`validate.ts`) at client creation instead.
|
|
31
|
+
*
|
|
32
|
+
* A ticker absent from a plan is simply not servable by THIS source's read
|
|
33
|
+
* plane — callers decide how to degrade (typically: ask the next source in
|
|
34
|
+
* their fed set, then omit). Because every source reads its own
|
|
35
|
+
* feeds, write set == read set — there is no separate read-coverage
|
|
36
|
+
* diagnostic to carry.
|
|
36
37
|
*/
|
|
37
38
|
export type OracleReadPlan = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
plane: "hermes";
|
|
41
|
-
feedIdByTicker: Map<string, string>;
|
|
39
|
+
plane: "lazer";
|
|
40
|
+
feedIdByTicker: Map<string, number>;
|
|
42
41
|
} | {
|
|
43
42
|
plane: "quote_center";
|
|
44
43
|
tickers: string[];
|
|
45
|
-
}
|
|
44
|
+
};
|
|
45
|
+
/** The tickers a resolved plan can actually serve, regardless of plane. */
|
|
46
|
+
export declare function readPlanTickers(plan: OracleReadPlan): string[];
|
|
46
47
|
/**
|
|
47
48
|
* Resolve `source`'s read plan for `tickers`. Pure config lookup — no
|
|
48
|
-
* network, no endpoint resolution (endpoints come from
|
|
49
|
-
* `
|
|
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.
|
|
49
|
+
* network, no endpoint resolution (endpoints come from `LAZER_INFRA` /
|
|
50
|
+
* `waterxQuoteCenterEndpoint` / the deployment's own env).
|
|
68
51
|
*/
|
|
69
|
-
export declare function resolveHermesReadEndpoint(network: Network, sources: readonly OracleSource[], override?: string): string;
|
|
70
52
|
export declare function resolveOracleReadPlan(host: OracleHost, source: OracleSource, tickers: string[]): OracleReadPlan;
|