@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.
- package/README.md +37 -17
- package/dist/cjs/src/account/account.js +2 -1
- package/dist/cjs/src/account/config.d.ts +3 -2
- package/dist/cjs/src/account/funding/balance.d.ts +25 -2
- package/dist/cjs/src/account/funding/balance.js +36 -24
- package/dist/cjs/src/account/funding/credit.js +6 -10
- package/dist/cjs/src/constants.d.ts +15 -1
- package/dist/cjs/src/constants.js +18 -4
- package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
- package/dist/cjs/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +13 -0
- package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
- package/dist/cjs/src/generated/waterx_rule/deps/sui/vec_map.js +31 -0
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +946 -0
- package/dist/cjs/src/oracle/aggregate.d.ts +23 -21
- package/dist/cjs/src/oracle/aggregate.js +133 -59
- package/dist/cjs/src/oracle/config.d.ts +82 -41
- package/dist/cjs/src/oracle/config.js +0 -42
- package/dist/cjs/src/oracle/host.d.ts +26 -11
- package/dist/cjs/src/oracle/index.d.ts +6 -2
- package/dist/cjs/src/oracle/index.js +36 -8
- package/dist/cjs/src/oracle/price-update-rule.d.ts +16 -10
- package/dist/cjs/src/oracle/price-update-rule.js +3 -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 +78 -0
- package/dist/cjs/src/oracle/rule-registry.d.ts +14 -11
- package/dist/cjs/src/oracle/rule-registry.js +16 -11
- package/dist/cjs/src/oracle/rules/pyth-core-rule.js +4 -4
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +29 -4
- package/dist/cjs/src/oracle/rules/pyth-rule.js +5 -4
- package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +126 -0
- package/dist/cjs/src/oracle/rules/waterx-rule.js +312 -0
- package/dist/cjs/src/perp/client.d.ts +71 -20
- package/dist/cjs/src/perp/client.js +35 -13
- package/dist/cjs/src/perp/config.d.ts +6 -7
- package/dist/cjs/src/perp/config.js +12 -11
- package/dist/cjs/src/perp/constants.d.ts +0 -6
- package/dist/cjs/src/perp/constants.js +11 -9
- package/dist/cjs/src/perp/fetch/account.js +3 -0
- package/dist/cjs/src/perp/fetch/bridge.js +2 -1
- package/dist/cjs/src/perp/fetch/market.js +2 -1
- package/dist/cjs/src/perp/fetch/positions.d.ts +16 -10
- package/dist/cjs/src/perp/fetch/positions.js +23 -20
- package/dist/cjs/src/perp/index.d.ts +9 -5
- package/dist/cjs/src/perp/index.js +16 -7
- package/dist/cjs/src/perp/liq-view.d.ts +64 -0
- package/dist/cjs/src/perp/liq-view.js +74 -0
- package/dist/cjs/src/perp/user/order.d.ts +13 -0
- package/dist/cjs/src/perp/user/order.js +30 -16
- package/dist/cjs/src/perp/user/staking.js +3 -2
- package/dist/cjs/src/perp/user/trading.js +25 -24
- package/dist/cjs/src/perp/user/wlp.js +6 -5
- package/dist/cjs/src/prediction/utils.d.ts +11 -2
- package/dist/cjs/src/prediction/utils.js +22 -22
- package/dist/cjs/src/unified-client.d.ts +41 -15
- package/dist/cjs/src/unified-client.js +4 -2
- package/dist/cjs/src/utils/format.d.ts +14 -0
- package/dist/cjs/src/utils/format.js +24 -0
- package/dist/cjs/src/utils/math.d.ts +304 -12
- package/dist/cjs/src/utils/math.js +397 -17
- package/dist/cjs/src/utils/validate.d.ts +69 -0
- package/dist/cjs/src/utils/validate.js +183 -0
- package/dist/src/account/account.js +2 -1
- package/dist/src/account/config.d.ts +3 -2
- package/dist/src/account/funding/balance.d.ts +25 -2
- package/dist/src/account/funding/balance.js +36 -24
- package/dist/src/account/funding/credit.js +6 -10
- package/dist/src/constants.d.ts +15 -1
- package/dist/src/constants.js +17 -3
- package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.d.ts +8 -0
- package/dist/src/generated/waterx_rule/deps/bucket_v2_framework/float.js +10 -0
- package/dist/src/generated/waterx_rule/deps/sui/vec_map.d.ts +36 -0
- package/dist/src/generated/waterx_rule/deps/sui/vec_map.js +27 -0
- package/dist/src/generated/waterx_rule/waterx_rule.d.ts +813 -0
- package/dist/src/generated/waterx_rule/waterx_rule.js +855 -0
- package/dist/src/oracle/aggregate.d.ts +23 -21
- package/dist/src/oracle/aggregate.js +133 -59
- package/dist/src/oracle/config.d.ts +82 -41
- package/dist/src/oracle/config.js +1 -41
- package/dist/src/oracle/host.d.ts +26 -11
- package/dist/src/oracle/index.d.ts +6 -2
- package/dist/src/oracle/index.js +27 -9
- package/dist/src/oracle/price-update-rule.d.ts +16 -10
- package/dist/src/oracle/price-update-rule.js +3 -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 +74 -0
- package/dist/src/oracle/rule-registry.d.ts +14 -11
- package/dist/src/oracle/rule-registry.js +16 -11
- package/dist/src/oracle/rules/pyth-core-rule.js +5 -5
- package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +21 -0
- package/dist/src/oracle/rules/pyth-lazer-rule.js +28 -3
- package/dist/src/oracle/rules/pyth-rule.js +5 -4
- package/dist/src/oracle/rules/waterx-rule.d.ts +126 -0
- package/dist/src/oracle/rules/waterx-rule.js +305 -0
- package/dist/src/perp/client.d.ts +71 -20
- package/dist/src/perp/client.js +36 -14
- package/dist/src/perp/config.d.ts +6 -7
- package/dist/src/perp/config.js +11 -9
- package/dist/src/perp/constants.d.ts +0 -6
- package/dist/src/perp/constants.js +10 -8
- package/dist/src/perp/fetch/account.js +3 -0
- package/dist/src/perp/fetch/bridge.js +2 -1
- package/dist/src/perp/fetch/market.js +2 -1
- package/dist/src/perp/fetch/positions.d.ts +16 -10
- package/dist/src/perp/fetch/positions.js +28 -20
- package/dist/src/perp/index.d.ts +9 -5
- package/dist/src/perp/index.js +6 -4
- package/dist/src/perp/liq-view.d.ts +64 -0
- package/dist/src/perp/liq-view.js +71 -0
- package/dist/src/perp/user/order.d.ts +13 -0
- package/dist/src/perp/user/order.js +30 -16
- package/dist/src/perp/user/staking.js +3 -2
- package/dist/src/perp/user/trading.js +25 -24
- package/dist/src/perp/user/wlp.js +6 -5
- package/dist/src/prediction/utils.d.ts +11 -2
- package/dist/src/prediction/utils.js +22 -22
- package/dist/src/unified-client.d.ts +41 -15
- package/dist/src/unified-client.js +4 -2
- package/dist/src/utils/format.d.ts +14 -0
- package/dist/src/utils/format.js +21 -0
- package/dist/src/utils/math.d.ts +304 -12
- package/dist/src/utils/math.js +394 -17
- package/dist/src/utils/validate.d.ts +69 -0
- package/dist/src/utils/validate.js +167 -0
- package/package.json +4 -1
|
@@ -19,12 +19,14 @@
|
|
|
19
19
|
*
|
|
20
20
|
* `refreshOraclePrices` additionally routes the on-chain price *update* leg
|
|
21
21
|
* (the fetch + verify/push step, before any of the above feeding) through the
|
|
22
|
-
* `PriceUpdateRule`
|
|
22
|
+
* `PriceUpdateRule` of EVERY source in the `host.oracleSources` fed set — see
|
|
23
|
+
* `rule-registry.ts`.
|
|
23
24
|
*/
|
|
24
25
|
import type { Transaction, TransactionArgument } from "@mysten/sui/transactions";
|
|
25
26
|
import type { OracleHost } from "./host.ts";
|
|
26
27
|
import type { OracleSource, PriceUpdateRule, UpdateDataProvider } from "./price-update-rule.ts";
|
|
27
28
|
import { type OracleFeeSource, type PythCache } from "./pyth.ts";
|
|
29
|
+
import { type WaterxSignedEnvelope } from "./rules/waterx-rule.ts";
|
|
28
30
|
/**
|
|
29
31
|
* Aggregate one ticker's price into the shared `Oracle`: build a collector, feed
|
|
30
32
|
* every rule the ticker is configured for, then `aggregate`.
|
|
@@ -54,6 +56,7 @@ export declare function aggregateTicker(tx: Transaction, host: OracleHost, args:
|
|
|
54
56
|
ticker: string;
|
|
55
57
|
priceInfoObjectId?: string;
|
|
56
58
|
lazerUpdate?: TransactionArgument;
|
|
59
|
+
waterxEnvelope?: WaterxSignedEnvelope;
|
|
57
60
|
}): void;
|
|
58
61
|
/**
|
|
59
62
|
* Thin wrapper over {@link aggregateTicker} for a Pyth-fed ticker. Kept for
|
|
@@ -82,27 +85,26 @@ export declare function aggregateTickerWithConstant(tx: Transaction, host: Oracl
|
|
|
82
85
|
* entry, Lazer if the lazer update leg served it — see below — Supra when
|
|
83
86
|
* enabled, Constant when it's a constant ticker).
|
|
84
87
|
*
|
|
85
|
-
* Before that, the on-chain price *update* leg is routed by
|
|
86
|
-
* (see `rule-registry.ts`):
|
|
87
|
-
* `supportedTickers(host)
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* dry-run, which is correct.
|
|
88
|
+
* Before that, the on-chain price *update* leg is routed by the
|
|
89
|
+
* `host.oracleSources` fed set (see `rule-registry.ts`): EVERY listed source
|
|
90
|
+
* updates the tickers its own `supportedTickers(host)` serves, all in this one
|
|
91
|
+
* PTB. There is **no cross-source fallback** — a requested ticker NO listed
|
|
92
|
+
* source serves, and that is not a constant-only ticker (which needs no
|
|
93
|
+
* price-update leg), fails the build immediately with a clear error naming
|
|
94
|
+
* the ticker and the list. That is the deliberate "fail the tx-build, don't
|
|
95
|
+
* silently reroute" contract: a wrong-but-present feed id is NOT validated
|
|
96
|
+
* here (it surfaces on-chain at dry-run); a ticker MISSING from every listed
|
|
97
|
+
* source's feeds is caught here.
|
|
96
98
|
*
|
|
97
|
-
*
|
|
98
|
-
* per-rule PTB atomicity. A fee-source pre-check runs first (
|
|
99
|
-
* `requiresFeeSource`) BEFORE any off-chain fetch or PTB mutation —
|
|
100
|
-
* fee-charging source with no `opts.feeSource` throws
|
|
99
|
+
* Each source's fetch + build runs against its own infra, guaranteeing
|
|
100
|
+
* per-rule PTB atomicity. A fee-source pre-check runs first (any listed
|
|
101
|
+
* source's `requiresFeeSource`) BEFORE any off-chain fetch or PTB mutation —
|
|
102
|
+
* so a fee-charging source with no `opts.feeSource` throws
|
|
101
103
|
* `OracleFeeSourceUnavailable` with zero wasted network calls and zero stray
|
|
102
|
-
* moveCalls. Only once that check passes
|
|
103
|
-
*
|
|
104
|
-
* can still fail mid-append for
|
|
105
|
-
* throw.
|
|
104
|
+
* moveCalls. Only once that check passes do the off-chain fetches run — in
|
|
105
|
+
* parallel across sources — and ALL settle before the first PTB mutation;
|
|
106
|
+
* on-chain reads inside `buildUpdateCalls` can still fail mid-append for
|
|
107
|
+
* other reasons — callers discard the tx on any throw.
|
|
106
108
|
*
|
|
107
109
|
* **Collector-feed leg is rule-aware:** a lazer-served group's
|
|
108
110
|
* `buildUpdateCalls` returns the verified `Update` PTB value
|
|
@@ -137,7 +139,7 @@ export declare function refreshOraclePrices(tx: Transaction, host: OracleHost, t
|
|
|
137
139
|
/**
|
|
138
140
|
* @internal Test-only: layer fake `PriceUpdateRule`s on top of the
|
|
139
141
|
* production registry (see `rule-registry.ts`'s `resolveOracleRule`).
|
|
140
|
-
* Production callers never set this — routing is by `host.
|
|
142
|
+
* Production callers never set this — routing is by `host.oracleSources`
|
|
141
143
|
* alone.
|
|
142
144
|
*/
|
|
143
145
|
ruleOverrides?: Partial<Record<OracleSource, PriceUpdateRule>>;
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
*
|
|
21
21
|
* `refreshOraclePrices` additionally routes the on-chain price *update* leg
|
|
22
22
|
* (the fetch + verify/push step, before any of the above feeding) through the
|
|
23
|
-
* `PriceUpdateRule`
|
|
23
|
+
* `PriceUpdateRule` of EVERY source in the `host.oracleSources` fed set — see
|
|
24
|
+
* `rule-registry.ts`.
|
|
24
25
|
*/
|
|
25
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
27
|
exports.aggregateTicker = aggregateTicker;
|
|
@@ -34,6 +35,7 @@ const constant_rule_ts_1 = require("./rules/constant-rule.js");
|
|
|
34
35
|
const pyth_lazer_rule_ts_1 = require("./rules/pyth-lazer-rule.js");
|
|
35
36
|
const pyth_rule_ts_1 = require("./rules/pyth-rule.js");
|
|
36
37
|
const supra_rule_ts_1 = require("./rules/supra-rule.js");
|
|
38
|
+
const waterx_rule_ts_1 = require("./rules/waterx-rule.js");
|
|
37
39
|
/**
|
|
38
40
|
* Resolve one group's off-chain update payload for {@link refreshOraclePrices}:
|
|
39
41
|
* try `provider.get(source, tickers)` first (when a provider is configured),
|
|
@@ -116,6 +118,20 @@ function aggregateTicker(tx, host, args) {
|
|
|
116
118
|
(0, pyth_lazer_rule_ts_1.feedLazerRule)(tx, host, collector, args.lazerUpdate);
|
|
117
119
|
fed = true;
|
|
118
120
|
}
|
|
121
|
+
if (args.waterxEnvelope !== undefined) {
|
|
122
|
+
// waterx_rule::collect_batch_latest verifies the batch signature and feeds
|
|
123
|
+
// this collector's symbol from the batch. If the ticker's aggregator does
|
|
124
|
+
// not (yet) weight `WaterxRule`, the contribution is silently dropped
|
|
125
|
+
// on-chain — feeding ahead of the weight migration is safe for THIS tx.
|
|
126
|
+
// CAVEAT (unlike lazer): the feed call records a per-symbol signed-
|
|
127
|
+
// timestamp high-water mark REGARDLESS of weights, and a replayed
|
|
128
|
+
// timestamp ABORTS (`EReplayedSignature`, audit F-014) — so two PTBs
|
|
129
|
+
// carrying the same envelope for the same symbol cannot both land; the
|
|
130
|
+
// second aborts even where waterx is unweighted. See WaterxRule's module
|
|
131
|
+
// header.
|
|
132
|
+
(0, waterx_rule_ts_1.feedWaterxRule)(tx, host, collector, args.waterxEnvelope);
|
|
133
|
+
fed = true;
|
|
134
|
+
}
|
|
119
135
|
if (fed) {
|
|
120
136
|
// Supra rides on the same collector when enabled (abstains on-chain otherwise).
|
|
121
137
|
(0, supra_rule_ts_1.maybeFeedSupra)(tx, host, collector);
|
|
@@ -164,27 +180,26 @@ function aggregateTickerWithConstant(tx, host, args) {
|
|
|
164
180
|
* entry, Lazer if the lazer update leg served it — see below — Supra when
|
|
165
181
|
* enabled, Constant when it's a constant ticker).
|
|
166
182
|
*
|
|
167
|
-
* Before that, the on-chain price *update* leg is routed by
|
|
168
|
-
* (see `rule-registry.ts`):
|
|
169
|
-
* `supportedTickers(host)
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* dry-run, which is correct.
|
|
183
|
+
* Before that, the on-chain price *update* leg is routed by the
|
|
184
|
+
* `host.oracleSources` fed set (see `rule-registry.ts`): EVERY listed source
|
|
185
|
+
* updates the tickers its own `supportedTickers(host)` serves, all in this one
|
|
186
|
+
* PTB. There is **no cross-source fallback** — a requested ticker NO listed
|
|
187
|
+
* source serves, and that is not a constant-only ticker (which needs no
|
|
188
|
+
* price-update leg), fails the build immediately with a clear error naming
|
|
189
|
+
* the ticker and the list. That is the deliberate "fail the tx-build, don't
|
|
190
|
+
* silently reroute" contract: a wrong-but-present feed id is NOT validated
|
|
191
|
+
* here (it surfaces on-chain at dry-run); a ticker MISSING from every listed
|
|
192
|
+
* source's feeds is caught here.
|
|
178
193
|
*
|
|
179
|
-
*
|
|
180
|
-
* per-rule PTB atomicity. A fee-source pre-check runs first (
|
|
181
|
-
* `requiresFeeSource`) BEFORE any off-chain fetch or PTB mutation —
|
|
182
|
-
* fee-charging source with no `opts.feeSource` throws
|
|
194
|
+
* Each source's fetch + build runs against its own infra, guaranteeing
|
|
195
|
+
* per-rule PTB atomicity. A fee-source pre-check runs first (any listed
|
|
196
|
+
* source's `requiresFeeSource`) BEFORE any off-chain fetch or PTB mutation —
|
|
197
|
+
* so a fee-charging source with no `opts.feeSource` throws
|
|
183
198
|
* `OracleFeeSourceUnavailable` with zero wasted network calls and zero stray
|
|
184
|
-
* moveCalls. Only once that check passes
|
|
185
|
-
*
|
|
186
|
-
* can still fail mid-append for
|
|
187
|
-
* throw.
|
|
199
|
+
* moveCalls. Only once that check passes do the off-chain fetches run — in
|
|
200
|
+
* parallel across sources — and ALL settle before the first PTB mutation;
|
|
201
|
+
* on-chain reads inside `buildUpdateCalls` can still fail mid-append for
|
|
202
|
+
* other reasons — callers discard the tx on any throw.
|
|
188
203
|
*
|
|
189
204
|
* **Collector-feed leg is rule-aware:** a lazer-served group's
|
|
190
205
|
* `buildUpdateCalls` returns the verified `Update` PTB value
|
|
@@ -205,64 +220,122 @@ function aggregateTickerWithConstant(tx, host, args) {
|
|
|
205
220
|
async function refreshOraclePrices(tx, host, tickers, opts = {}) {
|
|
206
221
|
if (tickers.length === 0)
|
|
207
222
|
return;
|
|
223
|
+
// Dedupe the caller's list (order-preserving): a repeated ticker would
|
|
224
|
+
// otherwise aggregate TWICE in this one PTB — wasted gas for every rule,
|
|
225
|
+
// and a hard ABORT under waterx: the second `collect_batch_latest` carries
|
|
226
|
+
// the same envelope, and the on-chain per-symbol replay guard rejects an
|
|
227
|
+
// already-accepted signed timestamp (`EReplayedSignature`, F-014) even
|
|
228
|
+
// inside a single transaction.
|
|
229
|
+
tickers = [...new Set(tickers)];
|
|
208
230
|
// price_info_object lookup for every ticker with a pyth_rule.feeds entry —
|
|
209
231
|
// needed by aggregateTicker's (unchanged) Pyth feed step below regardless of
|
|
210
232
|
// which rule performed the on-chain update for that ticker.
|
|
211
233
|
const pythTickers = tickers.filter((t) => host.config.packages.pyth_rule?.feeds?.[t] !== undefined);
|
|
212
234
|
const priceInfoByTicker = new Map();
|
|
213
235
|
pythTickers.forEach((t) => priceInfoByTicker.set(t, host.getPythFeed(t).price_info_object));
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
//
|
|
221
|
-
//
|
|
236
|
+
// The fed set is a LIST (`host.oracleSources`, normalized + deduped at
|
|
237
|
+
// client creation): ONE build carries every listed source's data, and the
|
|
238
|
+
// chain's per-ticker weight tables decide which contributions count —
|
|
239
|
+
// feeding an unweighted rule's PRICE is dropped on-chain, while starving a
|
|
240
|
+
// weighted one aborts. That asymmetry is what makes weight migrations
|
|
241
|
+
// safe: flip weights per ticker at any time while the fed set stays a
|
|
242
|
+
// superset of every ticker's weighted set. (One caveat: waterx's feed call
|
|
243
|
+
// burns a per-symbol signed-timestamp high-water mark regardless of
|
|
244
|
+
// weights — see aggregateTicker's waterx branch.) Still NO fallback
|
|
245
|
+
// BETWEEN sources: each group serves only the tickers its own feeds list.
|
|
246
|
+
// Zero-ticker groups are dropped here so everything downstream (fee check,
|
|
247
|
+
// fetch fan-out, update-leg build) can assume every group has work.
|
|
248
|
+
const groups = host.oracleSources
|
|
249
|
+
.map((source) => {
|
|
250
|
+
const rule = (0, rule_registry_ts_1.resolveOracleRule)(source, opts.ruleOverrides);
|
|
251
|
+
const supported = new Set(rule.supportedTickers(host));
|
|
252
|
+
return { source, rule, tickers: tickers.filter((t) => supported.has(t)) };
|
|
253
|
+
})
|
|
254
|
+
.filter((group) => group.tickers.length > 0);
|
|
255
|
+
// Fail the tx-build (NOT client init, NOT a silent reroute) when NO listed
|
|
256
|
+
// source has a feed for a requested ticker that actually needs a price
|
|
222
257
|
// update. Only a CONSTANT-ONLY ticker is exempt — priced entirely by
|
|
223
258
|
// `constant_rule`, it needs no update leg from any source. A DUAL-FEED ticker
|
|
224
259
|
// (constant AND pyth) still needs its Pyth leg refreshed, so `isConstantTicker`
|
|
225
|
-
// alone must NOT exempt it:
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
260
|
+
// alone must NOT exempt it: with no source able to serve it, feeding an
|
|
261
|
+
// unrefreshed Pyth leg would price it stale (or abort on a missing weighted
|
|
262
|
+
// source). `priceInfoByTicker.has(t)` ⇔ the ticker has a `pyth_rule.feeds`
|
|
263
|
+
// entry, so `constant && !hasPyth` is exactly constant-only. This catches a
|
|
264
|
+
// MISSING feed; a present-but-WRONG feed id is deliberately not validated
|
|
265
|
+
// here (it aborts on-chain at dry-run).
|
|
266
|
+
const covered = new Set(groups.flatMap((group) => group.tickers));
|
|
231
267
|
const isConstantOnly = (t) => host.isConstantTicker(t) && !priceInfoByTicker.has(t);
|
|
232
|
-
const unservable = tickers.filter((t) => !
|
|
268
|
+
const unservable = tickers.filter((t) => !covered.has(t) && !isConstantOnly(t));
|
|
233
269
|
if (unservable.length > 0) {
|
|
234
|
-
|
|
270
|
+
const sources = host.oracleSources.join(", ");
|
|
271
|
+
throw new Error(`oracleSource [${sources}] has no feed configured for ticker(s): ` +
|
|
235
272
|
`${unservable.join(", ")}. Sources are self-contained with no fallback — add ` +
|
|
236
|
-
|
|
273
|
+
`feeds for them under a listed source, or list a source that serves them.`);
|
|
237
274
|
}
|
|
238
|
-
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
if (selectedGroup.length > 0 && !opts.feeSource && selectedRule.requiresFeeSource) {
|
|
275
|
+
// Fee-source pre-check, hoisted ABOVE the off-chain fetches and PTB build
|
|
276
|
+
// below. It consults only `rule.requiresFeeSource` — known before any fetch
|
|
277
|
+
// or PTB mutation — so a fee-charging source (Pyth Core) in the fed set with
|
|
278
|
+
// no `feeSource` throws with ZERO wasted network calls and zero PTB
|
|
279
|
+
// commands, rather than waiting for `buildPythPriceUpdateCalls`'s own
|
|
280
|
+
// per-call guard to fire after the off-chain fetches already ran.
|
|
281
|
+
if (!opts.feeSource && groups.some((group) => group.rule.requiresFeeSource)) {
|
|
246
282
|
throw new pyth_ts_1.OracleFeeSourceUnavailableError();
|
|
247
283
|
}
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
284
|
+
// Phase 1 — resolve every group's update data IN PARALLEL: the per-source
|
|
285
|
+
// fetches (Hermes VAA / Lazer POST / quote-center GET) are independent
|
|
286
|
+
// network calls on the tx-build money path, so a multi-source fed set must
|
|
287
|
+
// not pay one RTT per source sequentially. ALL fetches settle before the
|
|
288
|
+
// first PTB mutation below, so a fetch failure never strands moveCalls in a
|
|
289
|
+
// caller-owned tx — and a failure in ANY group fails the whole build (a
|
|
290
|
+
// listed source is load-bearing; silently building without it would starve
|
|
291
|
+
// its weighted tickers on-chain).
|
|
292
|
+
const dataByGroup = await Promise.all(groups.map((group) => resolveGroupUpdateData(host, group, opts.updateDataProvider)));
|
|
293
|
+
// Phase 2 — build each group's update leg sequentially, in list order, so
|
|
294
|
+
// PTB command order stays deterministic. The carry step below is an
|
|
295
|
+
// exhaustive switch over the group's rule kind: a future source whose feed
|
|
296
|
+
// leg needs per-ticker data from its update leg must decide its carry here
|
|
297
|
+
// — falling through silently would starve its weighted tickers on-chain.
|
|
252
298
|
const lazerUpdateByTicker = new Map();
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
299
|
+
// Signed batch envelope per waterx-served ticker. Unlike Lazer's shared PTB
|
|
300
|
+
// handle, waterx's verify+feed is bundled into `collect_batch_latest` in the
|
|
301
|
+
// per-ticker feed leg, so its `buildUpdateCalls` emits nothing and the
|
|
302
|
+
// envelope is carried straight from the group's fetched data.
|
|
303
|
+
const waterxEnvelopeByTicker = new Map();
|
|
304
|
+
for (const [i, group] of groups.entries()) {
|
|
305
|
+
const data = dataByGroup[i] ?? null;
|
|
306
|
+
const handle = (await group.rule.buildUpdateCalls(tx, host, data, {
|
|
257
307
|
cache: opts.cache,
|
|
258
308
|
feeSource: opts.feeSource,
|
|
259
309
|
})) ?? undefined;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
310
|
+
switch (group.rule.kind) {
|
|
311
|
+
case "pyth_rule":
|
|
312
|
+
// Core's update leg wrote the PriceInfoObjects in place — the feed
|
|
313
|
+
// leg reads them by id (`priceInfoByTicker`), nothing to carry.
|
|
314
|
+
break;
|
|
315
|
+
case "pyth_lazer_rule":
|
|
316
|
+
// Route by the handle's kind discriminant — the tag exists so a
|
|
317
|
+
// non-lazer handle can never be silently fed into
|
|
318
|
+
// pyth_lazer_rule::feed.
|
|
319
|
+
if (handle?.kind === "pyth_lazer_rule") {
|
|
320
|
+
for (const ticker of group.tickers)
|
|
321
|
+
lazerUpdateByTicker.set(ticker, handle.update);
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
case "waterx_rule": {
|
|
325
|
+
// waterx_rule emits no shared handle (verify+feed is bundled into the
|
|
326
|
+
// per-ticker `collect_batch_latest`), so the envelope is carried
|
|
327
|
+
// straight from this group's fetched data to the feed leg below.
|
|
328
|
+
const envelope = (0, waterx_rule_ts_1.waterxEnvelopeOf)(data);
|
|
329
|
+
if (envelope) {
|
|
330
|
+
for (const ticker of group.tickers)
|
|
331
|
+
waterxEnvelopeByTicker.set(ticker, envelope);
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
default: {
|
|
336
|
+
const exhausted = group.rule.kind;
|
|
337
|
+
throw new Error(`refreshOraclePrices: unhandled rule kind '${String(exhausted)}'`);
|
|
338
|
+
}
|
|
266
339
|
}
|
|
267
340
|
}
|
|
268
341
|
// Aggregate each ticker, feeding whichever rules it is configured for.
|
|
@@ -271,6 +344,7 @@ async function refreshOraclePrices(tx, host, tickers, opts = {}) {
|
|
|
271
344
|
ticker,
|
|
272
345
|
priceInfoObjectId: priceInfoByTicker.get(ticker),
|
|
273
346
|
lazerUpdate: lazerUpdateByTicker.get(ticker),
|
|
347
|
+
waterxEnvelope: waterxEnvelopeByTicker.get(ticker),
|
|
274
348
|
});
|
|
275
349
|
}
|
|
276
350
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { BasePackageEntry } from "../account/config.ts";
|
|
13
13
|
import type { BaseLineConfig } from "../base-client.ts";
|
|
14
|
-
import type {
|
|
14
|
+
import type { FetchPolicy } from "./update-fetch.ts";
|
|
15
15
|
export interface PythRulePackage extends BasePackageEntry {
|
|
16
16
|
config: string;
|
|
17
17
|
feeds: Record<string, {
|
|
@@ -30,7 +30,7 @@ export interface PythSponsorRulePackage extends BasePackageEntry {
|
|
|
30
30
|
*
|
|
31
31
|
* `enabled` mirrors the JSON field verbatim but MUST NOT be read for routing —
|
|
32
32
|
* which rule prices a ticker is decided solely by the client's `oracleSource`
|
|
33
|
-
* create option (see `OracleHost.
|
|
33
|
+
* create option (see `OracleHost.oracleSources`), never by this flag or any
|
|
34
34
|
* other config value.
|
|
35
35
|
*/
|
|
36
36
|
export interface PythLazerRulePackage extends BasePackageEntry {
|
|
@@ -82,6 +82,40 @@ export interface SupraRulePackage extends BasePackageEntry {
|
|
|
82
82
|
*/
|
|
83
83
|
enabled?: boolean;
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Per-ticker `waterx_rule` feed entry. Keyed in `feeds` by the oracle **ticker**
|
|
87
|
+
* (e.g. `"SUIUSD"`, the same key `pyth_rule.feeds` uses), so
|
|
88
|
+
* `Object.keys(feeds)` is the SDK's supported-ticker set. The fields are
|
|
89
|
+
* informational off-chain — the SDK keys routing/support off the entry's
|
|
90
|
+
* presence and pushes the enclave-signed price verbatim, never re-deriving it.
|
|
91
|
+
*/
|
|
92
|
+
export interface WaterxRuleFeedEntry {
|
|
93
|
+
/** Exchange ticker the quote-center aggregates from (e.g. `"SUIUSDT"`). */
|
|
94
|
+
ticker?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* `waterx_rule` deployment entry — the first-party Nautilus-TEE oracle rule.
|
|
98
|
+
* Read by `WaterxRule` (`rules/waterx-rule.ts`): `feeds` for ticker support,
|
|
99
|
+
* `config`/`enclave_config`/`enclave` for the `collect_batch_latest` call,
|
|
100
|
+
* `published_at` for the package address. The off-chain signed price is pulled
|
|
101
|
+
* from the quote-center (endpoint from the rule-owned `WATERX_INFRA` table in
|
|
102
|
+
* `rules/waterx-rule.ts`), not this JSON.
|
|
103
|
+
*
|
|
104
|
+
* `enabled` mirrors the JSON field verbatim but MUST NOT be read for routing —
|
|
105
|
+
* which rule prices a ticker is decided solely by the client's `oracleSource`
|
|
106
|
+
* create option (see `OracleHost.oracleSources`), mirroring `pyth_lazer_rule`.
|
|
107
|
+
*/
|
|
108
|
+
export interface WaterxRulePackage extends BasePackageEntry {
|
|
109
|
+
/** Shared `waterx_rule::Config` (per-symbol on-chain feed_config). */
|
|
110
|
+
config: string;
|
|
111
|
+
/** Shared `EnclaveConfig<WATERX_RULE>` the on-chain signature verify runs against. */
|
|
112
|
+
enclave_config: string;
|
|
113
|
+
/** Shared `Enclave<WATERX_RULE>` holding the registered TEE signing pubkey. */
|
|
114
|
+
enclave: string;
|
|
115
|
+
enabled?: boolean;
|
|
116
|
+
/** Oracle ticker → feed entry; presence marks the ticker as waterx-served. */
|
|
117
|
+
feeds: Record<string, WaterxRuleFeedEntry>;
|
|
118
|
+
}
|
|
85
119
|
export interface WaterxOraclePackage extends BasePackageEntry {
|
|
86
120
|
listing_cap: string;
|
|
87
121
|
oracle: string;
|
|
@@ -99,19 +133,10 @@ export interface OraclePackages {
|
|
|
99
133
|
pyth_lazer_rule?: PythLazerRulePackage;
|
|
100
134
|
constant_rule?: WaterxConstantRulePackage;
|
|
101
135
|
supra_rule?: SupraRulePackage;
|
|
136
|
+
/** See {@link WaterxRulePackage} — read by `WaterxRule` when `oracleSource` selects it. */
|
|
137
|
+
waterx_rule?: WaterxRulePackage;
|
|
102
138
|
waterx_oracle: WaterxOraclePackage;
|
|
103
139
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Resolved Pyth Core infra as it lives on `client.pyth` — NOT a config-JSON
|
|
106
|
-
* shape. `state_id` / `wormhole_state_id` / `hermes_endpoint` come verbatim
|
|
107
|
-
* from the fixed per-network constant ({@link PYTH_DEFAULTS}); `api_key` /
|
|
108
|
-
* `fetch` are layered on from the caller's `pythApiKey` / `pythFetch` create
|
|
109
|
-
* options. None of it is sourced from the canonical `waterx-config` JSON — the
|
|
110
|
-
* SDK never reads a `pyth` block there (a Bearer secret has no place in a
|
|
111
|
-
* public CDN document). The infra is the same for every `oracleSource`; the
|
|
112
|
-
* `pyth_lazer_rule` source reads only the `api_key` / `fetch` from here and
|
|
113
|
-
* gets its on-chain infra from {@link LAZER_DEFAULTS} + config instead.
|
|
114
|
-
*/
|
|
115
140
|
/**
|
|
116
141
|
* The caller-tunable subset of `fetchWithPolicy`'s policy exposed on the
|
|
117
142
|
* `pythFetch` create option and `client.pyth.fetch` — the retry/timeout budget
|
|
@@ -124,18 +149,24 @@ export type PythFetchPolicy = {
|
|
|
124
149
|
timeoutMs?: number;
|
|
125
150
|
retries?: number;
|
|
126
151
|
};
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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 {
|
|
131
163
|
/**
|
|
132
|
-
* Pyth
|
|
164
|
+
* Pyth access token (`Authorization: Bearer …`). Required by
|
|
133
165
|
* `PythLazerRule`'s signed-update fetch — Lazer is auth-first, so there is
|
|
134
|
-
* no keyless default
|
|
135
|
-
*
|
|
136
|
-
* `
|
|
137
|
-
*
|
|
138
|
-
* 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
|
|
139
170
|
* https://docs.pyth.network/price-feeds/core/upgrade) this is ALSO required
|
|
140
171
|
* for `pyth_rule`'s Hermes fetch (`fetchPriceFeedsUpdateData`) — see
|
|
141
172
|
* `fetch` below.
|
|
@@ -151,27 +182,37 @@ export interface PythInfraConfig {
|
|
|
151
182
|
*/
|
|
152
183
|
fetch?: PythFetchPolicy;
|
|
153
184
|
}
|
|
154
|
-
export declare const PYTH_DEFAULTS: Record<Network, PythInfraConfig>;
|
|
155
185
|
/**
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
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.
|
|
160
191
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* still the original v1 publish; mainnet is the v2-upgraded package (which
|
|
168
|
-
* still exposes the v1 entry `pyth_lazer_rule` binds). Values mirror the
|
|
169
|
-
* contract repo's `pyth_lazer_rule/Move.toml` published-at pins.
|
|
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.
|
|
170
198
|
*/
|
|
171
|
-
export
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
199
|
+
export interface WaterxAccessConfig {
|
|
200
|
+
/**
|
|
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
|
|
204
|
+
* `…/api/quote-center/v1/quotes/update` and a proxy route is not rewritten
|
|
205
|
+
* away. A trailing slash is trimmed.
|
|
206
|
+
*/
|
|
207
|
+
endpoint?: string;
|
|
208
|
+
/**
|
|
209
|
+
* Retry/timeout policy (and `fetchImpl`) for the quote-center fetch — see
|
|
210
|
+
* `fetchWithPolicy` (`./update-fetch.ts`). Supplied via the `waterxFetch`
|
|
211
|
+
* create option. Falls back to `fetchWithPolicy`'s built-in defaults (15s
|
|
212
|
+
* timeout, 2 retries) when unset — never to another source's policy.
|
|
213
|
+
*/
|
|
214
|
+
fetch?: FetchPolicy;
|
|
215
|
+
}
|
|
175
216
|
/**
|
|
176
217
|
* The narrow config shape the oracle/refresh code needs. `WaterXConfig`
|
|
177
218
|
* (the perp line's full config) is assignable to this, so `PerpClient` satisfies
|
|
@@ -11,45 +11,3 @@
|
|
|
11
11
|
* mirrors the earlier account-config hoist.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.LAZER_DEFAULTS = exports.PYTH_DEFAULTS = void 0;
|
|
15
|
-
exports.PYTH_DEFAULTS = {
|
|
16
|
-
MAINNET: {
|
|
17
|
-
state_id: "0x1f9310238ee9298fb703c3419030b35b22bb1cc37113e3bb5007c99aec79e5b8",
|
|
18
|
-
wormhole_state_id: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
|
|
19
|
-
hermes_endpoint: "https://hermes.pyth.network",
|
|
20
|
-
},
|
|
21
|
-
TESTNET: {
|
|
22
|
-
state_id: "0x243759059f4c3111179da5878c12f68d612c21a8d54d85edc86164bb18be1c7c",
|
|
23
|
-
wormhole_state_id: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790",
|
|
24
|
-
hermes_endpoint: "https://hermes-beta.pyth.network",
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// Pyth Lazer — external infra, defaults by network
|
|
29
|
-
// ============================================================================
|
|
30
|
-
/**
|
|
31
|
-
* Pyth Lazer (Pyth Pro) external infra the `PythLazerRule` needs, by network.
|
|
32
|
-
* Mirrors {@link PYTH_DEFAULTS}: per-network constants for infrastructure Pyth
|
|
33
|
-
* operates (not part of the `waterx-config` JSON). A fuller `PYTH_INFRA`
|
|
34
|
-
* restructure is deferred — this stays a minimal map until then.
|
|
35
|
-
*
|
|
36
|
-
* - `endpoint` — Lazer HTTP API base; signed updates come from
|
|
37
|
-
* `POST /v1/latest_price` (Bearer-authenticated). The service is
|
|
38
|
-
* network-agnostic (one signed payload verifies on any chain that trusts the
|
|
39
|
-
* Lazer signers), so both networks share the production host.
|
|
40
|
-
* - `verifier_package` — the Sui package carrying
|
|
41
|
-
* `pyth_lazer::parse_and_verify_le_ecdsa_update`. Per-network: testnet is
|
|
42
|
-
* still the original v1 publish; mainnet is the v2-upgraded package (which
|
|
43
|
-
* still exposes the v1 entry `pyth_lazer_rule` binds). Values mirror the
|
|
44
|
-
* contract repo's `pyth_lazer_rule/Move.toml` published-at pins.
|
|
45
|
-
*/
|
|
46
|
-
exports.LAZER_DEFAULTS = {
|
|
47
|
-
MAINNET: {
|
|
48
|
-
endpoint: "https://pyth-lazer.dourolabs.app",
|
|
49
|
-
verifier_package: "0xefbfd064480777699fd9c557a5804d72ace7bc82661fdc8d1f1a44ea6d92ee10",
|
|
50
|
-
},
|
|
51
|
-
TESTNET: {
|
|
52
|
-
endpoint: "https://pyth-lazer.dourolabs.app",
|
|
53
|
-
verifier_package: "0xf5bd2141967507050a91b58de3d95e77c432cd90d1799ee46effc27430a68c21",
|
|
54
|
-
},
|
|
55
|
-
};
|
|
@@ -9,26 +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
|
+
/**
|
|
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
|
+
*/
|
|
31
|
+
readonly waterx?: WaterxAccessConfig;
|
|
21
32
|
/** gRPC client for the on-chain reads the Pyth update path needs. */
|
|
22
33
|
readonly grpcClient: SuiGrpcClient;
|
|
23
34
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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).
|
|
30
45
|
*/
|
|
31
|
-
readonly
|
|
46
|
+
readonly oracleSources: readonly OracleSource[];
|
|
32
47
|
/** True when `ticker` is priced by `constant_rule`. */
|
|
33
48
|
isConstantTicker(ticker: string): boolean;
|
|
34
49
|
/** The `supra_rule` config when deployed, enabled, and fully wired; else `undefined`. */
|