@waterx/sdk 4.3.2 → 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 +225 -0
- package/README.md +216 -45
- package/SKILLS.md +34 -0
- 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/generated/waterx_rule/waterx_rule.d.ts +140 -7
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +163 -8
- package/dist/cjs/src/oracle/aggregate.d.ts +49 -62
- package/dist/cjs/src/oracle/aggregate.js +208 -164
- package/dist/cjs/src/oracle/config.d.ts +38 -51
- 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 +87 -69
- 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 +271 -57
- package/dist/cjs/src/oracle/rules/waterx-rule.js +743 -144
- 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 +40 -55
- 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 +43 -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 +9 -35
- 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/generated/waterx_rule/waterx_rule.d.ts +140 -7
- package/dist/src/generated/waterx_rule/waterx_rule.js +151 -7
- package/dist/src/oracle/aggregate.d.ts +49 -62
- package/dist/src/oracle/aggregate.js +209 -164
- package/dist/src/oracle/config.d.ts +38 -51
- 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 +61 -54
- 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 +271 -57
- package/dist/src/oracle/rules/waterx-rule.js +735 -144
- 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 +40 -55
- 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 +17 -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 +9 -35
- 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 +8 -2
- 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
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `validate.ts` — boot-time oracle-deployment asserts consumers (FE/BE) fold
|
|
4
|
+
* onto instead of each hand-rolling them:
|
|
5
|
+
*
|
|
6
|
+
* - {@link assertOracleWriteCoverage} — the "this fed set can actually price
|
|
7
|
+
* the tickers I care about" guard. Because every source reads through its
|
|
8
|
+
* own feeds namespace, write set == read set — passing this ALSO validates
|
|
9
|
+
* the read plane (there is deliberately no separate read-coverage assert).
|
|
10
|
+
* - {@link missingOracleCredentials} — the env-shaped credential audit: which
|
|
11
|
+
* listed sources cannot run with the credentials this deployment supplied.
|
|
12
|
+
* Boot-time mirror of `refreshOraclePrices`'s own per-build credential
|
|
13
|
+
* pre-check (`aggregate.ts`), keyed off the same rule-owned
|
|
14
|
+
* `credential` declaration so the two can never disagree.
|
|
15
|
+
*
|
|
16
|
+
* Deliberately NOT called by `PerpClient` itself: client creation stays
|
|
17
|
+
* guard-free (a source with absent feeds surfaces at tx-build for exactly the
|
|
18
|
+
* tickers it can't serve). These are for consumers whose deployment policy is
|
|
19
|
+
* "fail the BOOT, not the first trade".
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.OracleTickerUnservedError = void 0;
|
|
23
|
+
exports.assertOracleWriteCoverage = assertOracleWriteCoverage;
|
|
24
|
+
exports.partitionServableTickers = partitionServableTickers;
|
|
25
|
+
exports.servableTickers = servableTickers;
|
|
26
|
+
exports.missingOracleCredentials = missingOracleCredentials;
|
|
27
|
+
const price_update_rule_ts_1 = require("./price-update-rule.js");
|
|
28
|
+
const rule_registry_ts_1 = require("./rule-registry.js");
|
|
29
|
+
/**
|
|
30
|
+
* A build depends on a ticker this client's fed set cannot price.
|
|
31
|
+
*
|
|
32
|
+
* Raised from two places, deliberately the same type: the per-BUILD composers
|
|
33
|
+
* (`refreshOraclePrices` skipped the ticker by design — see
|
|
34
|
+
* `OracleRefreshSummary` — and the composer decided it was load-bearing for
|
|
35
|
+
* the action) and the boot-time {@link assertOracleWriteCoverage}. One error
|
|
36
|
+
* for one question: "this fed set cannot price these tickers".
|
|
37
|
+
*/
|
|
38
|
+
class OracleTickerUnservedError extends Error {
|
|
39
|
+
tickers;
|
|
40
|
+
sources;
|
|
41
|
+
constructor(tickers, sources, why) {
|
|
42
|
+
super(`fed set [${sources.join(", ")}] has no feed for ticker(s): ${tickers.join(", ")}. ` +
|
|
43
|
+
(why ?? "This build depends on their prices, so it cannot proceed. ") +
|
|
44
|
+
"Add feeds under a listed source, list a source that serves them, or pass " +
|
|
45
|
+
"allowUnrefreshedPrices: true to build anyway against whatever price the " +
|
|
46
|
+
"chain already holds.");
|
|
47
|
+
this.name = "OracleTickerUnservedError";
|
|
48
|
+
this.tickers = tickers;
|
|
49
|
+
this.sources = sources;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.OracleTickerUnservedError = OracleTickerUnservedError;
|
|
53
|
+
/**
|
|
54
|
+
* Assert this deployment's fed set can price every ticker in `tickers`.
|
|
55
|
+
*
|
|
56
|
+
* Throws {@link OracleTickerUnservedError} naming ALL the unservable ones (not
|
|
57
|
+
* just the first — an operator fixing a config wants the whole list).
|
|
58
|
+
*
|
|
59
|
+
* This is the boot-time twin of the per-build behaviour, and it guards the gap
|
|
60
|
+
* that per-build handling deliberately leaves open: `refreshOraclePrices`
|
|
61
|
+
* SKIPS a ticker no source serves, and only a composer that happens to depend
|
|
62
|
+
* on that ticker turns the skip into an error. A market nobody trades today
|
|
63
|
+
* would therefore stay silently unpriceable until someone did. Pass the ticker
|
|
64
|
+
* set your deployment cares about (typically every market) and find out at
|
|
65
|
+
* boot instead.
|
|
66
|
+
*
|
|
67
|
+
* It does NOT check "every listed source has feeds" any more: the fed set is
|
|
68
|
+
* derived from exactly that condition (see `deriveOracleSources`), so that
|
|
69
|
+
* assert became unreachable for any real client — it could only fire for a
|
|
70
|
+
* config mutated after construction, which is a test fixture, not a
|
|
71
|
+
* deployment. Write set == read set by construction (each source reads its own
|
|
72
|
+
* feeds), so this single assert still covers both planes.
|
|
73
|
+
*/
|
|
74
|
+
function assertOracleWriteCoverage(host, tickers) {
|
|
75
|
+
const { unservable } = partitionServableTickers(host, tickers);
|
|
76
|
+
if (unservable.length > 0) {
|
|
77
|
+
throw new OracleTickerUnservedError(unservable, host.oracleSources);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Tickers the client's LISTED sources carry a feed for. */
|
|
81
|
+
function fedSetTickers(host) {
|
|
82
|
+
return new Set(host.oracleSources.flatMap((source) => (0, rule_registry_ts_1.resolveOracleRule)(source).supportedTickers(host)));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Tickers ANY rule in this config carries a feed for — listed or not.
|
|
86
|
+
*
|
|
87
|
+
* The fed set answers "can THIS client price it"; this answers "does the chain
|
|
88
|
+
* plausibly weight a price-update rule for it", which is what decides whether
|
|
89
|
+
* a constant leg alone is the whole picture. `supra_rule` counts (it is a
|
|
90
|
+
* weighted leg even though it is not an `OracleSource`) but only when it is
|
|
91
|
+
* actually wired — an unwired block's feeds map is documented as
|
|
92
|
+
* informational, and honouring a stale one would strand constant-only tickers
|
|
93
|
+
* for no benefit.
|
|
94
|
+
*/
|
|
95
|
+
function tickersWithAnySourceFeed(host) {
|
|
96
|
+
const out = new Set();
|
|
97
|
+
for (const source of price_update_rule_ts_1.ORACLE_SOURCES) {
|
|
98
|
+
// Skip a source the deployment DISABLED — routing already honours
|
|
99
|
+
// `enabled: false` (`deriveOracleSources`), and applying it in one place
|
|
100
|
+
// but not the other meant a disabled block's informational feeds
|
|
101
|
+
// disqualified a constant-only ticker that nothing would ever feed. The
|
|
102
|
+
// predicate has to match what actually gets emitted.
|
|
103
|
+
if (host.config.packages[source]?.enabled === false)
|
|
104
|
+
continue;
|
|
105
|
+
for (const ticker of (0, rule_registry_ts_1.resolveOracleRule)(source).supportedTickers(host))
|
|
106
|
+
out.add(ticker);
|
|
107
|
+
}
|
|
108
|
+
// `getSupraRule()` already requires `enabled` — see `config-view.ts`.
|
|
109
|
+
if (host.getSupraRule() !== undefined) {
|
|
110
|
+
for (const ticker of Object.keys(host.config.packages.supra_rule?.feeds ?? {}))
|
|
111
|
+
out.add(ticker);
|
|
112
|
+
}
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* THE acceptance predicate, in partition form — the single definition of
|
|
117
|
+
* "will `refreshOraclePrices` put a price on chain for this ticker".
|
|
118
|
+
*
|
|
119
|
+
* A ticker is servable when some LISTED source's feeds carry it, or when it is
|
|
120
|
+
* CONSTANT-ONLY: `constant_rule` pins it and no other rule in the config feeds
|
|
121
|
+
* it. The stricter constant test matters — a constant-pinned ticker that some
|
|
122
|
+
* other rule also feeds gets aggregated from a constant-only collector, and if
|
|
123
|
+
* the chain weights that other rule the aggregate aborts `EMissingPriceSource`.
|
|
124
|
+
* (`aggregateTicker` only appends a supra leg when a price-update source
|
|
125
|
+
* already fed the collector, so a constant-only collector can never carry one.)
|
|
126
|
+
*
|
|
127
|
+
* `covered` lets a caller that has ALREADY resolved which of its tickers its
|
|
128
|
+
* fed set serves — `refreshOraclePrices`, off its rule groups — pass that in
|
|
129
|
+
* rather than have it recomputed. Both callers therefore share one rule, which
|
|
130
|
+
* is the point: a consumer pre-filtering with {@link servableTickers} cannot
|
|
131
|
+
* hand the build a ticker it will silently skip.
|
|
132
|
+
*
|
|
133
|
+
* Order-preserving. The `anyFeed` set is built at most once per call, and only
|
|
134
|
+
* when a constant-pinned ticker actually needs it.
|
|
135
|
+
*/
|
|
136
|
+
function partitionServableTickers(host, tickers, covered) {
|
|
137
|
+
const fed = covered ?? fedSetTickers(host);
|
|
138
|
+
const servable = [];
|
|
139
|
+
const unservable = [];
|
|
140
|
+
let anyFeed;
|
|
141
|
+
for (const ticker of tickers) {
|
|
142
|
+
if (fed.has(ticker)) {
|
|
143
|
+
servable.push(ticker);
|
|
144
|
+
}
|
|
145
|
+
else if (host.isConstantTicker(ticker)) {
|
|
146
|
+
anyFeed ??= tickersWithAnySourceFeed(host);
|
|
147
|
+
(anyFeed.has(ticker) ? unservable : servable).push(ticker);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
unservable.push(ticker);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { servable, unservable };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The subset of `tickers` this deployment's fed set can actually price — the
|
|
157
|
+
* servable half of {@link partitionServableTickers}, which is literally the
|
|
158
|
+
* rule `refreshOraclePrices` applies.
|
|
159
|
+
*/
|
|
160
|
+
function servableTickers(host, tickers) {
|
|
161
|
+
return partitionServableTickers(host, tickers).servable;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Which of `sources` cannot run with the supplied credentials — one row per
|
|
165
|
+
* (source, missing credential). Empty array ⇒ the fed set is fully
|
|
166
|
+
* credentialed. Pure and env-shaped on purpose: consumers call it from their
|
|
167
|
+
* boot-time env asserts (zod superRefine, config validators) BEFORE any
|
|
168
|
+
* client exists, passing the raw values their env resolved. The per-build
|
|
169
|
+
* enforcement twin — `refreshOraclePrices`'s credential pre-check — reads the
|
|
170
|
+
* same rule-owned `credential` declaration, so a deployment this function passes
|
|
171
|
+
* cannot later trip that check for a listed source.
|
|
172
|
+
*/
|
|
173
|
+
function missingOracleCredentials(sources, creds) {
|
|
174
|
+
// The env-shaped bag, normalized to the kind-keyed shape ONCE — the check
|
|
175
|
+
// below then never mentions a specific kind.
|
|
176
|
+
const supplied = { pyth_api_key: creds.pythApiKey };
|
|
177
|
+
const missing = [];
|
|
178
|
+
for (const source of sources) {
|
|
179
|
+
const required = (0, rule_registry_ts_1.resolveOracleRule)(source).credential?.kind;
|
|
180
|
+
if (required !== undefined && !supplied[required]) {
|
|
181
|
+
missing.push({ source, credential: required });
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return missing;
|
|
185
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `weight-coverage.ts` — the ON-CHAIN half of "can this deployment price these
|
|
3
|
+
* tickers", and the only place the fed-set invariant is actually enforced.
|
|
4
|
+
*
|
|
5
|
+
* Everything in `validate.ts` reasons from config alone: it answers "does some
|
|
6
|
+
* listed source carry a feed for this ticker". That is necessary and not
|
|
7
|
+
* sufficient, because the aggregator decides which contributions COUNT. The
|
|
8
|
+
* dangerous shape is a ticker that is servable by config yet weighted to a rule
|
|
9
|
+
* the fed set cannot supply: `refreshOraclePrices` happily aggregates it from a
|
|
10
|
+
* source the chain does not weight, `remove_outliers` finds no weighted
|
|
11
|
+
* contribution, and the abort takes down the WHOLE PTB — every other ticker in
|
|
12
|
+
* the same build with it.
|
|
13
|
+
*
|
|
14
|
+
* The mirror-image shape is just as dangerous and less obvious: a ticker
|
|
15
|
+
* weighted to a rule this client DOES list, but whose feed that source does not
|
|
16
|
+
* carry. Being in the fed set buys nothing per ticker — `refreshOraclePrices`
|
|
17
|
+
* groups a ticker under a source only when that source's feeds have it — so the
|
|
18
|
+
* leg never appears and the weighted rule is starved just the same.
|
|
19
|
+
*
|
|
20
|
+
* That is live on mainnet today, not hypothetical. `XAGUSD` / `WTIUSD` /
|
|
21
|
+
* `BRENTUSD` are in `waterx_rule.feeds` (so: servable) while their aggregators
|
|
22
|
+
* still weight the retired `PythRule@1`, which 5.0.0 cannot feed at all. The
|
|
23
|
+
* config-only asserts wave all three through; only reading the weights catches
|
|
24
|
+
* them.
|
|
25
|
+
*
|
|
26
|
+
* Async and chain-reading, so it is NOT on the build path — it belongs in a
|
|
27
|
+
* deployment's boot sequence or a pre-release check, next to
|
|
28
|
+
* `assertOracleWriteCoverage`.
|
|
29
|
+
*/
|
|
30
|
+
import type { OracleHost } from "./host.ts";
|
|
31
|
+
/**
|
|
32
|
+
* Auxiliary witnesses — fed alongside a source rather than being one.
|
|
33
|
+
*
|
|
34
|
+
* Their emission is CONDITIONAL, per ticker, so they cannot be treated as
|
|
35
|
+
* globally available (which certified a ticker clean that then aborted):
|
|
36
|
+
*
|
|
37
|
+
* - `ConstantRule` rides only when `host.isConstantTicker(ticker)`.
|
|
38
|
+
* - `SupraRule` rides only when the deployment has supra wired AND a price
|
|
39
|
+
* -update source already fed that collector — `aggregateTicker` puts the
|
|
40
|
+
* supra leg inside `if (fed)`, so a ticker no listed source serves never
|
|
41
|
+
* gets one, constant-only tickers included.
|
|
42
|
+
*/
|
|
43
|
+
/** One ticker's on-chain weighting, as far as fed-set coverage is concerned. */
|
|
44
|
+
export interface TickerWeightCoverage {
|
|
45
|
+
ticker: string;
|
|
46
|
+
/** Weighted rule witness names, as the aggregator holds them. */
|
|
47
|
+
weighted: string[];
|
|
48
|
+
/** Weighted rules this client's fed set cannot feed (retired, or unlisted). */
|
|
49
|
+
unsuppliable: string[];
|
|
50
|
+
}
|
|
51
|
+
/** Raised by {@link assertOracleWeightCoverage}; `rows` names every offender. */
|
|
52
|
+
export declare class OracleWeightCoverageError extends Error {
|
|
53
|
+
readonly rows: TickerWeightCoverage[];
|
|
54
|
+
constructor(rows: TickerWeightCoverage[]);
|
|
55
|
+
}
|
|
56
|
+
/** Raised when an aggregator object cannot be decoded — see `readOracleWeightCoverage`. */
|
|
57
|
+
export declare class OracleWeightUnreadableError extends Error {
|
|
58
|
+
readonly ticker: string;
|
|
59
|
+
constructor(ticker: string, aggregatorId: string, why: string);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read each ticker's aggregator and report which weighted rules this fed set
|
|
63
|
+
* cannot supply.
|
|
64
|
+
*
|
|
65
|
+
* Tickers with no aggregator entry in the config are skipped, not failed: an
|
|
66
|
+
* unlisted aggregator means the deployment does not price that ticker on chain
|
|
67
|
+
* at all, which {@link assertOracleWriteCoverage} is the right check for.
|
|
68
|
+
*/
|
|
69
|
+
export declare function readOracleWeightCoverage(host: OracleHost, tickers: readonly string[]): Promise<TickerWeightCoverage[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Throw {@link OracleWeightCoverageError} when any of `tickers` is weighted to
|
|
72
|
+
* a rule this fed set cannot feed.
|
|
73
|
+
*
|
|
74
|
+
* The chain-reading twin of `assertOracleWriteCoverage`: that one catches a
|
|
75
|
+
* ticker NO source serves (loud at build anyway), this one catches the quieter
|
|
76
|
+
* and more damaging case — a ticker every config check passes, which aborts the
|
|
77
|
+
* entire transaction on chain.
|
|
78
|
+
*/
|
|
79
|
+
export declare function assertOracleWeightCoverage(host: OracleHost, tickers: readonly string[]): Promise<void>;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `weight-coverage.ts` — the ON-CHAIN half of "can this deployment price these
|
|
4
|
+
* tickers", and the only place the fed-set invariant is actually enforced.
|
|
5
|
+
*
|
|
6
|
+
* Everything in `validate.ts` reasons from config alone: it answers "does some
|
|
7
|
+
* listed source carry a feed for this ticker". That is necessary and not
|
|
8
|
+
* sufficient, because the aggregator decides which contributions COUNT. The
|
|
9
|
+
* dangerous shape is a ticker that is servable by config yet weighted to a rule
|
|
10
|
+
* the fed set cannot supply: `refreshOraclePrices` happily aggregates it from a
|
|
11
|
+
* source the chain does not weight, `remove_outliers` finds no weighted
|
|
12
|
+
* contribution, and the abort takes down the WHOLE PTB — every other ticker in
|
|
13
|
+
* the same build with it.
|
|
14
|
+
*
|
|
15
|
+
* The mirror-image shape is just as dangerous and less obvious: a ticker
|
|
16
|
+
* weighted to a rule this client DOES list, but whose feed that source does not
|
|
17
|
+
* carry. Being in the fed set buys nothing per ticker — `refreshOraclePrices`
|
|
18
|
+
* groups a ticker under a source only when that source's feeds have it — so the
|
|
19
|
+
* leg never appears and the weighted rule is starved just the same.
|
|
20
|
+
*
|
|
21
|
+
* That is live on mainnet today, not hypothetical. `XAGUSD` / `WTIUSD` /
|
|
22
|
+
* `BRENTUSD` are in `waterx_rule.feeds` (so: servable) while their aggregators
|
|
23
|
+
* still weight the retired `PythRule@1`, which 5.0.0 cannot feed at all. The
|
|
24
|
+
* config-only asserts wave all three through; only reading the weights catches
|
|
25
|
+
* them.
|
|
26
|
+
*
|
|
27
|
+
* Async and chain-reading, so it is NOT on the build path — it belongs in a
|
|
28
|
+
* deployment's boot sequence or a pre-release check, next to
|
|
29
|
+
* `assertOracleWriteCoverage`.
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.OracleWeightUnreadableError = exports.OracleWeightCoverageError = void 0;
|
|
33
|
+
exports.readOracleWeightCoverage = readOracleWeightCoverage;
|
|
34
|
+
exports.assertOracleWeightCoverage = assertOracleWeightCoverage;
|
|
35
|
+
const rule_registry_ts_1 = require("./rule-registry.js");
|
|
36
|
+
/**
|
|
37
|
+
* The on-chain witness struct each SDK source feeds. The aggregator's weight
|
|
38
|
+
* table is keyed by these type names, so this is the join between what the
|
|
39
|
+
* chain requires and what the fed set can supply.
|
|
40
|
+
*
|
|
41
|
+
* `ConstantRule` and `SupraRule` are auxiliary legs rather than sources — the
|
|
42
|
+
* SDK feeds them alongside whichever source ran, so a ticker weighted only to
|
|
43
|
+
* them needs no source. Anything NOT in this map (notably the retired
|
|
44
|
+
* `PythRule`) cannot be supplied by this SDK at any fed set.
|
|
45
|
+
*/
|
|
46
|
+
const WITNESS_TO_SOURCE = Object.freeze({
|
|
47
|
+
PythLazerRule: "pyth_lazer_rule",
|
|
48
|
+
WaterxRule: "waterx_rule",
|
|
49
|
+
});
|
|
50
|
+
/** Raised by {@link assertOracleWeightCoverage}; `rows` names every offender. */
|
|
51
|
+
class OracleWeightCoverageError extends Error {
|
|
52
|
+
rows;
|
|
53
|
+
constructor(rows) {
|
|
54
|
+
const detail = rows.map((r) => `${r.ticker} weights ${r.unsuppliable.join(" + ")}`).join("; ");
|
|
55
|
+
super(`on-chain aggregator weights name rule(s) this fed set cannot supply: ${detail}. ` +
|
|
56
|
+
`Aggregating such a ticker emits a collector with no WEIGHTED contribution, so ` +
|
|
57
|
+
`remove_outliers aborts EMissingPriceSource and takes the whole PTB down — every ` +
|
|
58
|
+
`other ticker in the same build with it. Fix by migrating the on-chain weight to a ` +
|
|
59
|
+
`rule this deployment feeds, or by not requesting these tickers.`);
|
|
60
|
+
this.name = "OracleWeightCoverageError";
|
|
61
|
+
this.rows = rows;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.OracleWeightCoverageError = OracleWeightCoverageError;
|
|
65
|
+
/** Raised when an aggregator object cannot be decoded — see `readOracleWeightCoverage`. */
|
|
66
|
+
class OracleWeightUnreadableError extends Error {
|
|
67
|
+
ticker;
|
|
68
|
+
constructor(ticker, aggregatorId, why) {
|
|
69
|
+
super(`cannot read aggregator ${aggregatorId} for ${ticker}: ${why}. This check exists to fail ` +
|
|
70
|
+
`CLOSED, so an undecodable weight table is an error rather than an empty one — treating ` +
|
|
71
|
+
`it as "no weights" would certify every ticker clean without verifying anything.`);
|
|
72
|
+
this.name = "OracleWeightUnreadableError";
|
|
73
|
+
this.ticker = ticker;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.OracleWeightUnreadableError = OracleWeightUnreadableError;
|
|
77
|
+
/** `0x…::aggregator::PythRule` → `PythRule`; already-short names pass through. */
|
|
78
|
+
function witnessName(raw) {
|
|
79
|
+
const s = typeof raw === "string" ? raw : String(raw?.name ?? raw);
|
|
80
|
+
return s.split("::").pop() ?? s;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Read each ticker's aggregator and report which weighted rules this fed set
|
|
84
|
+
* cannot supply.
|
|
85
|
+
*
|
|
86
|
+
* Tickers with no aggregator entry in the config are skipped, not failed: an
|
|
87
|
+
* unlisted aggregator means the deployment does not price that ticker on chain
|
|
88
|
+
* at all, which {@link assertOracleWriteCoverage} is the right check for.
|
|
89
|
+
*/
|
|
90
|
+
async function readOracleWeightCoverage(host, tickers) {
|
|
91
|
+
const aggregators = host.config.packages.waterx_oracle.aggregators;
|
|
92
|
+
// Which tickers each LISTED source actually feeds — per source, not merged.
|
|
93
|
+
//
|
|
94
|
+
// Being in the fed set is not enough: `refreshOraclePrices` groups a ticker
|
|
95
|
+
// under a source only when that source's feeds carry it, so a lazer-weighted
|
|
96
|
+
// ticker that only WaterX feeds gets no lazer leg no matter that lazer is
|
|
97
|
+
// listed. Treating a listed source as suppliable for EVERY ticker passed
|
|
98
|
+
// exactly that case, which then aborts `EMissingPriceSource` on chain.
|
|
99
|
+
const feedsByWitness = new Map();
|
|
100
|
+
for (const [witness, source] of Object.entries(WITNESS_TO_SOURCE)) {
|
|
101
|
+
if (host.oracleSources.includes(source)) {
|
|
102
|
+
feedsByWitness.set(witness, new Set((0, rule_registry_ts_1.resolveOracleRule)(source).supportedTickers(host)));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const supraWired = host.getSupraRule() !== undefined;
|
|
106
|
+
/** Some listed source feeds this ticker, so a collector gets fed at all. */
|
|
107
|
+
const anySourceFeeds = (ticker) => {
|
|
108
|
+
for (const served of feedsByWitness.values())
|
|
109
|
+
if (served.has(ticker))
|
|
110
|
+
return true;
|
|
111
|
+
return false;
|
|
112
|
+
};
|
|
113
|
+
const suppliableFor = (ticker, witness) => {
|
|
114
|
+
const served = feedsByWitness.get(witness);
|
|
115
|
+
// A source witness: suppliable only where that source has THIS ticker's feed.
|
|
116
|
+
if (served !== undefined)
|
|
117
|
+
return served.has(ticker);
|
|
118
|
+
if (witness === "ConstantRule")
|
|
119
|
+
return host.isConstantTicker(ticker);
|
|
120
|
+
// Supra rides on a collector a SOURCE already fed — never on its own, and
|
|
121
|
+
// never on a constant-only collector.
|
|
122
|
+
if (witness === "SupraRule")
|
|
123
|
+
return supraWired && anySourceFeeds(ticker);
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
const wanted = tickers.filter((t) => Object.hasOwn(aggregators, t));
|
|
127
|
+
// Independent reads — one round trip each would make a 30-market boot assert
|
|
128
|
+
// needlessly serial.
|
|
129
|
+
const objects = await Promise.all(wanted.map((t) =>
|
|
130
|
+
// Explicit field mask: the client's `getObject` wrapper requests none, so
|
|
131
|
+
// `json` would come back undefined and every aggregator would look
|
|
132
|
+
// weightless — an assert that passes exactly where it must fail.
|
|
133
|
+
host.grpcClient.getObject({ objectId: aggregators[t], include: { json: true } })));
|
|
134
|
+
return wanted.map((ticker, i) => {
|
|
135
|
+
// FAIL CLOSED on anything undecodable. Defaulting a missing object / JSON /
|
|
136
|
+
// weights map to an empty list made the assert succeed without verifying a
|
|
137
|
+
// single weight — the exact fail-open shape this gate exists to prevent.
|
|
138
|
+
const id = aggregators[ticker];
|
|
139
|
+
const json = objects[i]?.object?.json;
|
|
140
|
+
if (json === undefined || json === null || typeof json !== "object") {
|
|
141
|
+
throw new OracleWeightUnreadableError(ticker, id, "no JSON payload in the object read");
|
|
142
|
+
}
|
|
143
|
+
const raw = json.weights;
|
|
144
|
+
const entries = Array.isArray(raw) ? raw : raw?.contents;
|
|
145
|
+
if (!Array.isArray(entries)) {
|
|
146
|
+
throw new OracleWeightUnreadableError(ticker, id, "no decodable `weights` table");
|
|
147
|
+
}
|
|
148
|
+
const weighted = entries.map((e) => witnessName(e.key));
|
|
149
|
+
if (weighted.some((w) => w === "" || w === "undefined")) {
|
|
150
|
+
throw new OracleWeightUnreadableError(ticker, id, "a weight entry has no rule type name");
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
ticker,
|
|
154
|
+
weighted,
|
|
155
|
+
unsuppliable: weighted.filter((w) => !suppliableFor(ticker, w)),
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Throw {@link OracleWeightCoverageError} when any of `tickers` is weighted to
|
|
161
|
+
* a rule this fed set cannot feed.
|
|
162
|
+
*
|
|
163
|
+
* The chain-reading twin of `assertOracleWriteCoverage`: that one catches a
|
|
164
|
+
* ticker NO source serves (loud at build anyway), this one catches the quieter
|
|
165
|
+
* and more damaging case — a ticker every config check passes, which aborts the
|
|
166
|
+
* entire transaction on chain.
|
|
167
|
+
*/
|
|
168
|
+
async function assertOracleWeightCoverage(host, tickers) {
|
|
169
|
+
const rows = await readOracleWeightCoverage(host, tickers);
|
|
170
|
+
const bad = rows.filter((r) => r.unsuppliable.length > 0);
|
|
171
|
+
if (bad.length > 0)
|
|
172
|
+
throw new OracleWeightCoverageError(bad);
|
|
173
|
+
}
|
|
@@ -17,70 +17,33 @@ import { type LoadConfigOptions, type PythAccessConfig, type PythFetchPolicy, ty
|
|
|
17
17
|
import type { Network } from "./constants.ts";
|
|
18
18
|
export interface CreateClientOptions extends LoadConfigOptions {
|
|
19
19
|
grpcUrl?: string;
|
|
20
|
-
/**
|
|
21
|
-
* Which oracle price-update source drives `refreshOraclePrices`. REQUIRED —
|
|
22
|
-
* there is NO default source: every deployment names its source explicitly
|
|
23
|
-
* (wire it from your own env var, e.g. `ORACLE_SOURCE`). Each source is
|
|
24
|
-
* self-contained (own infra, own endpoints, own config) with NO cross-source
|
|
25
|
-
* fallback:
|
|
26
|
-
*
|
|
27
|
-
* - `'pyth_rule'` — Pyth Core `pyth_rule` updates (Hermes VAA + per-feed
|
|
28
|
-
* update fees); Core state + Hermes endpoint live in the source's own
|
|
29
|
-
* `PYTH_CORE_INFRA` table.
|
|
30
|
-
* - `'pyth_lazer_rule'` — Pyth Lazer signed updates (ONE `leEcdsa` verify
|
|
31
|
-
* per PTB, no per-feed fees); needs `packages.pyth_lazer_rule` with feeds
|
|
32
|
-
* and a `pythApiKey` (Lazer is auth-first); Lazer infra lives in the
|
|
33
|
-
* source's own `LAZER_INFRA` table.
|
|
34
|
-
* - `'waterx_rule'` — the first-party WaterX quote-center (Nautilus-TEE,
|
|
35
|
-
* ed25519-signed batches): ONE envelope covering the build's tickers,
|
|
36
|
-
* verified AND fed by a single `collect_batch_latest` per collector. No
|
|
37
|
-
* credential and no per-update fee; needs `packages.waterx_rule` with
|
|
38
|
-
* feeds. Quote-center infra lives in the source's own `WATERX_INFRA`
|
|
39
|
-
* table; endpoint/transport overridable via
|
|
40
|
-
* {@link CreateClientOptions.waterxEndpoint} /
|
|
41
|
-
* {@link CreateClientOptions.waterxFetch} — the browser-CORS proxy hook,
|
|
42
|
-
* since this is the one source fetched from the page.
|
|
43
|
-
*
|
|
44
|
-
* The name is source-neutral on purpose — a source need not be Pyth (as
|
|
45
|
-
* `'waterx_rule'` shows). Selecting a source whose feed for a requested
|
|
46
|
-
* ticker is absent is NOT an error at client creation: it fails at tx-build
|
|
47
|
-
* time for exactly those tickers (see `refreshOraclePrices`).
|
|
48
|
-
*
|
|
49
|
-
* Accepts a SINGLE source or a LIST. A list means every listed source's
|
|
50
|
-
* data is fetched and fed in one build — required whenever the on-chain
|
|
51
|
-
* weight tables have more than one rule weighted (e.g. a Core→Pro or
|
|
52
|
-
* Pro+Waterx coexistence window): the chain drops unweighted contributions
|
|
53
|
-
* (harmless) but aborts on a starved weighted rule, so the list must stay a
|
|
54
|
-
* SUPERSET of every ticker's weighted set. Order is meaningful to consumers
|
|
55
|
-
* (read-plane priority), not to the on-chain build.
|
|
56
|
-
*/
|
|
57
|
-
oracleSource: OracleSource | OracleSource[];
|
|
58
20
|
/**
|
|
59
21
|
* Pyth Lazer access token (`Authorization: Bearer …`). Required under
|
|
60
|
-
* `
|
|
61
|
-
* `
|
|
62
|
-
* the canonical `waterx-config` JSON — pass it at client init from your
|
|
63
|
-
* env var (e.g. `PYTH_API_KEY`); the SDK never reads `process.env`.
|
|
22
|
+
* a config that wires `pyth_lazer_rule` (Lazer is auth-first) and unused by
|
|
23
|
+
* `waterx_rule` (public quote-center). This is a SECRET and never belongs
|
|
24
|
+
* in the canonical `waterx-config` JSON — pass it at client init from your
|
|
25
|
+
* own env var (e.g. `PYTH_API_KEY`); the SDK never reads `process.env`.
|
|
64
26
|
*/
|
|
65
27
|
pythApiKey?: string;
|
|
66
28
|
/**
|
|
67
|
-
* Retry/timeout policy for the off-chain
|
|
29
|
+
* Retry/timeout policy for the off-chain Lazer update fetch (see
|
|
68
30
|
* `fetchWithPolicy`). Optional — defaults to 15s timeout, 2 retries.
|
|
69
31
|
*/
|
|
70
32
|
pythFetch?: PythFetchPolicy;
|
|
71
33
|
/**
|
|
72
|
-
* Quote-center base URL for `
|
|
34
|
+
* Quote-center base URL for `waterx_rule` — overrides the
|
|
73
35
|
* source's own per-network `WATERX_INFRA` default.
|
|
74
36
|
*
|
|
75
|
-
* This is the one source a BROWSER fetches itself (the signed
|
|
76
|
-
*
|
|
37
|
+
* This is the one source a BROWSER fetches itself (the signed price is pulled
|
|
38
|
+
* from the page), so it is bound by the quote-center deployment's CORS
|
|
77
39
|
* allowlist. A front end whose origin is not allowed — or one that must route
|
|
78
40
|
* egress through its own backend — points this at a same-origin proxy that
|
|
79
|
-
* forwards `GET /v1/quotes/
|
|
41
|
+
* forwards `GET /v1/quotes/leaves` (and `GET /v1/quotes/update`, the fallback
|
|
42
|
+
* route). Unused by the Pyth sources.
|
|
80
43
|
*
|
|
81
44
|
* An absolute URL. Any base PATH is preserved (`joinEndpointPath`), so
|
|
82
45
|
* `https://app.example/api/quote-center` fetches
|
|
83
|
-
* `https://app.example/api/quote-center/v1/quotes/
|
|
46
|
+
* `https://app.example/api/quote-center/v1/quotes/leaves` — a proxy route
|
|
84
47
|
* survives instead of being rewritten to the origin root.
|
|
85
48
|
*/
|
|
86
49
|
waterxEndpoint?: string;
|
|
@@ -96,14 +59,14 @@ export declare class PerpClient extends BaseLineClient<WaterXConfig> {
|
|
|
96
59
|
/** Caller-supplied Pyth credential + fetch policy — NO infra; each source owns its own tables. */
|
|
97
60
|
pyth: PythAccessConfig;
|
|
98
61
|
/**
|
|
99
|
-
* Caller-supplied quote-center overrides for `
|
|
62
|
+
* Caller-supplied quote-center overrides for `waterx_rule`
|
|
100
63
|
* (`waterxEndpoint` / `waterxFetch` create options) — access-only, mirroring
|
|
101
64
|
* `pyth` above; unset fields resolve against the rule's own `WATERX_INFRA`.
|
|
102
65
|
*/
|
|
103
66
|
waterx: WaterxAccessConfig;
|
|
104
67
|
/** Wormhole infra for the credit bridge (network defaults unless overridden). */
|
|
105
68
|
wormhole: WormholeInfraConfig;
|
|
106
|
-
/** The fed set
|
|
69
|
+
/** The fed set, derived from the config — see {@link deriveOracleSources}. */
|
|
107
70
|
readonly oracleSources: readonly OracleSource[];
|
|
108
71
|
/** Canonical-schema lookups (delegated to below); no transport. */
|
|
109
72
|
private readonly view;
|
|
@@ -123,11 +86,33 @@ export declare class PerpClient extends BaseLineClient<WaterXConfig> {
|
|
|
123
86
|
getMarket(ticker: string): import("./config.ts").WaterxPerpMarketEntry;
|
|
124
87
|
/** @see PerpConfigView.getAggregator */
|
|
125
88
|
getAggregator(ticker: string): string;
|
|
126
|
-
/**
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
89
|
+
/**
|
|
90
|
+
* WLP pool-token tickers THIS client's fed set can actually price — the
|
|
91
|
+
* ticker set the WLP builders refresh before `assert_prices_fresh`.
|
|
92
|
+
*
|
|
93
|
+
* Filtered, not raw `Object.keys(pool_tokens)`: a token only an UNLISTED
|
|
94
|
+
* source serves is not priceable by this client. The predicate is
|
|
95
|
+
* `refreshOraclePrices`'s own (`servableTickers`), so this list is exactly
|
|
96
|
+
* what a refresh would accept.
|
|
97
|
+
*
|
|
98
|
+
* NOTE this is a QUERY, not what the WLP builders use — they deliberately
|
|
99
|
+
* refresh and bump the WHOLE pool, because dropping an unpriceable asset
|
|
100
|
+
* from both halves is silent (see `assertWlpPoolRefreshed`).
|
|
101
|
+
*/
|
|
102
|
+
pricedPoolTickers(): string[];
|
|
103
|
+
/**
|
|
104
|
+
* {@link pricedPoolTickers} already joined to each token's Move type.
|
|
105
|
+
*
|
|
106
|
+
* A query, not a build primitive: the WLP builders deliberately refresh and
|
|
107
|
+
* bump the WHOLE pool (`refreshWlpPoolOracles`), because pre-filtering to
|
|
108
|
+
* what this client can price silently drops an asset from both halves. Use
|
|
109
|
+
* this to ASK what a fed set covers — e.g. a dashboard, or a boot assert
|
|
110
|
+
* pairing it with `assertOracleWriteCoverage`.
|
|
111
|
+
*/
|
|
112
|
+
pricedPoolTokens(): {
|
|
113
|
+
ticker: string;
|
|
114
|
+
tokenType: string;
|
|
115
|
+
}[];
|
|
131
116
|
/** @see PerpConfigView.isConstantTicker */
|
|
132
117
|
isConstantTicker(ticker: string): boolean;
|
|
133
118
|
/** @see PerpConfigView.getSupraRule */
|